Compare commits

...

134 Commits

Author SHA1 Message Date
Robin Jones
88d654129a
[SC64][WEB] FAQ spelling fix (#109)
A minor mistake that I noticed.
2025-03-19 08:59:29 +01:00
Mateusz Faderewski
b88c9a314b [SC64][SW] Added license notice in the sc64deployer help 2025-03-12 23:05:13 +01:00
Mateusz Faderewski
e4c3f34fb0 [SC64][SW] Added warning about unknown variant of IPL3 2025-03-12 22:36:26 +01:00
Luke Stadem
b520f9ace8
[SC64][SW] Added rerun-if-changed for bootloader dependency (#108)
Changes to the bootloader source were not being noticed by cargo when
recompiling sc64deployer.

We can use
[rerun-if-changed](https://doc.rust-lang.org/cargo/reference/build-scripts.html#rerun-if-changed)
to instruct cargo to rerun the `build.rs` script if there were any
changes to any file inside `bootloader/src/` (recursively).
2025-03-12 18:47:50 +01:00
Mateusz Faderewski
d8c4f979cc [SC64][WEB] FAQ cleanup 2025-03-11 22:21:08 +01:00
Robin Jones
d63f5893da
[SC64][WEB] FAQ improvements (#104)
Add some improvements. take what you need.
2025-03-11 22:17:33 +01:00
Mateusz Faderewski
d307e1a5b1 [SC64][SW] Remove use keyword for std::ffi::c_char in ftdi.rs 2025-03-11 22:16:24 +01:00
liffy
65f8fa3cf7
[SC64][SW] Fix invalid variable type (description/serial) for libftdi functions in sc64deployer (#105)
`c_char` isn't `i8` on all architectures (e.g. on ARM it's `u8`)

Co-authored-by: lif <>
Co-authored-by: Mateusz Faderewski <sc@mateuszfaderewski.pl>
2025-03-11 22:14:52 +01:00
Mateusz Faderewski
6c566bd530
[SC64][CI/CD] Fix firmware building (#107) 2025-03-11 22:04:38 +01:00
Mateusz Faderewski
99060bec15 [SC64][SW] Display more meaningful error message for menu load 2025-03-11 21:20:41 +01:00
Mateusz Faderewski
63feaa0c2e [SC64][SW] Add project license information in the bootloader 2025-03-11 14:04:16 +01:00
Mateusz Faderewski
a59ad1d39b [SC64][HW] License PCB project files under CERN-OHL-S-2.0 2025-03-11 14:01:49 +01:00
Mateusz Faderewski
30fb3d0ea6 [SC64][SW] Disable auto new line in bootloader display printing functions 2025-03-09 21:14:54 +01:00
Mateusz Faderewski
a3d4082384 [SC64][SW] Added an option to force load menu when boot mode is ROM/DDIPL and R button is held 2025-03-09 20:50:24 +01:00
Mateusz Faderewski
0739ca624c [SC64][SW] Added controller reading functions in the bootloader 2025-03-09 20:48:15 +01:00
Mateusz Faderewski
bb1ce45dfe [SC64][CI/CD] Move Lattice Diamond license to GitHub secrets 2025-03-09 09:33:17 +01:00
Mateusz Faderewski
9193e9c6f2 [SC64][BUILD] Moved getting commit info to build.sh script 2025-03-08 22:14:35 +01:00
Mateusz Faderewski
3fbb6f3823 [SC64][BUILD] Moved time printing from docker_build.sh to build.sh 2025-03-08 22:12:38 +01:00
Mateusz Faderewski
f546e5d17d [SC64][SW] Implement FlashRAM timings emulation and add a fake variant of FlashRAM 2025-03-07 20:51:56 +01:00
Mateusz Faderewski
8393963650 [SC64][SW] Enable support for GPT partition scheme in FatFs + Update FatFs 2025-02-01 02:19:22 +01:00
Mateusz Faderewski
20a9ec0087 [SC64][BUILD] Force docker image platform to linux/x86_64 2025-01-27 19:50:53 +01:00
Mateusz Faderewski
b3d9e98e68 [SC64][WEB] Added a FAQ page + small updates 2025-01-27 19:49:59 +01:00
Luke Stadem
6698550dbd
[SC64][DOCS] Fix inaccurate identifier string for successful USB packets (#100)
According to my testing and the [existing sc64deployer
software](/Polprzewodnikowy/SummerCart64/blob/main/sw/deployer/src/sc64/link.rs#L186),
the identifier should be `CMP`, not `RSP`.
2024-12-24 21:01:24 +01:00
Mateusz Faderewski
18041e2547 [SC64] v2.20.2 release 2024-11-18 22:58:35 +01:00
Mateusz Faderewski
0538a28f9e [SC64][SW] Fixed regression in the SD card module introduced in the latest refactor 2024-11-18 22:57:14 +01:00
Mateusz Faderewski
1ade3ade8e [SC64] v2.20.1 release 2024-11-16 15:20:12 +01:00
Mateusz Faderewski
80b4aa95cd [SC64] Updated GitHub issue template 2024-11-16 13:59:46 +01:00
Mateusz Faderewski
6eef811cd6 [SC64][SW] Fix SD deinit error when the card is not locked + SD module refactor 2024-11-16 13:47:20 +01:00
Raphaël Tétreault
e2c100ae7f
[SC64] Revise README to include Feature subheadings for easy at-a-glance reading (#77)
I made some minor changes to the README to try and address the most
common read-the-manual moments seen in the N64Brew Discord.

Specifically, I broke out the features listed in the README into
sub-categories, with the non-developer features up at the top for
non-technical people to read first.

The categories are:
- Hardware-Dependent Game Features
- Game Saves
- Menu
- Game Development
- Cartridge Production

Co-authored-by: Mateusz Faderewski <sc@mateuszfaderewski.pl>
2024-10-11 19:09:41 +02:00
Mateusz Faderewski
a6e86587ae [SC64][DOCS][WEB] Updated readme, documentation and website 2024-10-11 18:36:10 +02:00
Mateusz Faderewski
93ab101be4 [SC64] Updated GitHub issue/PR templates 2024-10-11 18:26:46 +02:00
Mateusz Faderewski
cc41652e6f [SC64][DOCS][WEB] Added a link to a video build guide 2024-10-09 11:19:25 +02:00
Mateusz Faderewski
ed63eb3e8c [SC64] v2.20.0 release 2024-09-29 21:14:55 +02:00
Mateusz Faderewski
db4f16754f [SC64][SW] Release SD lock on init error 2024-09-29 21:14:32 +02:00
Mateusz Faderewski
74e20cb8cc
[SC64][SW] Added access to the SD card via USB interface (#90) 2024-09-29 20:58:52 +02:00
Mateusz Faderewski
3146cc8c99 [SC64][SW] Fix USB reset procedure (I/O buffer purge) 2024-09-03 12:48:36 +02:00
Mateusz Faderewski
4a50e33acd [SC64][WEB] Updated info on the website 2024-08-24 22:02:25 +02:00
Mateusz Faderewski
d12bfaabf6 [SC64][SW] Fix timeout issues on slow backends in sc64deployer 2024-08-18 13:30:24 +02:00
Mateusz Faderewski
04cecb1955 [SC64] v2.19.0 release 2024-08-17 18:23:57 +02:00
Mateusz Faderewski
a5284aa770 [SC64][SW] Updated sc64env docker image 2024-08-17 16:53:57 +02:00
Giovanni Bajo
bbcf041b5a
[SC64][SW] Allow lowercase confirmation (#85)
At least one user fell for this, so we can allow lowercase to reduce
support issues
2024-08-17 15:06:41 +02:00
Mateusz Faderewski
12e16b807a [SC64][DOCS][WEB] Updated website and documentation 2024-08-16 13:59:46 +02:00
Mateusz Faderewski
92fb4a85df
[SC64][FW][SW] New framework for SC64 IRQ handling (#68) 2024-08-16 13:52:01 +02:00
Mateusz Faderewski
1259687902 [SC64][HW] Changed battery holder from 1060 to 1058 + minor PCB improvements 2024-08-11 15:41:09 +02:00
Mateusz Faderewski
d8976def97 [SC64][SW] Optimized memory usage in the sc64deployer 2024-07-23 18:26:17 +02:00
Mateusz Faderewski
e9ee025e21 [SC64][FW][SW] Slightly speed up DMA write transfer speed + USB speed test fixes 2024-07-21 22:15:06 +02:00
Mateusz Faderewski
912f356650 [SC64][SW] Added USB speed test 2024-07-21 20:15:44 +02:00
Mateusz Faderewski
631f140c48 [SC64][SW] Adjust buffer sizes in sc64deployer to tune for maximum transfer speed 2024-07-21 12:19:03 +02:00
Mateusz Faderewski
71cef2cd6c [SC64][SW] Change error type starting ID to avoid reusing old error code IDs 2024-07-21 12:17:44 +02:00
Mateusz Faderewski
1b71b4a333
[SC64][FW] Verilator tests + many bugfixes in the FPGA code (#75) 2024-07-21 11:15:08 +02:00
Mateusz Faderewski
5e33e516a2
[SC64][SW] Implement new libftdi backend in the sc64deployer (#72) 2024-07-21 10:48:20 +02:00
Mena
5adc95b6e1
[SC64][HW] Update design of sc64_shell_button_b3fs-105x_with_end_stop.step (#74)
button redesign to stop rattle
2024-07-07 19:16:40 +02:00
Mateusz Faderewski
acc3e588d8 [SC64][SW] Fixed RTC raw time offset calculation 2024-06-15 00:33:43 +02:00
Mateusz Faderewski
a571fe16f5 [SC64][SW] Added support for 400 leap years for the RTC 2024-06-14 21:47:10 +02:00
Mateusz Faderewski
903efe5353 [SC64][SW] Add missing cleanup during SD card initialization 2024-06-14 21:46:02 +02:00
Mateusz Faderewski
e4af127e55 [SC64][FW][SW] Added option to set and read century when updating RTC datetime 2024-06-06 23:00:38 +02:00
Mateusz Faderewski
6bbfee44e7 [SC64][SW] Added inverted own address SDRAM tests 2024-05-20 16:23:41 +02:00
Mateusz Faderewski
9843a79a86 [SC64][SW] controller: fixed stuck LED state when error was cleared 2024-05-20 16:18:14 +02:00
Mateusz Faderewski
80c06f3e53 [SC64][DOCS] Added FTDI driver installation requirement in the build guide 2024-05-16 21:07:38 +02:00
Mateusz Faderewski
554305290e [SC64][SW] controller: corrected SD card init procedure 2024-05-14 19:39:00 +02:00
Mateusz Faderewski
e6751c262d [SC64][SW] bootloader/controller: added more meaningful errors in the SD card module
Also added manual CRC16 check in the software for data blocks smaller than 512 bytes
2024-05-14 01:36:34 +02:00
Mateusz Faderewski
92838da349 [SC64][SW] Added SD card FatFs tests, rearranged SDRAM tests 2024-05-12 02:45:56 +02:00
Mateusz Faderewski
a884d69308 [SC64][SW] sc64deployer: use chunked write/read for memory access 2024-05-08 21:31:29 +02:00
Mateusz Faderewski
7bc4e6d180 [SC64][SW] sc64deployer: added SDRAM tests 2024-05-08 20:24:08 +02:00
Mateusz Faderewski
a0bd0ddd98 [SC64][SW] Bootloader: rearranged tests and added/changed SDRAM patterns 2024-05-07 00:42:07 +02:00
Mateusz Faderewski
b8632a305b [SC64][HW] Added back notes column to the interactive BOM file 2024-05-06 00:15:08 +02:00
Mateusz Faderewski
b89ca68cb4 [SC64][SW] Bootloader: added PI tests and improved SDRAM test reliability 2024-05-05 21:01:46 +02:00
Mateusz Faderewski
0f3eaa6d17 [SC64][DOCS] Updated readme 2024-05-05 16:15:26 +02:00
Mateusz Faderewski
5854b4ec0d [SC64][WEB] Add BOM directly on the website 2024-05-05 16:03:06 +02:00
Mateusz Faderewski
9599db8307 [SC64][FW] Set timing constraints for SDRAM pins 2024-05-05 07:08:44 +02:00
Mateusz Faderewski
cf19dc6151 [SC64][SW] Update: allow firmware update from the Flash memory 2024-05-05 01:53:19 +02:00
Mateusz Faderewski
0e868b5ad5 [SC64][FW] Added placeholder test point outputs in the FPGA project 2024-05-03 17:55:40 +02:00
Mateusz Faderewski
8a49e954ce [SC64][BUILD] Fixed BOM source path in builder script 2024-05-03 17:53:34 +02:00
Mateusz Faderewski
3b13d21e63 [SC64][FW] CIC: use output enable register in PIO 2024-05-03 17:51:20 +02:00
Mateusz Faderewski
4eaa0b3353 [SC64][FW] Flash: fixed partial page write + handle data mask during write
Flash memory module had an issue when ending address was not page (256 bytes) aligned.

Now it's possible to write single bytes to the Flash instead of being forced to do 16 bit aligned writes.
2024-05-03 17:49:44 +02:00
Mateusz Faderewski
64c3b69454 [SC64][DOCS][WEB] Updated readme and website 2024-04-30 19:20:02 +02:00
Mateusz Faderewski
83bcfd3065 [SC64][HW] Updated license and author info on the PCB 2024-04-17 17:37:52 +02:00
Mateusz Faderewski
61bd3c62d8 [SC64][HW] Updated PCB date and revision 2024-04-17 17:04:36 +02:00
Mateusz Faderewski
2846938c5f [SC64][HW] Added README.md for shell design files 2024-04-17 16:51:42 +02:00
Mateusz Faderewski
0050688255 [SC64][HW] Organize and rename shell design files 2024-04-17 16:47:56 +02:00
Mateusz Faderewski
03daabeae8
[SC64][HW] Add shell models for injection molding and expand screw hole size in the PCB (#69)
Co-authored-by: Mena <emdazer@gmail.com>
2024-04-17 16:34:10 +02:00
Mateusz Faderewski
e93cecfae3 [SC64][FW][SW] Fixed unreliable CIC boot 2024-04-11 01:34:36 +02:00
Mateusz Faderewski
0150060f1e [SC64][DOCS] Updated readme 2024-04-10 21:48:00 +02:00
Mateusz Faderewski
42b10e85f1 [SC64][DOCS] Updated readme 2024-04-10 21:45:42 +02:00
Mateusz Faderewski
cff730cafc [SC64][SW] Minor formatting and spelling fixes 2024-04-10 21:32:17 +02:00
Mateusz Faderewski
f6b94aec97 [SC64][FW][SW] Added CIC diagnostic, changed software timeout timer to hardware (derived from PIF clock) 2024-04-10 12:56:05 +02:00
Mateusz Faderewski
c156b72bee [SC64][SW] Added very basic SDRAM test in the primer before flashing bootloader 2024-03-17 02:04:05 +01:00
Mateusz Faderewski
f27f644a7e [SC64][SW] Fixed SC64 reset procedure in the deployer 2024-03-14 20:07:07 +01:00
Mateusz Faderewski
5b880fc052 [SC64][BUILD] Replaced website publish action 2024-03-04 15:29:10 +01:00
Mateusz Faderewski
a12641bf39 [SC64][BUILD] Bumped GitHub Actions dependencies 2024-03-04 12:55:47 +01:00
Mateusz Faderewski
01bef4060e [SC64][SW] Updated deployer dependencies 2024-03-04 12:47:24 +01:00
Mateusz Faderewski
b4b3659458 [SC64][SW] Fix buffered receive bug in sc64deployer server 2024-03-04 00:54:51 +01:00
Mateusz Faderewski
7a83fb3eae [SC64][FW] Updated Lattice Diamond license.dat file 2024-03-01 22:15:30 +01:00
Mateusz Faderewski
66f71c2040 [SC64][WEB] Updated website content (64DD section) 2024-01-29 14:30:49 +01:00
Mateusz Faderewski
95b78f3cd9 [SC64] v2.18.1 release 2024-01-29 14:26:22 +01:00
Mateusz Faderewski
421d0438f3
[SC64][FW][SW] Controller rewrite to remove task subsystem + minor bug fixes (#64)
This PR completely removes `task.c / task.h` from `sw/controller` STM32
code.
Additionally, these changes were implemented:
- Updated IPL3
- Added new diagnostic data (voltage and temperature) readout commands
for USB and N64
- Fixed some issues with FlashRAM save type
- Joybus timings were relaxed to accommodate communication with
unsynchronized master controller (like _Datel Game Killer_, thanks
@RWeick)
- N64 embedded test program now waits for release of button press to
proceed
- Fixed issue where, in rare circumstances, I2C peripheral in STM32
would get locked-up on power-up
- LED blinking behavior on SD card access was changed
- LED blink duration on save writeback has been extended
- Minor fixes through the entire of hardware abstraction layer for STM32
code
- Primer now correctly detects issues with I2C bus during first time
programming
- `primer.py` script gives more meaningful error messages
- Fixed bug where RTC time was always written on N64FlashcartMenu boot
- sc64deployer now displays "Diagnostic data" instead of "MCU stack
usage"
2024-01-29 14:23:18 +01:00
Mateusz Faderewski
be37025d42 [SC64][WEB] Added option to buy SC64 in Phenom Mod store 2024-01-25 08:33:33 +01:00
Mateusz Faderewski
17c12f5957 [SC64][WEB] Updated website content + made menu buttons bigger 2024-01-21 20:37:07 +01:00
Mateusz Faderewski
f7eb6a73b4 [SC64][SW] Removed _oscillator running after time set_ check in the RTC, lowered I2C clock speed 2024-01-12 03:12:56 +01:00
Mateusz Faderewski
b84213b3e4 [SC64][WEB] Fix embed image 2024-01-11 09:18:28 +01:00
Mateusz Faderewski
356f1f2f0f [SC64][WEB] Added embed meta info 2024-01-11 09:06:13 +01:00
Mateusz Faderewski
42acb48004 [SC64][WEB] Added rendered PCB images 2024-01-11 05:23:03 +01:00
Mateusz Faderewski
1f7be611d8 [SC64][WEB] Updated website home page 2024-01-11 02:22:52 +01:00
Mateusz Faderewski
13fc38fe73 [SC64][SW] Implement correct behavior for FlashRAM writes 2024-01-10 22:38:04 +01:00
Mateusz Faderewski
2639a93b6f [SC64][WEB] Fix menu CSS 2024-01-10 22:35:30 +01:00
Mateusz Faderewski
7ea74f19a5 [SC64][WEB] Added favicon 2024-01-07 20:04:24 +01:00
Mateusz Faderewski
7f21902e21 [SC64][WEB] Fix publishing website 2024-01-07 19:25:47 +01:00
Mateusz Faderewski
d7aadf48f9 [SC64][WEB] Added initial website 2024-01-07 19:21:11 +01:00
Mason Stooksbury
5ae3e32d63
[SC64][HW] Added small piece to reach the tactile button from the back shell (#61)
Adding a small piece to reach the button from the back shell. Fits
great, works well, and doesn't fall out

![button](https://github.com/Polprzewodnikowy/SummerCart64/assets/40926080/f35e3420-af41-4476-81e3-f46825c84245)

![IMG20231221114136](https://github.com/Polprzewodnikowy/SummerCart64/assets/40926080/66868832-cc00-492c-9d95-b3c9fb0c7944)

![IMG20231221114114](https://github.com/Polprzewodnikowy/SummerCart64/assets/40926080/c5c867ce-c1ea-4933-b84f-29746245c92d)
2023-12-21 23:59:08 +01:00
Mason Stooksbury
ef053f9c52
[SC64][DOCS] Update 06_build_guide.md regarding shell screws (#62)
Updated the Build Guide with details around which screws work best for
putting the shell together
2023-12-21 21:57:07 +01:00
Mateusz Faderewski
3ed1ad4d73
[SC64][SW] Add Windows 32-bit build for sc64deployer (#60) 2023-12-17 21:11:20 +01:00
Mateusz Faderewski
c14da52f46
[SC64] Fix linguist statistics 2023-12-15 00:44:32 +01:00
Mateusz Faderewski
6c1446c9df [SC64] v2.18.0 release 2023-12-14 20:52:34 +01:00
Mateusz Faderewski
bf13434f40 [SC64][SW] Added command to reset SC64 state in deployer 2023-12-14 20:33:21 +01:00
Mateusz Faderewski
3f3f1e3b86 [SC64][SW] Added option to set custom CIC seed in deployer 2023-12-14 20:28:21 +01:00
Mateusz Faderewski
ff27e35ae8
[SC64][FW][SW] Moved CIC emulation from MCU to FPGA (#56) 2023-12-14 19:26:54 +01:00
Robin Jones
e0198083ae
[SC64][DOCS] Update 06_build_guide.md (#52)
Make it more obvious that you need the repo when programming (and some
other minor improvements).

---------

Co-authored-by: Mateusz Faderewski <sc@mateuszfaderewski.pl>
Co-authored-by: Mateusz Faderewski <polprzewodnikowy@gmail.com>
2023-12-14 19:07:52 +01:00
ottelo
fe855c31ae
[SC64][DOCS] Update 06_build_guide.md (#55)
Add few useful notes.
2023-12-14 18:50:30 +01:00
Mateusz Faderewski
73716de8f6 [SC64][DOCS] Updated documentation 2023-09-24 19:07:07 +02:00
Mateusz Faderewski
ebb2b3b77e [SC64][DOCS] Documented USB interface asynchronous packets 2023-09-24 18:36:16 +02:00
Mateusz Faderewski
473f3b883b [SC64] v2.17.0 release 2023-09-15 21:01:01 +02:00
Mateusz Faderewski
bee41d1d04 [SC64][SW] Changed menu loading procedure, updated boot procedure, 64DD fixes 2023-09-15 20:51:57 +02:00
Mateusz Faderewski
6eb89688ab [SC64][SW] Added ability to send debug commands at startup in deployer 2023-09-04 20:57:20 +02:00
Mateusz Faderewski
5c6f25500a [SC64][DOCS] Updated documentation 2023-08-30 19:24:35 +02:00
Mateusz Faderewski
a28e118cba [SC64][DOCS] Updated documentation 2023-08-30 18:14:24 +02:00
Mateusz Faderewski
129bb4b800 [SC64][SW] SDRAM test use cached memory address 2023-08-26 14:18:22 +02:00
Mateusz Faderewski
e170abdcd3 [SC64][DOCS] Updated documentation 2023-08-26 13:37:48 +02:00
Mateusz Faderewski
b68d4a4be0 [SC64] Fixed building when commit message contained certain characters 2023-08-25 17:38:04 +02:00
Nabile Rahmani
bfd501dd8a
[SC64][DOCS] USB command arguments description (time and CIC params) (#35)
Work in progress, criticism/corrections welcome.

---------

Co-authored-by: Mateusz Faderewski <sc@mateuszfaderewski.pl>
2023-08-25 17:26:58 +02:00
Mateusz Faderewski
664092036f
[SC64][SW] Disable writeback prior to jumping to menu code, … (#44)
…added SDRAM tests, SC64 reference implementation rewrite
2023-08-25 17:13:42 +02:00
Mateusz Faderewski
a4a52fd15a
[SC64][SW] Added support for Only 64DD IPL mode in deployer. (#43)
And added ability to pipe commands in debug mode.
2023-08-25 17:10:22 +02:00
Christopher Bonhage
716123fedf
[SC64] Include SVG logo in assets (#47)
Created in Inkscape using the exported PNG as a reference.

Special care was taken to preserve the angles and spacing of the
original design.

The guide lines and reference image have been included as hidden layers
in the SVG.
2023-08-16 21:30:47 +02:00
Mateusz Faderewski
b3a9d5ff63 [SC64] v2.16.0 release 2023-06-30 01:11:25 +02:00
Mateusz Faderewski
c4f6a0d555
[SC64][FW][SW] SD card byte swap on reads support (#39)
And other bug fixes related to DMA write mask
2023-06-30 01:09:02 +02:00
225 changed files with 196491 additions and 75097 deletions

1
.gitattributes vendored
View File

@ -1,4 +1,5 @@
fw/project/lcmxo2/*.sty linguist-generated
fw/rtl/serv/* linguist-vendored
fw/rtl/vendor/** -linguist-vendored
fw/rtl/vendor/lcmxo2/generated/* linguist-generated
hw/pcb/*.html linguist-generated

1
.github/FUNDING.yml vendored
View File

@ -1,2 +1 @@
github: polprzewodnikowy
ko_fi: polprzewodnikowy

View File

@ -1,27 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1.
2.
3.
4.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Possible solution**
Not obligatory, but suggest a fix/reason for the bug.

58
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,58 @@
name: Bug Report
description: File a bug report
title: "[SC64][BUG] "
labels: ["bug"]
assignees:
- Polprzewodnikowy
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: checkboxes
id: sanity-check
attributes:
label: Is your issue really a bug?
description: |
Issue tracker in this repository is for **BUG REPORTS ONLY**.
Make sure your problem is caused by the firmware/PC app and **not** by the software you're running on the flashcart.
Errors in the documentation are also considered a bug.
If your issue is related to the menu then report it in the [N64FlashcartMenu] repository.
[N64FlashcartMenu]: https://github.com/Polprzewodnikowy/N64FlashcartMenu
options:
- label: I understand the difference between flashcart firmware, N64FlashcartMenu and `sc64deployer` PC app.
required: true
- label: I found a bug in FPGA HDL (`/fw/rtl`)
- label: I found a bug in MCU app (`/sw/controller`)
- label: I found a bug in N64 bootloader (`/sw/bootloader`)
- label: I found a bug in PC app (`/sw/deployer`)
- label: I found a bug in initial programming script (`/sw/tools/primer.py`)
- label: I found an error in documentation (`/docs`)
- label: I found an issue elsewhere
- type: input
id: version
attributes:
label: Firmware version
placeholder: v2.20.2
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: Describe the bug
description: |
Tell us what you noticed as a bug, and what is your expected outcome.
The more detailed the description is the better.
If applicable please attach screenshots and/or video showing the problem.
validations:
required: true
- type: textarea
id: deployer-info
attributes:
label: Output logs from `sc64deployer info`
description: If possible, please copy and paste the output from the command specified above.
render: shell

View File

@ -1,8 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: GitHub Discussions
url: https://github.com/Polprzewodnikowy/SummerCart64/discussions
about: Please use for QUESTIONS, conversations or discussions.
- name: N64brew Discord
url: https://discord.gg/8xvRPqCAFC
about: Alternative channel for asking QUESTIONS.
url: https://discord.gg/8VNMKhxqQn
about: The go-to community to ask about SummerCart64

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,20 +0,0 @@
**Description**
Provide a headline summary of your changes in the Title above.
Describe your changes in detail.
**Related Issue**
This project only accepts pull requests related to open issues.
If suggesting a change, please discuss it in an issue first.
If fixing a bug, there should be an issue describing it with steps to reproduce.
Please link to the issue here:
**Motivation and Context**
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.
**How Has This Been Tested?**
Please describe in detail how you tested your changes.
Include details of your testing environment, and the tests you ran to see how your change affects other areas of the code, etc.
**Screenshots**
If applicable, add screenshots to help demonstrate your feature/bugfix.

View File

@ -2,7 +2,7 @@ name: build
on:
push:
branches:
branches:
- main
pull_request:
branches:
@ -18,7 +18,9 @@ jobs:
steps:
- name: Download SummerCart64 repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set package version
uses: frabert/replace-string-action@v2
@ -28,13 +30,19 @@ jobs:
string: '${{ github.ref_name }}'
replace-with: '-'
- name: Retrieve the Lattice Diamond license from secrets and decode it
run: echo $LICENSE | base64 --decode > fw/project/lcmxo2/license.dat
env:
LICENSE: ${{ secrets.LATTICE_DIAMOND_LICENSE_BASE64 }}
- name: Build firmware
run: ./docker_build.sh release --force-clean
env:
MAC_ADDRESS: ${{ secrets.LATTICE_DIAMOND_MAC_ADDRESS }}
SC64_VERSION: ${{ steps.version.outputs.replaced }}
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: sc64-pkg-${{ steps.version.outputs.replaced }}
path: |
@ -52,32 +60,43 @@ jobs:
build-deployer:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
version: [windows, windows-32bit, linux, macos]
include:
- os: windows-latest
executable: sc64deployer.exe
name: sc64-deployer-windows
options: -c -a -f
extension: zip
- version: windows
os: windows-latest
executable: target/release/sc64deployer.exe
package-name: sc64-deployer-windows
package-params: -c -a -f
package-extension: zip
- os: ubuntu-latest
linux-packages: libudev-dev
executable: sc64deployer
name: sc64-deployer-linux
options: -czf
extension: tar.gz
- version: windows-32bit
os: windows-latest
build-params: --target=i686-pc-windows-msvc
executable: target/i686-pc-windows-msvc/release/sc64deployer.exe
package-name: sc64-deployer-windows-32bit
package-params: -c -a -f
package-extension: zip
- os: macos-latest
executable: sc64deployer
name: sc64-deployer-macos
options: -czf
extension: tgz
- version: linux
os: ubuntu-latest
apt-packages: libudev-dev
executable: target/release/sc64deployer
package-name: sc64-deployer-linux
package-params: -czf
package-extension: tar.gz
- version: macos
os: macos-latest
executable: target/release/sc64deployer
package-name: sc64-deployer-macos
package-params: -czf
package-extension: tgz
runs-on: ${{ matrix.os }}
steps:
- name: Download SummerCart64 repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set package version
uses: frabert/replace-string-action@v2
@ -87,32 +106,66 @@ jobs:
string: '${{ github.ref_name }}'
replace-with: '-'
- name: Install linux packages
if: matrix.linux-packages
- name: Install apt packages
if: matrix.apt-packages
run: |
sudo apt-get update
sudo apt-get -y install ${{ matrix.linux-packages }}
sudo apt-get -y install ${{ matrix.apt-packages }}
- name: Build deployer
run: cargo b -r
run: cargo b -r ${{ matrix.build-params }}
working-directory: sw/deployer
- name: Package executable
run: |
mkdir package
cd target/release
tar ${{ matrix.options }} ../../package/${{ matrix.name }}-${{ steps.version.outputs.replaced }}.${{ matrix.extension }} ${{ matrix.executable }}
mkdir -p ./package
cp ${{ matrix.executable }} ./package/
cd ./package
tar ${{ matrix.package-params }} ./${{ matrix.package-name }}-${{ steps.version.outputs.replaced }}.${{ matrix.package-extension }} *
working-directory: sw/deployer
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}-${{ steps.version.outputs.replaced }}
path: sw/deployer/package/${{ matrix.name }}-${{ steps.version.outputs.replaced }}.${{ matrix.extension }}
name: ${{ matrix.package-name }}-${{ steps.version.outputs.replaced }}
path: sw/deployer/package/${{ matrix.package-name }}-${{ steps.version.outputs.replaced }}.${{ matrix.package-extension }}
- name: Upload release assets
if: github.event_name == 'release' && github.event.action == 'created'
uses: softprops/action-gh-release@v0.1.15
with:
files: |
sw/deployer/package/${{ matrix.name }}-${{ steps.version.outputs.replaced }}.${{ matrix.extension }}
sw/deployer/package/${{ matrix.package-name }}-${{ steps.version.outputs.replaced }}.${{ matrix.package-extension }}
publish-website:
if: github.ref == 'refs/heads/main'
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Download SummerCart64 repository
uses: actions/checkout@v4
- name: Copy BOM file to the website folder
run: cp ./hw/pcb/sc64v2_bom.html ./web
- name: Setup GitHub pages
uses: actions/configure-pages@v4
- name: Upload website artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./web
- name: Publish website from uploaded artifact
id: deployment
uses: actions/deploy-pages@v4

103
README.md
View File

@ -1,27 +1,43 @@
# SC64 - an open source Nintendo 64 flashcart
# SummerCart64 - a fully open source N64 flashcart
[<img src="assets/sc64_logo.svg" />](assets/sc64_logo.svg)
[<img src="assets/sc64_logo_256_160.png" />](assets/sc64_logo_256_160.png)
---
**For non-technical description of the SummerCart64, please head to the https://summercart64.dev website!**
## Features
- 64 MiB SDRAM memory for game and save data
- 16 MiB FLASH memory for bootloader and extended game data
- 8 kiB on-chip buffer for general use
- ~23.8 MiB/s peak transfer rate USB interface for data upload/download and debug functionality
- ~23.8 MiB/s peak transfer rate SD card interface
- EEPROM, SRAM and FlashRAM save types with automatic writeback to SD card
- Battery backed real time clock (RTC)
- Status LED and button for general use
- 64DD add-on emulation
- IS-Viewer 64 debug interface
- N64 bootloader with support for IPL3 registers spoofing and loading menu from SD card
- Enhanced [UltraCIC_C](https://github.com/jago85/UltraCIC_C) emulation with automatic region switching and programmable seed/checksum values
- PC app for communicating with flashcart (game/save data upload/download, feature enable control and debug terminal)
- [UNFLoader](https://github.com/buu342/N64-UNFLoader) support
- Initial programming via UART header or dedicated JTAG/SWD interfaces
- Software and firmware updatable via USB interface
- 3D printable plastic shell
- **ROM and Save Memory On-board**
- 64 MiB SDRAM memory for game and save data (enough memory to support every retail game without compromise)
- 16 MiB FLASH memory for bootloader and extended game data (with extended memory flashcart supports game ROMs up to 78 MiB)
- **Game Saves**
- EEPROM 4k/16k, SRAM and FlashRAM save types with an automatic writeback to the SD card (no reset button press required)
- **Hardware-Dependent Game Features**
- 64DD add-on emulation
- Battery backed real time clock (RTC)
- **Menu**
- Dedicated open source menu written specifically for this flashcart - [N64FlashcartMenu](https://github.com/Polprzewodnikowy/N64FlashcartMenu)
- **Game Development**
- ~23.8 MiB/s peak transfer rate SD card interface
- ~23.8 MiB/s peak transfer rate USB interface for data upload/download and debug functionality
- PC app to access the flashcart features:
- Game/save data upload/download
- Feature enable control
- Debug terminal
- Access to the SD card
- Firmware update
- [UNFLoader](https://github.com/buu342/N64-UNFLoader) support
- IS-Viewer 64 debug interface (fixed 64 kiB buffer with a movable base address)
- 8 kiB on-chip buffer for general use
- Status LED and button for general use
- [UltraCIC_C](https://github.com/jago85/UltraCIC_C) emulation with automatic region switching and programmable seed/checksum values
- N64 bootloader with support for IPL3 registers spoofing and loading menu from SD card
- **Cartridge Production**
- Initial programming via UART header or via dedicated JTAG/SWD interfaces
- 3D printable shell
---
@ -29,38 +45,30 @@
- [Quick startup guide](./docs/00_quick_startup_guide.md)
- [Memory map](./docs/01_memory_map.md)
- [USB commands](./docs/02_usb_commands.md)
- [N64 commands](./docs/03_n64_commands.md)
- [N64 commands](./docs/02_n64_commands.md)
- [USB interface](./docs/03_usb_interface.md)
- [Config options](./docs/04_config_options.md)
- [FW/SW building](./docs/05_fw_sw_building.md)
- [Manufacturing guidelines](./docs/06_manufacturing_guidelines.md)
- [FW and SW info](./docs/05_fw_and_sw_info.md)
- [Build guide](./docs/06_build_guide.md)
---
## How do I get one?
I've prepared all necessary manufacturing files on [PCBWay Shared Project](https://www.pcbway.com/project/shareproject/SC64_an_open_source_Nintendo_64_flashcart_14b9688a.html) site.
Full disclosure: for every order made through this link I will receive 10% of PCB manufacturing and PCB assembly service cost. This is a great way of supporting further project development.
Most up to date information about purchasing/manufacturing options is available on https://summercart64.dev website!
<a href="https://www.pcbway.com/project/shareproject/SC64_an_open_source_Nintendo_64_flashcart_14b9688a.html"><img src="https://www.pcbway.com/project/img/images/frompcbway-1220.png" alt="PCB from PCBWay" /></a>
If you want to order it yourself then I've prepared all necessary manufacturing files on the [PCBWay Shared Project](https://www.pcbway.com/project/member/shareproject/?bmbno=1046ED64-8AEE-44) site.
If you don't need a physical product but still want to support me then check my [GitHub sponsors](https://github.com/sponsors/Polprzewodnikowy) page.
**Be careful**: this is an advanced project and it is assumed that you have enough knowledge about electronics.
Selecting wrong options or giving PCB manufacturer wrong information might result in an undesired time and/or money loss.
Boards also come unprogrammed from the manufacturer - you need to do **initial programming step** yourself after receiving the board.
**Price of the components is not included in the initial quote at the checkout** - manufacturer will contact you later with updated price.
To avoid problems _**please**_ read **both** [build guide](./docs/06_build_guide.md) and description on the shared project page **in full**.
If you have even slightest doubt about the ordering or programming process, it is better to leave it to someone experienced - ask in the [N64brew Discord server](https://discord.gg/8VNMKhxqQn) if that's the case.
---
**Full disclosure**: for every order made through [this link](https://www.pcbway.com/project/member/shareproject/?bmbno=1046ED64-8AEE-44) I will receive 10% of PCB manufacturing and PCB assembly service cost (price of the components is not included in the split). This is a great way of supporting further project development.
## Where's menu?
Menu, as known from 64drive or EverDrive-64, is currently under development. Progress can be tracked in [N64FlashcartMenu](https://github.com/Polprzewodnikowy/N64FlashcartMenu) repository.
Ambitious goal of this software is to target every flashcart available on the market. However, main focus for now is getting at least basic UI running on the SC64.
---
## Help / Q&A
For any questions related to this project, please use [*Discussions*](https://github.com/Polprzewodnikowy/SummerCollection/discussions) tab in GitHub repository.
Do not use my e-mail for these questions, as I want to have a centralized knowledge base accessible for everyone interested in this project.
I'm also active at [N64brew](https://discord.gg/WqFgNWf) Discord server as `korgeaux#5558` but keep in mind that [*Discussions*](https://github.com/Polprzewodnikowy/SummerCollection/discussions) tab is a preferred option. **Discord is not a replacement for contact form in any way.**
If you don't need a physical product but still want to support me then check the sponsor links on the [official website](https://summercart64.dev).
---
@ -74,14 +82,20 @@ I'm also active at [N64brew](https://discord.gg/WqFgNWf) Discord server as `korg
[<img src="assets/sc64_finished_example.jpg" alt="SC64 finished example" width="800" />](assets/sc64_finished_example.jpg)
[<img src="assets/sc64_pcb_front.jpg" alt="SC64 PCB front" width="800" />](assets/sc64_pcb_front.jpg)
[<img src="assets/sc64_pcb_back.jpg" alt="SC64 PCB back" width="800" />](assets/sc64_pcb_back.jpg)
---
## Acknowledgement
This project wouldn't be possible without these contributions:
- [64drive](https://64drive.retroactive.be) orders being on permanent hold long before creating this repository.
- [64drive](https://64drive.retroactive.be) ([archived](https://web.archive.org/web/20240406215731/https://64drive.retroactive.be/)) orders being on permanent hold long before creating this repository.
- [EverDrive-64 X7](https://krikzz.com/our-products/cartridges/ed64x7.html) being disappointment for homebrew development (slow USB upload, unjustified price and overcomplicated SD card access).
- Context: Both aforementioned products were priced at $199 in 2020. 64drive features made it a vastly more useful tool for homebrew development.
Since then, 64drive had never been restocked and EverDrive-64 X7 price was lowered to $159 (as of May 2024).
- [Jan Goldacker (@jago85)](https://github.com/jago85) and his projects:
- [Brutzelkarte](https://github.com/jago85/Brutzelkarte_FPGA) providing solid base for starting this project and sparking hope for true open source N64 flashcarts.
- [UltraCIC_C](https://github.com/jago85/UltraCIC_C) reimplementation for easy integration in modern microcontrollers. Thanks also goes to everyone involved in N64 CIC reverse engineering.
@ -89,3 +103,4 @@ This project wouldn't be possible without these contributions:
- [FatFs](http://elm-chan.org/fsw/ff/00index_e.html) FAT32/exFAT library being easiest to integrate in embedded environment.
- [Yakumono's (@LuigiBlood)](https://twitter.com/LuigiBlood) extensive [64DD documentation](https://github.com/LuigiBlood/64dd/wiki) and its implementation in various emulators.
- [Libdragon](https://github.com/DragonMinded/libdragon) open source N64 SDK project and its developers.
- [SERV](https://github.com/olofk/serv) bit-serial 32-bit RISC-V CPU soft core.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 173 KiB

236
assets/sc64_logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

BIN
assets/sc64_pcb_back.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

BIN
assets/sc64_pcb_front.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 KiB

View File

@ -8,6 +8,7 @@ PACKAGE_FILE_NAME="sc64-extra"
TOP_FILES=(
"./fw/ftdi/ft232h_config.xml"
"./fw/project/lcmxo2/impl1/fpga_max_frequency.txt"
"./sw/tools/primer.py"
"./sw/tools/requirements.txt"
"./sc64-firmware-${SC64_VERSION}.bin"
@ -16,7 +17,8 @@ TOP_FILES=(
FILES=(
"./assets/*"
"./docs/*"
"./hw/pcb/sc64_hw_v2.0a_bom.html"
"./hw/pcb/LICENSE"
"./hw/pcb/sc64v2_bom.html"
"./hw/pcb/sc64v2.kicad_pcb"
"./hw/pcb/sc64v2.kicad_pro"
"./hw/pcb/sc64v2.kicad_sch"
@ -26,17 +28,35 @@ FILES=(
"./README.md"
)
HAVE_COMMIT_INFO=false
BUILT_BOOTLOADER=false
BUILT_CONTROLLER=false
BUILT_CIC=false
BUILT_FPGA=false
BUILT_UPDATE=false
BUILT_RELEASE=false
FORCE_CLEAN=false
get_last_commit_info () {
if [ "$HAVE_COMMIT_INFO" = true ]; then return; fi
SAFE_DIRECTORY="-c safe.directory=$(pwd)"
GIT_BRANCH=$(git $SAFE_DIRECTORY rev-parse --abbrev-ref HEAD)
GIT_TAG=$(git $SAFE_DIRECTORY describe --tags 2> /dev/null)
GIT_SHA=$(git $SAFE_DIRECTORY rev-parse HEAD)
GIT_MESSAGE=$(git $SAFE_DIRECTORY log --oneline --format=%B -n 1 HEAD | head -n 1)
HAVE_COMMIT_INFO=true
}
build_bootloader () {
if [ "$BUILT_BOOTLOADER" = true ]; then return; fi
get_last_commit_info
pushd sw/bootloader > /dev/null
if [ "$FORCE_CLEAN" = true ]; then
make clean
@ -65,9 +85,24 @@ build_controller () {
BUILT_CONTROLLER=true
}
build_cic () {
if [ "$BUILT_CIC" = true ]; then return; fi
pushd sw/cic > /dev/null
if [ "$FORCE_CLEAN" = true ]; then
./build.sh clean
fi
./build.sh all
popd > /dev/null
BUILT_CIC=true
}
build_fpga () {
if [ "$BUILT_FPGA" = true ]; then return; fi
build_cic
pushd fw/project/lcmxo2 > /dev/null
if [ "$FORCE_CLEAN" = true ]; then
rm -rf ./impl1/
@ -81,8 +116,11 @@ build_fpga () {
build_update () {
if [ "$BUILT_UPDATE" = true ]; then return; fi
get_last_commit_info
build_bootloader
build_controller
build_cic
build_fpga
pushd sw/tools > /dev/null
@ -90,6 +128,7 @@ build_update () {
rm -f ../../sc64-firmware-*.bin
fi
GIT_INFO=""
GIT_INFO+=$'\n'"freq: $(cat ../../fw/project/lcmxo2/impl1/fpga_max_frequency.txt)"
if [ ! -z "${SC64_VERSION}" ]; then GIT_INFO+=$'\n'"ver: $SC64_VERSION"; fi
if [ ! -z "${GIT_BRANCH}" ]; then GIT_INFO+=$'\n'"branch: $GIT_BRANCH"; fi
if [ ! -z "${GIT_TAG}" ]; then GIT_INFO+=$'\n'"tag: $GIT_TAG"; fi
@ -124,10 +163,11 @@ build_release () {
print_usage () {
echo "builder script for SC64"
echo "usage: ./build.sh [bootloader] [controller] [fpga] [update] [release] [-c] [--help]"
echo "usage: ./build.sh [bootloader] [controller] [cic] [fpga] [update] [release] [-c] [--help]"
echo "parameters:"
echo " bootloader - compile N64 bootloader software"
echo " controller - compile MCU controller software"
echo " cic - compile CIC emulation software"
echo " fpga - compile FPGA design"
echo " update - compile all software and designs"
echo " release - collect and zip files for release (triggers 'update' build)"
@ -143,8 +183,17 @@ if test $# -eq 0; then
exit 1
fi
print_time () {
echo "Build took $SECONDS seconds"
}
trap "echo \"Build failed\"; print_time" ERR
SECONDS=0
TRIGGER_BOOTLOADER=false
TRIGGER_CONTROLLER=false
TRIGGER_CIC=false
TRIGGER_FPGA=false
TRIGGER_UPDATE=false
TRIGGER_RELEASE=false
@ -157,6 +206,9 @@ while test $# -gt 0; do
controller)
TRIGGER_CONTROLLER=true
;;
cic)
TRIGGER_CIC=true
;;
fpga)
TRIGGER_FPGA=true
;;
@ -185,6 +237,9 @@ done
if [ "$TRIGGER_BOOTLOADER" = true ]; then build_bootloader; fi
if [ "$TRIGGER_CONTROLLER" = true ]; then build_controller; fi
if [ "$TRIGGER_CIC" = true ]; then build_cic; fi
if [ "$TRIGGER_FPGA" = true ]; then build_fpga; fi
if [ "$TRIGGER_UPDATE" = true ]; then build_update; fi
if [ "$TRIGGER_RELEASE" = true ]; then build_release; fi
print_time

View File

@ -1,42 +1,29 @@
#!/bin/bash
BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.5"
BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.10"
BUILDER_PLATFORM="linux/x86_64"
pushd $(dirname $0) > /dev/null
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
GIT_TAG=$(git describe --tags 2> /dev/null)
GIT_SHA=$(git rev-parse HEAD)
GIT_MESSAGE=$(git log --oneline --format=%B -n 1 HEAD | head -n 1)
if [ -t 1 ]; then
DOCKER_OPTIONS="-it"
fi
SECONDS=0
docker run \
$DOCKER_OPTIONS \
--rm \
--user $(id -u):$(id -g) \
--mac-address ${MAC_ADDRESS:-F8:12:34:56:78:90} \
--mount type=bind,src="$(pwd)/fw/project/lcmxo2/license.dat",target="/flexlm/license.dat" \
--mount type=bind,src="$(pwd)",target="/workdir" \
-v "$(pwd)"/fw/project/lcmxo2/license.dat:/flexlm/license.dat \
-v "$(pwd)":/workdir \
-h=`hostname` \
-e GIT_BRANCH="$GIT_BRANCH" \
-e GIT_TAG="$GIT_TAG" \
-e GIT_SHA="$GIT_SHA" \
-e GIT_MESSAGE="$GIT_MESSAGE" \
-e SC64_VERSION=${SC64_VERSION:-""} \
--platform $BUILDER_PLATFORM \
$BUILDER_IMAGE \
./build.sh $@
BUILD_ERROR=$?
echo "Build took $SECONDS seconds"
BUILD_RESULT=$?
popd > /dev/null
if [ $BUILD_ERROR -ne 0 ]; then
exit -1
fi
exit $BUILD_RESULT

View File

@ -1,41 +1,38 @@
- [First time setup](#first-time-setup)
- [Firmware backup/update](#firmware-backupupdate)
- [Uploading game and/or save](#uploading-game-andor-save)
- [Downloading save](#downloading-save)
- [Running 64DD games](#running-64dd-games)
- [Direct boot option](#direct-boot-option)
- [Debug terminal](#debug-terminal)
- [Standalone mode (Running menu and games on the N64)](#standalone-mode-running-menu-and-games-on-the-n64)
- [Developer mode (Uploading ROMs from the PC, and more)](#developer-mode-uploading-roms-from-the-pc-and-more)
- [Uploading game and/or save from PC](#uploading-game-andor-save-from-pc)
- [Downloading save to PC](#downloading-save-to-pc)
- [Running 64DD games from PC](#running-64dd-games-from-pc)
- [Direct boot option](#direct-boot-option)
- [Debug terminal on PC](#debug-terminal-on-pc)
- [Firmware backup/update](#firmware-backupupdate)
- [LED blink patters](#led-blink-patters)
---
## First time setup
# First time setup
## Standalone mode (Running menu and games on the N64)
Menu, as known from 64drive or EverDrive-64, is developed in another repository: [N64FlashcartMenu](https://github.com/Polprzewodnikowy/N64FlashcartMenu).
Download latest version from [here](https://github.com/Polprzewodnikowy/N64FlashcartMenu/releases) and put `sc64menu.n64` file in the root directory of the SD card.
Additionally, follow the instructions in the N64FlashcartMenu repository for more information about thr SD card setup and extra functionality.
When N64 is powered on menu is automatically loaded from the SD card. Supported file system formats are FAT32 and exFAT.
---
## Developer mode (Uploading ROMs from the PC, and more)
**Windows platform: replace `./sc64deployer` in examples below with `sc64deployer.exe`**
1. Download the latest deployer tool (`sc64-deployer-{os}-{version}.{ext}`) and firmware (`sc64-firmware-{version}.bin`) from GitHub releases page
2. Extract deployer tool package contents to a folder and place firmware file inside it
1. Download the latest deployer tool (`sc64-deployer-{os}-{version}.{ext}`) from the GitHub releases page
2. Extract deployer tool package contents to a folder
3. Connect SC64 device to your computer with USB type C cable
4. Run `./sc64deployer list` to check if device is detected in the system
5. Update SC64 firmware to the latest version with `./sc64deployer firmware update sc64-firmware-{version}.bin`
6. Run `./sc64deployer info` to check if update process finished successfully and SC64 is detected correctly
5. Follow instructions below for specific use cases
---
## Firmware backup/update
Keeping SC64 firmware up to date is highly recommended.
`sc64deployer` application is tightly coupled with specific firmware versions and will error out when it detects unsupported firmware version.
To download and backup current version of the SC64 firmware run `./sc64deployer firmware backup sc64-firmware-backup.bin`
To update SC64 firmware run `./sc64deployer firmware update sc64-firmware-{version}.bin`
To print firmware metadata run `./sc64deployer firmware info sc64-firmware-{version}.bin`
---
## Uploading game and/or save
### Uploading game and/or save from PC
`./sc64deployer upload path_to_rom.n64 --save-type eeprom4k --save path_to_save.sav`
@ -44,18 +41,14 @@ Application will try to autodetect used save type so explicitly setting save typ
Check included help in the application to list available save types.
Arguments `--save-type` and/or `--save` can be omitted if game doesn't require any save or you want to start with fresh save file.
---
## Downloading save
### Downloading save to PC
`./sc64deployer download save path_to_save.sav`
Replace `path_to_save.sav` with appropriate value.
Command will raise error when no save type is currently enabled in the SC64 device.
---
## Running 64DD games
### Running 64DD games from PC
64DD games require DDIPL ROM and disk images.
To run disk game type `./sc64deployer 64dd path_to_ddipl.n64 path_to_disk_1.ndd path_to_disk_2.ndd`.
@ -70,31 +63,38 @@ Make sure retail and development disks formats aren't mixed together.
If disk game supports running in conjunction with cartridge game then `--rom path_to_rom.n64` argument can be added to command above.
N64 will boot cartridge game instead of 64DD IPL.
---
## Direct boot option
### Direct boot option
If booting game through included bootloader isn't a desired option then flashcart can be put in special mode that omits this step.
Pass `--direct` option in `upload` or `64dd` command to disable bootloader during boot and console reset.
This option is useful only for very specific cases (e.g. testing custom IPL3 or running SC64 on top of GameShark).
TV type cannot be forced when direct boot mode is enabled.
---
## Debug terminal
### Debug terminal on PC
`sc64deployer` application supports UNFLoader protocol and has same functionality implemented as aforementioned program.
Type `./sc64deployer debug` to activate it.
### Firmware backup/update
Keeping SC64 firmware up to date is strongly recommended.
`sc64deployer` application is tightly coupled with specific firmware versions and will error out when it detects unsupported firmware version.
To download and backup current version of the SC64 firmware run `./sc64deployer firmware backup sc64-firmware-backup.bin`
To update SC64 firmware run `./sc64deployer firmware update sc64-firmware-{version}.bin`
To print firmware metadata run `./sc64deployer firmware info sc64-firmware-{version}.bin`
---
## LED blink patters
# LED blink patters
LED on SC64 board can blink in certain situations. Most of them during normal use are related to SD card access. Here's list of blink patterns:
| Pattern | Meaning |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| Nx [Short ON - Short OFF] | SD card access is in progress (initialization or data read/write) or save writeback is in progress |
| Irregular | SD card access is in progress (initialization or data read/write) or save writeback was finished |
| Nx [Medium ON - Long OFF] | CIC region did not match, please power off console and power on again |
| 2x [Very short ON - Short OFF] | Pattern used during firmware update process, it means that specific part of firmware has started programming |
| 10x [Very short ON - Very short OFF] | Firmware has been successfully updated |
@ -103,4 +103,4 @@ LED on SC64 board can blink in certain situations. Most of them during normal us
Nx means that blink count is varied.
LED blinking on SD card access can be disabled through `sc64deployer` application.
Please refer to included help for option to change the LED behavior.
Please refer to the included help for option to change the LED behavior.

View File

@ -1,36 +1,41 @@
- [Internal memory map](#internal-memory-map)
- [PI memory map](#pi-memory-map)
- [Address decoding limitations](#address-decoding-limitations)
- [Flash mapped sections](#flash-mapped-sections)
- [Address decoding limitations](#address-decoding-limitations)
- [Flash mapped sections](#flash-mapped-sections)
- [SC64 registers](#sc64-registers)
- [`0x1FFF_0000`: **STATUS/COMMAND**](#0x1fff_0000-statuscommand)
- [`0x1FFF_0004`: **DATA0** and `0x1FFF_0008`: **DATA1**](#0x1fff_0004-data0-and-0x1fff_0008-data1)
- [`0x1FFF_0000`: **SCR**](#0x1fff_0000-scr)
- [`0x1FFF_0004`: **DATA0** / `0x1FFF_0008`: **DATA1**](#0x1fff_0004-data0--0x1fff_0008-data1)
- [`0x1FFF_000C`: **IDENTIFIER**](#0x1fff_000c-identifier)
- [`0x1FFF_0010`: **KEY**](#0x1fff_0010-key)
- [`0x1FFF_0014`: **IRQ**](#0x1fff_0014-irq)
- [`0x1FFF_0018`: **AUX**](#0x1fff_0018-aux)
- [Command execution flow](#command-execution-flow)
- [Without interrupt](#without-interrupt)
- [With interrupt](#with-interrupt)
---
## Internal memory map
# Internal memory map
This mapping is used internally by FPGA/μC and when accessing flashcart from USB side.
| section | base | size | access | device |
| ------------------- | ------------- | ---------------- | ------ | -------- |
| SDRAM | `0x0000_0000` | 64 MiB | RW | SDRAM |
| Flash | `0x0400_0000` | 16 MiB | RW | Flash |
| Flash [1] | `0x0400_0000` | 16 MiB | RW/R | Flash |
| Data buffer | `0x0500_0000` | 8 kiB | RW | BlockRAM |
| EEPROM | `0x0500_2000` | 2 kiB | RW | BlockRAM |
| 64DD buffer | `0x0500_2800` | 256 bytes | RW | BlockRAM |
| FlashRAM buffer [1] | `0x0500_2900` | 128 bytes | R | BlockRAM |
| N/A [2] | `0x0500_2980` | to `0x07FF_FFFF` | R | N/A |
| 64DD/MCU buffer | `0x0500_2800` | 1 kiB | RW | BlockRAM |
| FlashRAM buffer [2] | `0x0500_2C00` | 128 bytes | R | BlockRAM |
| N/A [3] | `0x0500_2C80` | to `0x07FF_FFFF` | R | N/A |
- Note [1]: Due to BlockRAM usage optimization this section is read only.
- Note [2]: Read returns `0`. Maximum accessibe address space is 128 MiB.
- Note [1]: Flash memory region `0x04E0_0000` - `0x04FD_FFFF` is write protected as it contains N64 bootloader. This section can be overwritten only via firmware update process.
- Note [2]: Due to BlockRAM usage optimization this section is read only.
- Note [3]: Read returns `0`. Maximum accessible address space is 128 MiB.
---
## PI memory map
# PI memory map
This mapping is used when accessing flashcart from N64 side.
@ -48,13 +53,13 @@ This mapping is used when accessing flashcart from N64 side.
| ROM shadow [7] | `0x1FFC_0000` | 128 kiB | R | `0x04FE_0000` | Flash | mem bus | SC64 register access is enabled |
| Data buffer | `0x1FFE_0000` | 8 kiB | RW | `0x0500_0000` | Block RAM | mem bus | SC64 register access is enabled |
| EEPROM | `0x1FFE_2000` | 2 kiB | RW | `0x0500_2000` | Block RAM | mem bus | SC64 register access is enabled |
| 64DD buffer [8] | `0x1FFE_2800` | 256 bytes | RW | `0x0500_2800` | Block RAM | mem bus | SC64 register access is enabled |
| FlashRAM buffer [8] | `0x1FFE_2900` | 128 bytes | R | `0x0500_2900` | Block RAM | mem bus | SC64 register access is enabled |
| SC64 registers | `0x1FFF_0000` | 20 bytes | RW | N/A | Flashcart Interface | reg bus | SC64 register access is enabled |
| 64DD/MCU buffer [8] | `0x1FFE_2800` | 1 kiB | RW | `0x0500_2800` | Block RAM | mem bus | SC64 register access is enabled |
| FlashRAM buffer [8] | `0x1FFE_2C00` | 128 bytes | R | `0x0500_2C00` | Block RAM | mem bus | SC64 register access is enabled |
| SC64 registers | `0x1FFF_0000` | 28 bytes | RW | N/A | Flashcart Interface | reg bus | SC64 register access is enabled |
- Note [1]: 64DD IPL share SDRAM memory space with ROM (last 4 MiB minus 128 kiB for saves). Write access is always disabled for this section.
- Note [2]: SRAM and FlashRAM save types share SDRAM memory space with ROM (last 128 kiB).
- Note [3]: 32 kiB chunks are accesed at `0x0800_0000`, `0x0804_0000` and `0x0808_0000`.
- Note [3]: 32 kiB chunks are accessed at `0x0800_0000`, `0x0804_0000` and `0x0808_0000`.
- Note [4]: FlashRAM read access is multiplexed between mem and reg bus, writes are always mapped to reg bus.
- Note [5]: Write access is available when `ROM_WRITE_ENABLE` config is enabled.
- Note [6]: This address overlaps last 128 kiB of ROM space allowing SRAM and FlashRAM save types to work with games occupying almost all of ROM space (for example Pokemon Stadium 2). Reads are redirected to last 128 kiB of flash.
@ -79,59 +84,69 @@ Special commands are provided for performing flash erase and program.
During those operations avoid accessing flash mapped sections.
Data read will be corrupted and erase/program operations slows down.
---
## SC64 registers
# SC64 registers
SC64 contains small register region used for communication between N64 and controller code running on the μC.
Protocol is command based with support for up to 256 diferrent commands and two 32-bit argument/result values per operation.
Support for interrupts is provided but currently no command relies on it, 64DD IRQ is handled separately.
Protocol is command based with support for up to 256 different commands and two 32-bit argument/result values per operation.
Command execution finish can be optionally signaled with "cart interrupt"
| name | address | size | access | usage |
| ------------------ | ------------- | ------- | ------ | ---------------------------------- |
| **STATUS/COMMAND** | `0x1FFF_0000` | 4 bytes | RW | Command execution and status |
| **DATA0** | `0x1FFF_0004` | 4 bytes | RW | Command argument/result 0 |
| **DATA1** | `0x1FFF_0008` | 4 bytes | RW | Command argument/result 1 |
| **IDENTIFIER** | `0x1FFF_000C` | 4 bytes | RW | Flashcart identifier and IRQ clear |
| **KEY** | `0x1FFF_0010` | 4 bytes | W | SC64 register access lock/unlock |
| name | address | size | access | usage |
| -------------- | ------------- | ------- | ------ | -------------------------------- |
| **SCR** | `0x1FFF_0000` | 4 bytes | RW | Command execution and status |
| **DATA0** | `0x1FFF_0004` | 4 bytes | RW | Command argument/result 0 |
| **DATA1** | `0x1FFF_0008` | 4 bytes | RW | Command argument/result 1 |
| **IDENTIFIER** | `0x1FFF_000C` | 4 bytes | RW | Flashcart identifier |
| **KEY** | `0x1FFF_0010` | 4 bytes | W | SC64 register access lock/unlock |
| **IRQ** | `0x1FFF_0014` | 4 bytes | W | IRQ clear and enable |
| **AUX** | `0x1FFF_0018` | 4 bytes | RW | Auxiliary interrupt data channel |
---
#### `0x1FFF_0000`: **STATUS/COMMAND**
### `0x1FFF_0000`: **SCR**
| name | bits | access | meaning |
| ------------- | ------ | ------ | ----------------------------------------------------- |
| `CMD_BUSY` | [31] | R | `1` if dispatched command is pending/executing |
| `CMD_ERROR` | [30] | R | `1` if last executed command returned with error code |
| `IRQ_PENDING` | [29] | R | `1` if flashcart has raised an interrupt |
| N/A | [28:8] | N/A | Unused, write `0` for future compatibility |
| `CMD_ID` | [7:0] | RW | Command ID to be executed |
| name | bits | access | meaning |
| ----------------- | ------ | ------ | ------------------------------------------------------------ |
| `CMD_BUSY` | [31] | R | `1` if dispatched command is pending/executing |
| `CMD_ERROR` | [30] | R | `1` if last executed command returned with error code |
| `BTN_IRQ_PENDING` | [29] | R | `1` if flashcart has raised a "button pressed" interrupt |
| `BTN_IRQ_MASK` | [28] | R | `1` means "button pressed" interrupt is enabled (always `1`) |
| `CMD_IRQ_PENDING` | [27] | R | `1` if flashcart has raised a "command finish" interrupt |
| `CMD_IRQ_MASK` | [26] | R | `1` means "command finish" interrupt is enabled (always `1`) |
| `USB_IRQ_PENDING` | [25] | R | `1` if flashcart has raised an "USB not empty" interrupt |
| `USB_IRQ_MASK` | [24] | R | `1` means "USB not empty" interrupt is enabled |
| `AUX_IRQ_PENDING` | [23] | R | `1` if flashcart has raised an "AUX not empty" interrupt |
| `AUX_IRQ_MASK` | [22] | R | `1` means "AUX not empty" interrupt is enabled |
| N/A | [21:9] | N/A | Unused, write `0` for future compatibility |
| `CMD_IRQ_REQUEST` | [8] | RW | Raise cart interrupt signal when command finishes execution |
| `CMD_ID` | [7:0] | RW | Command ID to be executed |
Note: Write to this register raises `CMD_BUSY` bit and clears `CMD_ERROR` bit. Flashcart then will start executing provided command.
---
#### `0x1FFF_0004`: **DATA0** and `0x1FFF_0008`: **DATA1**
### `0x1FFF_0004`: **DATA0** / `0x1FFF_0008`: **DATA1**
| name | bits | access | meaning |
| --------- | ------ | ------ | ---------------------------------- |
| `DATA0/1` | [31:0] | RW | Command argument (W) or result (R) |
Note: Result is valid only when command has executed and `CMD_BUSY` bit is reset. When `CMD_ERROR` is set then **DATA0** register contains error code.
Note: Result is valid only when command has finished execution and `CMD_BUSY` bit is reset.
When `CMD_ERROR` is set then **DATA0** register contains error code.
---
#### `0x1FFF_000C`: **IDENTIFIER**
### `0x1FFF_000C`: **IDENTIFIER**
| name | bits | access | meaning |
| ------------ | ------ | ------ | ------------------------------------------------- |
| `IDENTIFIER` | [31:0] | RW | Flashcart identifier (ASCII `SCv2`) and IRQ clear |
| name | bits | access | meaning |
| ------------ | ------ | ------ | ----------------------------------- |
| `IDENTIFIER` | [31:0] | R | Flashcart identifier (ASCII `SCv2`) |
Note: Writing any value to this register will clear pending flashcart interrupt.
---
#### `0x1FFF_0010`: **KEY**
### `0x1FFF_0010`: **KEY**
| name | bits | access | meaning |
| ----- | ------ | ------ | ------------------------------------------ |
@ -139,19 +154,86 @@ Note: Writing any value to this register will clear pending flashcart interrupt.
Note: By default from cold boot (power on) or console reset (NMI) flashcart will disable access to SC64 specific memory regions.
**KEY** register is always enabled and listening for writes regardless of lock/unlock state.
To enable SC64 registers it is necesarry to provide sequence of values to this register.
To enable SC64 registers it is necessary to provide sequence of values to this register.
Value `0x00000000` will reset sequencer state.
Two consequentive writes of values `0x5F554E4C` and `0x4F434B5F` will unlock all SC64 registers if flashcart is in lock state.
Two consecutive writes of values `0x5F554E4C` and `0x4F434B5F` will unlock all SC64 registers if flashcart is in lock state.
Value `0xFFFFFFFF` will lock all SC64 registers if flashcart is in unlock state.
---
## Command execution flow
### `0x1FFF_0014`: **IRQ**
1. Check if command is already executing by reading `CMD_BUSY` bit in **STATUS/COMMAND** register (optional).
| name | bits | access | meaning |
| ----------------- | ------- | ------ | ---------------------------------------------- |
| `BTN_CLEAR` | [31] | W | Write `1` to clear "button pressed" interrupt |
| `CMD_CLEAR` | [30] | W | Write `1` to clear "command finish" interrupt |
| `USB_CLEAR` | [29] | W | Write `1` to clear "USB not empty" interrupt |
| `AUX_CLEAR` | [28] | W | Write `1` to clear "AUX not empty" interrupt |
| N/A | [27:12] | N/A | Unused, write `0` for future compatibility |
| `USB_IRQ_DISABLE` | [11] | W | Write `1` to disable "USB not empty" interrupt |
| `USB_IRQ_ENABLE` | [10] | W | Write `1` to enable "USB not empty" interrupt |
| `AUX_IRQ_DISABLE` | [9] | W | Write `1` to disable "AUX not empty" interrupt |
| `AUX_IRQ_ENABLE` | [8] | W | Write `1` to enable "AUX not empty" interrupt |
| N/A | [7:0] | N/A | Unused, write `0` for future compatibility |
Note: All interrupts are cleared and disabled when any of the following events occur:
- Hard reset
- NMI reset
- SC64 registers lock
SC64 interrupts are completely disabled when register access is not enabled.
---
### `0x1FFF_0018`: **AUX**
This register can be used as a very simple interface to the PC via USB.
Writing to this register generates an USB transfer with the contents of the written data.
New data available in the register are signaled via cart interrupt that needs to be enabled beforehand by setting `AUX_IRQ_ENABLE` bit in the **IRQ** register.
Status can be also manually polled by checking `AUX_IRQ_PENDING` bit in **SCR** register.
Interrupt needs to be acknowledged by setting `AUX_CLEAR` bit in the **IRQ** register.
There is no flow control, use this register as a ping-pong interface.
For example, PC sends AUX data, N64 receives interrupt, reads the data then writes to this register with a response.
This flow can be reversed if needed - N64 can be the initiating side.
| name | bits | access | meaning |
| ------ | ------ | ------ | -------------- |
| `DATA` | [31:0] | RW | Arbitrary data |
This register is used by the upload process in the `sc64deployer` to notify running app on the N64 about certain events.
All `DATA` values with upper 8 bits set to `1` (`0xFFxxxxxx`) are reserved for internal use by the SC64.
Refrain from using these values in your app for uses other than listed below.
Currently defined reserved `DATA` values are:
- `0xFF000000` - **Ping** - no-op command to test if app running on the N64 is listening to the AUX events.
- `0xFF000001` - **Halt** - causes the running app to stop all activity and wait in preparation for uploading new ROM to the SC64.
App still should listen to the AUX interrupt and respond to other messages.
- `0xFF000002` - **Reboot** - causes the running app to perform soft reboot by reloading IPL3 from the ROM and start executing it.
App running on the N64 shall respond to the AUX message with the same `DATA` value as incoming event for all events listed above, unless it's specified otherwise.
# Command execution flow
### Without interrupt
1. Check if command is already executing by reading `CMD_BUSY` bit in **SCR** register (optional).
2. Write command argument values to **DATA0** and **DATA1** registers, can be skipped if command doesn't require it.
3. Write command ID to **STATUS/COMMAND** register.
4. Wait for `CMD_BUSY` bit in **STATUS/COMMAND** register to go low.
5. Check if `CMD_ERROR` bit in **STATUS/COMMAND** is set:
3. Write command ID to **SCR** register.
4. Wait for `CMD_BUSY` bit in **SCR** register to go low.
5. Check if `CMD_ERROR` bit in **SCR** is set:
- If error is set then read **DATA0** register containing error code.
- If error is not set then read **DATA0** and **DATA1** registers containing command result values, can be skipped if command doesn't return any values.
### With interrupt
1. Check if command is already executing by reading `CMD_BUSY` bit in **SCR** register (optional).
2. Write command argument values to **DATA0** and **DATA1** registers, can be skipped if command doesn't require it.
3. Write command ID to **SCR** register and set `CMD_IRQ_REQUEST` bit high.
4. Wait for cart interrupt.
5. Check (in cart interrupt handler) if `CMD_IRQ_PENDING` bit in **SCR** register is set high.
6. Clear interrupt by setting `CMD_CLEAR` bit high in the **IRQ** register.
7. Check if `CMD_ERROR` bit in **SCR** is set:
- If error is set then read **DATA0** register containing error code.
- If error is not set then read **DATA0** and **DATA1** registers containing command result values, can be skipped if command doesn't return any values.

31
docs/02_n64_commands.md Normal file
View File

@ -0,0 +1,31 @@
- [N64 commands](#n64-commands)
---
## N64 commands
| id | name | arg0 | arg1 | rsp0 | rsp1 | description |
| --- | --------------------- | ------------- | ------------ | ---------------- | -------------- | ------------------------------------------------------------ |
| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` |
| `V` | **VERSION_GET** | --- | --- | major/minor | revision | Get flashcart firmware version |
| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option |
| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value |
| `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option |
| `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option |
| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value |
| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value |
| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart |
| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB |
| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length |
| `U` | **USB_WRITE_STATUS** | --- | --- | write_status | --- | Get USB write status |
| `i` | **SD_CARD_OP** | pi_address | operation | --- | return_data | Perform special operation on the SD card |
| `I` | **SD_SECTOR_SET** | sector | --- | --- | --- | Set starting sector for next SD card R/W operation |
| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from the SD card to flashcart memory space |
| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from the flashcart memory space to the SD card |
| `D` | **DISK_MAPPING_SET** | pi_address | table_size | --- | --- | Set 64DD disk mapping for SD mode |
| `w` | **WRITEBACK_PENDING** | --- | --- | pending_status | --- | Get save writeback status (is write queued to the SD card) |
| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it |
| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer |
| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size |
| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase |
| `%` | **DIAGNOSTIC_GET** | diagnostic_id | --- | --- | value | Get diagnostic data |

View File

@ -1,29 +0,0 @@
- [USB commands](#usb-commands)
---
## USB commands
| id | name | arg0 | arg1 | data | response | description |
| --- | ---------------------- | ------------ | ------------ | ---- | ---------------- | ------------------------------------------------------------- |
| `v` | **IDENTIFIER_GET** | --- | --- | --- | identifier | Get flashcart identifier `SCv2` |
| `V` | **VERSION_GET** | --- | --- | --- | version | Get flashcart firmware version |
| `R` | **STATE_RESET** | --- | --- | --- | --- | Reset flashcart state (CIC params and config options) |
| `B` | **CIC_PARAMS_SET** | cic_params_0 | cic_params_1 | --- | --- | Set CIC emulation parameters (disable/seed/checksum) |
| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option |
| `C` | **CONFIG_SET** | config_id | new_value | --- | --- | Set config option |
| `a` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option |
| `A` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option |
| `t` | **TIME_GET** | --- | --- | --- | time | Get current RTC value |
| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value |
| `m` | **MEMORY_READ** | address | length | --- | data | Read data from specified memory address |
| `M` | **MEMORY_WRITE** | address | length | data | --- | Write data to specified memory address |
| `U` | **USB_WRITE** | type | length | data | N/A | Send data to be received by app running on N64 (no response!) |
| `D` | **DD_SET_BLOCK_READY** | success | --- | --- | --- | Notify flashcart about 64DD block readiness |
| `W` | **WRITEBACK_ENABLE** | --- | --- | --- | --- | Enable save writeback through USB packet |
| `p` | **FLASH_WAIT_BUSY** | wait | --- | --- | erase_block_size | Wait until flash ready / Get flash block erase size |
| `P` | **FLASH_ERASE_BLOCK** | address | --- | --- | --- | Start flash block erase |
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
| `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address |
| `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info |
| `%` | **STACK_USAGE_GET** | --- | --- | --- | stack_usage | Get per task stack usage |

View File

@ -1,29 +0,0 @@
- [N64 commands](#n64-commands)
---
## N64 commands
| id | name | arg0 | arg1 | rsp0 | rsp1 | description |
| --- | --------------------- | ---------- | ------------ | ---------------- | -------------- | -------------------------------------------------- |
| `v` | **IDENTIFIER_GET** | --- | --- | identifier | --- | Get flashcart identifier `SCv2` |
| `V` | **VERSION_GET** | --- | --- | version | --- | Get flashcart firmware version |
| `c` | **CONFIG_GET** | config_id | --- | --- | current_value | Get config option |
| `C` | **CONFIG_SET** | config_id | new_value | --- | previous_value | Set config option and get previous value |
| `c` | **SETTING_GET** | setting_id | --- | --- | current_value | Get persistent setting option |
| `C` | **SETTING_SET** | setting_id | new_value | --- | --- | Set persistent setting option |
| `t` | **TIME_GET** | --- | --- | time_0 | time_1 | Get current RTC value |
| `T` | **TIME_SET** | time_0 | time_1 | --- | --- | Set new RTC value |
| `m` | **USB_READ** | pi_address | length | --- | --- | Receive data from USB to flashcart |
| `M` | **USB_WRITE** | pi_address | length/type | --- | --- | Send data from from flashcart to USB |
| `u` | **USB_READ_STATUS** | --- | --- | read_status/type | length | Get USB read status and type/length |
| `U` | **USB_WRITE_STATUS** | --- | --- | write_status | --- | Get USB write status |
| `i` | **SD_CARD_OP** | pi_address | operation | --- | return_data | Perform special operation on SD card |
| `I` | **SD_SECTOR_SET** | sector | --- | --- | --- | Set starting sector for next SD card R/W operation |
| `s` | **SD_READ** | pi_address | sector_count | --- | --- | Read sectors from SD card to flashcart |
| `S` | **SD_WRITE** | pi_address | sector_count | --- | --- | Write sectors from flashcart to SD card |
| `D` | **DD_SD_INFO** | pi_address | table_size | --- | --- | Set 64DD disk SD sector info |
| `W` | **WRITEBACK_SD_INFO** | pi_address | --- | --- | --- | Load writeback SD sector table and enable it |
| `K` | **FLASH_PROGRAM** | pi_address | length | --- | --- | Program flash with bytes loaded into data buffer |
| `p` | **FLASH_WAIT_BUSY** | wait | --- | erase_block_size | --- | Wait until flash ready / get block erase size |
| `P` | **FLASH_ERASE_BLOCK** | pi_address | --- | --- | --- | Start flash block erase |

773
docs/03_usb_interface.md Normal file
View File

@ -0,0 +1,773 @@
- [Protocol](#protocol)
- [Resetting communication](#resetting-communication)
- [PC -\> SC64 packets](#pc---sc64-packets)
- [**`CMD`** packet](#cmd-packet)
- [SC64 -\> PC packets](#sc64---pc-packets)
- [**`CMP`/`ERR`** packets](#cmperr-packets)
- [**`PKT`** packet](#pkt-packet)
- [Supported commands](#supported-commands)
- [`v`: **IDENTIFIER\_GET**](#v-identifier_get)
- [`response` (identifier)](#response-identifier)
- [`V`: **VERSION\_GET**](#v-version_get)
- [`response` (version)](#response-version)
- [`R`: **STATE\_RESET**](#r-state_reset)
- [`B`: **CIC\_PARAMS\_SET**](#b-cic_params_set)
- [`arg0` (cic\_params\_0)](#arg0-cic_params_0)
- [`arg1` (cic\_params\_1)](#arg1-cic_params_1)
- [`c`: **CONFIG\_GET**](#c-config_get)
- [`arg0` (config\_id)](#arg0-config_id)
- [`response` (config\_value)](#response-config_value)
- [`C`: **CONFIG\_SET**](#c-config_set)
- [`arg0` (config\_id)](#arg0-config_id-1)
- [`arg1` (config\_value)](#arg1-config_value)
- [`a`: **SETTING\_GET**](#a-setting_get)
- [`arg0` (setting\_id)](#arg0-setting_id)
- [`response` (setting\_value)](#response-setting_value)
- [`A`: **SETTING\_SET**](#a-setting_set)
- [`arg0` (setting\_id)](#arg0-setting_id-1)
- [`arg1` (setting\_value)](#arg1-setting_value)
- [`t`: **TIME\_GET**](#t-time_get)
- [`response` (time)](#response-time)
- [`T`: **TIME\_SET**](#t-time_set)
- [`arg0` (time\_0)](#arg0-time_0)
- [`arg1` (time\_1)](#arg1-time_1)
- [`m`: **MEMORY\_READ**](#m-memory_read)
- [`arg0` (address)](#arg0-address)
- [`arg1` (length)](#arg1-length)
- [`response` (data)](#response-data)
- [`M`: **MEMORY\_WRITE**](#m-memory_write)
- [`arg0` (address)](#arg0-address-1)
- [`arg1` (length)](#arg1-length-1)
- [`data` (data)](#data-data)
- [`U`: **USB\_WRITE**](#u-usb_write)
- [`arg0` (type)](#arg0-type)
- [`arg1` (length)](#arg1-length-2)
- [`data` (data)](#data-data-1)
- [`X`: **AUX\_WRITE**](#x-aux_write)
- [`arg0` (data)](#arg0-data)
- [`i`: **SD\_CARD\_OP**](#i-sd_card_op)
- [`arg0` (address)](#arg0-address-2)
- [`arg1` (operation)](#arg1-operation)
- [`response` (result/status)](#response-resultstatus)
- [Available SD card operations](#available-sd-card-operations)
- [SD card status](#sd-card-status)
- [`s`: **SD\_READ**](#s-sd_read)
- [`arg0` (address)](#arg0-address-3)
- [`arg1` (sector\_count)](#arg1-sector_count)
- [`data` (sector)](#data-sector)
- [`response` (result)](#response-result)
- [`S`: **SD\_WRITE**](#s-sd_write)
- [`arg0` (address)](#arg0-address-4)
- [`arg1` (sector\_count)](#arg1-sector_count-1)
- [`data` (sector)](#data-sector-1)
- [`response` (result)](#response-result-1)
- [`D`: **DD\_SET\_BLOCK\_READY**](#d-dd_set_block_ready)
- [`arg0` (error)](#arg0-error)
- [`W`: **WRITEBACK\_ENABLE**](#w-writeback_enable)
- [Asynchronous packets](#asynchronous-packets)
- [`X`: **AUX\_DATA**](#x-aux_data)
- [`data` (data)](#data-data-2)
- [`B`: **BUTTON**](#b-button)
- [`U`: **DATA**](#u-data)
- [`data` (data)](#data-data-3)
- [`G`: **DATA\_FLUSHED**](#g-data_flushed)
- [`D`: **DISK\_REQUEST**](#d-disk_request)
- [`data` (disk\_info/block\_data)](#data-disk_infoblock_data)
- [Fields details](#fields-details)
- [`I`: **IS\_VIEWER\_64**](#i-is_viewer_64)
- [`data` (text)](#data-text)
- [`S`: **SAVE\_WRITEBACK**](#s-save_writeback)
- [`data` (save\_contents)](#data-save_contents)
- [`F`: **UPDATE\_STATUS**](#f-update_status)
- [`data` (progress)](#data-progress)
- [Fields details](#fields-details-1)
---
## Protocol
SC64 exposes itself in the system as a simple serial device. This allows it to work without manually installed drivers.
Serial communication is also well supported in almost all programming languages making it easy to work with.
USB protocol use simple packet based communication. Every packet starts with 3 byte identifier and 1 byte data ID.
Every argument/data is sent as big-endian value.
### Resetting communication
Due to serial communication nature, data transfer between PC and flashcart might get out of sync (for example when long data transfer is aborted before sending/receiving all bytes).
Communication reset is done via emulated `DTR`/`DSR` pins.
Start reset procedure by setting `DTR` pin value to `high (1)`.
Next, observe `DSR` pin until its state is set to `high (1)`.
At this point communication has been reset and USB interface is disabled. Now it is a good moment to clear/purge any buffers.
Finish reset procedure by setting `DTR` pin value to `low (0)` and observe `DSR` pin until its state is set to `low (0)`.
Flashcart should be ready to accept new commands.
### PC -> SC64 packets
| identifier | description |
| ---------- | ------------------------ |
| `CMD` | Send command to the SC64 |
SC64 understands only one packet identifier - `CMD`.
Fourth byte denotes command ID listed in [supported commands](#supported-commands) section.
#### **`CMD`** packet
General structure of packet:
| offset | type | description |
| ------ | -------------------- | -------------------------- |
| `0` | char[3] | `CMD` identifier |
| `3` | char[1] | Command ID |
| `4` | uint32_t | First argument (arg0) |
| `8` | uint32_t | Second argument (arg1) |
| `12` | uint8_t[data_length] | Command data (if required) |
`CMD` packet always require arguments to be sent even if command does not require them.
Packet data length is derived from the argument if specific command supports it.
### SC64 -> PC packets
| identifier | description |
| ---------- | ---------------------------------------- |
| `CMP` | Success response to the received command |
| `ERR` | Error response to the received command |
| `PKT` | Asynchronous data packet |
SC64 sends response packet `CMP`/`ERR` to almost every command received from the PC.
Fourth byte is the same as in the command that triggered the response.
If command execution was not successful, then `CMP` identifier is replaced by the `ERR` identifier.
SC64 can also send `PKT` packet at any time as a response to action triggered by the N64 or the flashcart itself.
Fourth byte denotes packet ID listed in the [asynchronous packets](#asynchronous-packets) section.
#### **`CMP`/`ERR`** packets
General structure of packet:
| offset | type | description |
| ------ | -------------------- | ---------------------- |
| `0` | char[3] | `CMP`/`ERR` identifier |
| `3` | char[1] | Command ID |
| `4` | uint32_t | Response data length |
| `8` | uint8_t[data_length] | Response data (if any) |
`CMP`/`ERR` packet is sent as a response to the command sent by the PC.
`ERR` response might contain no (or undefined) data in the arbitrary data field compared to regular `CMP` packet.
#### **`PKT`** packet
General structure of packet:
| offset | type | description |
| ------ | -------------------- | -------------------- |
| `0` | char[3] | `PKT` identifier |
| `3` | char[1] | Packet ID |
| `4` | uint32_t | Packet data length |
| `8` | uint8_t[data_length] | Packet data (if any) |
Available packet IDs are listed in the [asynchronous packets](#asynchronous-packets) section.
---
## Supported commands
| id | name | arg0 | arg1 | data | response | description |
| --- | ----------------------------------------------- | ------------ | ------------- | ------ | ---------------- | -------------------------------------------------------------- |
| `v` | [**IDENTIFIER_GET**](#v-identifier_get) | --- | --- | --- | identifier | Get flashcart identifier `SCv2` |
| `V` | [**VERSION_GET**](#v-version_get) | --- | --- | --- | version | Get flashcart firmware version |
| `R` | [**STATE_RESET**](#r-state_reset) | --- | --- | --- | --- | Reset flashcart state (CIC params and config options) |
| `B` | [**CIC_PARAMS_SET**](#b-cic_params_set) | cic_params_0 | cic_params_1 | --- | --- | Set CIC emulation parameters (disable/seed/checksum) |
| `c` | [**CONFIG_GET**](#c-config_get) | config_id | --- | --- | config_value | Get config option |
| `C` | [**CONFIG_SET**](#c-config_set) | config_id | config_value | --- | --- | Set config option |
| `a` | [**SETTING_GET**](#a-setting_get) | setting_id | --- | --- | setting_value | Get persistent setting option |
| `A` | [**SETTING_SET**](#a-setting_set) | setting_id | setting_value | --- | --- | Set persistent setting option |
| `t` | [**TIME_GET**](#t-time_get) | --- | --- | --- | time | Get current RTC value |
| `T` | [**TIME_SET**](#t-time_set) | time_0 | time_1 | --- | --- | Set new RTC value |
| `m` | [**MEMORY_READ**](#m-memory_read) | address | length | --- | data | Read data from specified memory address |
| `M` | [**MEMORY_WRITE**](#m-memory_write) | address | length | data | --- | Write data to specified memory address |
| `U` | [**USB_WRITE**](#u-usb_write) | type | length | data | N/A | Send data to be received by app running on N64 (no response!) |
| `X` | [**AUX_WRITE**](#x-aux_write) | data | --- | --- | --- | Send small auxiliary data to be received by app running on N64 |
| `i` | [**SD_CARD_OP**](#i-sd_card_op) | address | operation | --- | result/status | Perform special operation on the SD card |
| `s` | [**SD_READ**](#s-sd_read) | address | sector_count | sector | result | Read sectors from the SD card to flashcart memory space |
| `S` | [**SD_WRITE**](#s-sd_write) | address | sector_count | sector | result | Write sectors from the flashcart memory space to the SD card |
| `D` | [**DD_SET_BLOCK_READY**](#d-dd_set_block_ready) | error | --- | --- | --- | Notify flashcart about 64DD block readiness |
| `W` | [**WRITEBACK_ENABLE**](#w-writeback_enable) | --- | --- | --- | --- | Enable save writeback through USB packet |
| `p` | **FLASH_WAIT_BUSY** | wait | --- | --- | erase_block_size | Wait until flash ready / Get flash block erase size |
| `P` | **FLASH_ERASE_BLOCK** | address | --- | --- | --- | Start flash block erase |
| `f` | **FIRMWARE_BACKUP** | address | --- | --- | status/length | Backup firmware to specified memory address |
| `F` | **FIRMWARE_UPDATE** | address | length | --- | status | Update firmware from specified memory address |
| `?` | **DEBUG_GET** | --- | --- | --- | debug_data | Get internal FPGA debug info |
| `%` | **DIAGNOSTIC_GET** | --- | --- | --- | diagnostic_data | Get diagnostic data |
---
### `v`: **IDENTIFIER_GET**
**Get flashcart identifier `SCv2`**
_This command does not require arguments or data._
#### `response` (identifier)
| offset | type | description |
| ------ | ------- | ----------- |
| `0` | char[4] | Identifier |
Identifier is always `SCv2` represented in ASCII code.
---
### `V`: **VERSION_GET**
**Get flashcart firmware version**
_This command does not require arguments or data._
#### `response` (version)
| offset | type | description |
| ------ | -------- | ------------- |
| `0` | uint16_t | Major version |
| `2` | uint16_t | Minor version |
| `4` | uint32_t | Revision |
Increment in major version represents breaking API changes.
Increment in minor version represents non breaking API changes.
Increment in revision field represents no API changes, usually it's denoting bugfixes.
---
### `R`: **STATE_RESET**
**Reset flashcart state (CIC params and config options)**
_This command does not require arguments or data._
_This command does not send response data._
This command is used to reset most of the config options to default state (same as on power-up).
Additionally, CIC emulation is enabled, 6102/7101 seed/checksum values are set and SD card lock is released.
---
### `B`: **CIC_PARAMS_SET**
**Set CIC emulation parameters (disable/seed/checksum)**
#### `arg0` (cic_params_0)
| bits | description |
| --------- | ------------------------------- |
| `[32:25]` | _Unused_ |
| `[24]` | Disable CIC |
| `[23:16]` | CIC seed (IPL2 and IPL3 stages) |
| `[15:0]` | Checksum (upper 16 bits) |
#### `arg1` (cic_params_1)
| bits | description |
| -------- | ------------------------ |
| `[31:0]` | Checksum (lower 32 bits) |
_This command does not send response data._
Use this command to set custom seed/checksum CIC values. Very useful for testing custom IPL3 replacements.
---
### `c`: **CONFIG_GET**
**Get config option**
#### `arg0` (config_id)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Config ID |
#### `response` (config_value)
| offset | type | description |
| ------ | -------- | ------------ |
| `0` | uint32_t | Config value |
Use this command to get value of config option. Available config options are listed [here](./04_config_options.md).
---
### `C`: **CONFIG_SET**
**Set config option**
#### `arg0` (config_id)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Config ID |
#### `arg1` (config_value)
| bits | description |
| -------- | ------------ |
| `[31:0]` | Config value |
_This command does not send response data._
Use this command to set value of config option. Available config options are listed [here](./04_config_options.md).
---
### `a`: **SETTING_GET**
**Get persistent setting option**
#### `arg0` (setting_id)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Setting ID |
#### `response` (setting_value)
| offset | type | description |
| ------ | -------- | ------------- |
| `0` | uint32_t | Setting value |
Use this command to get value of persistent setting option. Available persistent setting options are listed [here](./04_config_options.md).
---
### `A`: **SETTING_SET**
**Set persistent setting option**
#### `arg0` (setting_id)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Setting ID |
#### `arg1` (setting_value)
| bits | description |
| -------- | ------------- |
| `[31:0]` | Setting value |
_This command does not send response data._
Use this command to set value of persistent setting option. Available persistent setting options are listed [here](./04_config_options.md).
---
### `t`: **TIME_GET**
**Get current RTC value**
_This command does not require arguments or data._
#### `response` (time)
| offset | type | description |
| ------ | ------- | --------------------------------------- |
| `0` | uint8_t | Weekday (1 - 7), 1 represents Monday |
| `1` | uint8_t | Hours (0 - 23) |
| `2` | uint8_t | Minutes (0 - 59) |
| `3` | uint8_t | Seconds (0 - 59) |
| `4` | uint8_t | Century (0 - 7), 0 represents year 1900 |
| `5` | uint8_t | Year (0 - 99) |
| `6` | uint8_t | Month (1 - 12) |
| `7` | uint8_t | Day (1 - 31) |
Date/time values use the [BCD](https://en.wikipedia.org/wiki/Binary-coded_decimal) format.
---
### `T`: **TIME_SET**
**Set new RTC value**
#### `arg0` (time_0)
| bits | description |
| --------- | ------------------------------------ |
| `[31:24]` | Weekday (1 - 7), 1 represents Monday |
| `[23:16]` | Hours (0 - 23) |
| `[15:8]` | Minutes (0 - 59) |
| `[7:0]` | Seconds (0 - 59) |
#### `arg1` (time_1)
| bits | description |
| --------- | --------------------------------------- |
| `[31:24]` | Century (0 - 7), 0 represents year 1900 |
| `[23:16]` | Year (0 - 99) |
| `[15:8]` | Month (1 - 12) |
| `[7:0]` | Day (1 - 31) |
_This command does not send response data._
Date/time values use the [BCD](https://en.wikipedia.org/wiki/Binary-coded_decimal) format.
---
### `m`: **MEMORY_READ**
**Read data from specified memory address**
#### `arg0` (address)
| bits | description |
| -------- | ----------------------- |
| `[31:0]` | Starting memory address |
#### `arg1` (length)
| bits | description |
| -------- | --------------------------------------- |
| `[31:0]` | Number of bytes to read from the memory |
#### `response` (data)
| offset | type | description |
| ------ | --------------- | --------------- |
| `0` | uint8_t[length] | Memory contents |
Reads bytes from the specified memory address. Please refer to the [internal memory map](./01_memory_map.md) for available memory ranges.
---
### `M`: **MEMORY_WRITE**
**Write data to specified memory address**
#### `arg0` (address)
| bits | description |
| -------- | ----------------------- |
| `[31:0]` | Starting memory address |
#### `arg1` (length)
| bits | description |
| -------- | -------------------------------------- |
| `[31:0]` | Number of bytes to write to the memory |
#### `data` (data)
| offset | type | description |
| ------ | --------------- | --------------------------- |
| `0` | uint8_t[length] | Data to write to the memory |
_This command does not send response data._
Writes bytes to the specified memory address. Please refer to the [internal memory map](./01_memory_map.md) for available memory ranges.
---
### `U`: **USB_WRITE**
**Send data to be received by app running on N64 (no response!)**
#### `arg0` (type)
| bits | description |
| -------- | ----------- |
| `[31:8]` | _Unused_ |
| `[7:0]` | Datatype |
#### `arg1` (length)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Data length |
#### `data` (data)
| offset | type | description |
| ------ | --------------- | -------------- |
| `0` | uint8_t[length] | Arbitrary data |
_This command does not send response data._
_This command does not send `CMP`/`ERR` packet response!_
This command notifies N64 that data is waiting to be acknowledged.
If N64 side doesn't acknowledge data via [`m` **USB_READ**](./02_n64_commands.md#m-usb_read) N64 command within 1 second then data is flushed and [`G` **DATA_FLUSHED**](#asynchronous-packets) asynchronous packet is sent to the PC.
If N64 acknowledge the request, then data is written to the flashcart memory to address specified in [`m` **USB_READ**](./02_n64_commands.md) N64 command.
---
### `X`: **AUX_WRITE**
**Send small auxiliary data to be received by app running on N64**
#### `arg0` (data)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Data |
_This command does not send response data._
This command puts 32 bits of data to the AUX register accessible from the N64 side, and generates cart interrupt (if enabled).
---
### `i`: **SD_CARD_OP**
**Perform special operation on the SD card**
#### `arg0` (address)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Address |
#### `arg1` (operation)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Operation |
#### `response` (result/status)
| offset | type | description |
| ------ | -------- | ---------------------------------------------------------------------------------------------- |
| `0` | uint32_t | Operation result (valid values are listed in the [sd_error_t](../sw/controller/src/sd.h) enum) |
| `4` | uint32_t | SD card status (always returned and valid regardless of the SD card operation result) |
This command performs special operation on the SD card. When operation result is not `SD_OK`, then `ERR` packet is returned.
PC and N64 cannot use the SD card interface at the same time. Lock mechanism is implemented to prevent data corruption.
SD card access is locked when PC or N64 requests SD card initialization, and unlocked when the card is uninitialized.
Lock is also released when certain conditions occur - when N64 side lock is active then it is released when the console is powered off
and save writeback operation is not pending. PC side lock is released when USB interface is in reset state, or the USB cable is unplugged.
#### Available SD card operations
| operation | description |
| --------- | ---------------------------------------------------------------------------------------------- |
| `0` | Init SD card |
| `1` | Deinit SD card |
| `2` | Get SD card status |
| `3` | Get SD card info (loads CSD and CID registers to a specified address, data length is 32 bytes) |
| `4` | Turn on byte swap |
| `5` | Turn off byte swap |
#### SD card status
| bits | description |
| -------- | -------------------------------------------------------------------------- |
| `[31:5]` | _Unused_ |
| `[4]` | `0` - Byte swap disabled, `1` - Byte swap enabled (valid when initialized) |
| `[3]` | `0` - 25 MHz clock, `1` - 50 MHz clock (valid when initialized) |
| `[2]` | `0` - Byte addressed, `1` - Sector addressed (valid when initialized) |
| `[1]` | `0` - SD card not initialized, `1` - SD card initialized |
| `[0]` | `0` - SD card not inserted, `1` - SD card inserted |
---
### `s`: **SD_READ**
**Read sectors from the SD card to flashcart memory space**
#### `arg0` (address)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Address |
#### `arg1` (sector_count)
| bits | description |
| -------- | ------------ |
| `[31:0]` | Sector count |
#### `data` (sector)
| offset | type | description |
| ------ | -------- | --------------- |
| `0` | uint32_t | Starting sector |
#### `response` (result)
| offset | type | description |
| ------ | -------- | ---------------------------------------------------------------------------------------------- |
| `0` | uint32_t | Operation result (valid values are listed in the [sd_error_t](../sw/controller/src/sd.h) enum) |
This command reads sectors from the SD card to a specified memory address. When operation result is not `SD_OK`, then `ERR` packet is returned.
---
### `S`: **SD_WRITE**
**Write sectors from the flashcart memory space to the SD card**
#### `arg0` (address)
| bits | description |
| -------- | ----------- |
| `[31:0]` | Address |
#### `arg1` (sector_count)
| bits | description |
| -------- | ------------ |
| `[31:0]` | Sector count |
#### `data` (sector)
| offset | type | description |
| ------ | -------- | --------------- |
| `0` | uint32_t | Starting sector |
#### `response` (result)
| offset | type | description |
| ------ | -------- | ---------------------------------------------------------------------------------------------- |
| `0` | uint32_t | Operation result (valid values are listed in the [sd_error_t](../sw/controller/src/sd.h) enum) |
This command writes sectors from a specified memory address to the SD card. When operation result is not `SD_OK`, then `ERR` packet is returned.
---
### `D`: **DD_SET_BLOCK_READY**
**Notify flashcart about 64DD block readiness**
#### `arg0` (error)
| bits | description |
| -------- | -------------------------- |
| `[31:1]` | _Unused_ |
| `[0]` | `0` - Success, `1` - Error |
_This command does not send response data._
This command informs SC64 that 64DD disk block data was successfully (or not) read to the requested buffer or written to the 64DD disk file.
This command must be sent for each incoming [**DISK_REQUEST**](#d-disk_request) asynchronous packet.
---
### `W`: **WRITEBACK_ENABLE**
**Enable save writeback through USB packet**
_This command does not require arguments or data._
_This command does not send response data._
This command is used to enable save writeback module and set its mode to send data to the USB interface instead of writing to the SD card.
To disable save writeback change save type via [**SAVE_TYPE**](./04_config_options.md#6-save_type) config option (setting the same save type as currently enabled will also disable writeback module).
Save data is sent via [**SAVE_WRITEBACK**](#s-save_writeback) asynchronous packet.
---
## Asynchronous packets
| id | name | data | description |
| --- | --------------------------------------- | -------------------- | --------------------------------------------------------------------- |
| `X` | [**AUX_DATA**](#x-aux_data) | data | Data was written to the `AUX` register from the N64 side |
| `B` | [**BUTTON**](#b-button) | --- | Button on the back of the SC64 was pressed |
| `U` | [**DATA**](#u-data) | data | Data sent from the N64 |
| `G` | [**DATA_FLUSHED**](#g-data_flushed) | --- | Data from [`U` **USB_WRITE**](#u-usb_write) USB command was discarded |
| `D` | [**DISK_REQUEST**](#d-disk_request) | disk_info/block_data | 64DD disk block R/W request |
| `I` | [**IS_VIEWER_64**](#i-is_viewer_64) | text | IS-Viewer 64 `printf` text |
| `S` | [**SAVE_WRITEBACK**](#s-save_writeback) | save_contents | Flushed save data |
| `F` | [**UPDATE_STATUS**](#f-update_status) | progress | Firmware update progress |
---
### `X`: **AUX_DATA**
**Data was written to the `AUX` register from the N64 side**
This packet is sent when N64 writes to the `AUX` register in the SC64 register block.
#### `data` (data)
| offset | type | description |
| ------ | -------- | ----------- |
| `0` | uint32_t | Data |
---
### `B`: **BUTTON**
**Button on the back of the SC64 was pressed**
This packet is sent only when [**BUTTON_MODE**](./04_config_options.md#13-button_mode) config option is set to value "`2` - Button press sends USB packet".
_This packet does not send additional data._
---
### `U`: **DATA**
**Data sent from the N64**
This packet is sent when N64 command [**USB_WRITE**](./02_n64_commands.md#m-usb-write) is executed.
#### `data` (data)
| offset | type | description |
| ------ | -------------------- | ----------- |
| `0` | uint8_t | Datatype |
| `1` | uint24_t | Data length |
| `4` | uint8_t[data_length] | Packet data |
---
### `G`: **DATA_FLUSHED**
**Data from [`U` **USB_WRITE**](#u-usb_write) USB command was discarded**
This packet is sent only when data sent with USB command [`U` **USB_WRITE**](#u-usb_write) was not acknowledged by the N64 side with [`m` **USB_READ**](./02_n64_commands.md#m-usb_read) within 1 second time limit.
_This packet does not send additional data._
---
### `D`: **DISK_REQUEST**
**64DD disk block R/W request**
This packet is sent when 64DD mode is set to pass R/W requests to the USB interface with [**DD_SD_ENABLE**](./04_config_options.md#9-dd_sd_enable) config option.
Every disk request packet must be acknowledged by the PC side with [`D` **DD_SET_BLOCK_READY**](#d-dd_set_block_ready) USB command.
#### `data` (disk_info/block_data)
| offset | type | description |
| ------ | --------------------------- | ---------------------------------------------------- |
| `0` | uint32_t | Disk command |
| `4` | uint32_t | Memory address |
| `8` | uint32_t | Disk track/head/block |
| `12` | uint8_t[packet_length - 12] | Data to be written to the 64DD disk block (optional) |
#### Fields details
**Disk command**:
| value | description |
| ----- | ------------------------------ |
| `1` | Read data from 64DD disk block |
| `2` | Write data to 64DD disk block |
**Memory address**:
Internal SC64 address where data is expected to be written for read command
**Disk track/head/block**:
| bits | description |
| --------- | ----------- |
| `[31:13]` | _Unused_ |
| `[12:2]` | Track |
| `[1]` | Head |
| `[0]` | Block |
---
### `I`: **IS_VIEWER_64**
**IS-Viewer 64 `printf` text**
This packet is sent when IS-Viewer 64 module is enabled in the SC64 with [**ISV_ADDRESS**](./04_config_options.md#4-isv_address) config option, and data is written to the IS-Viewer 64 buffer.
#### `data` (text)
| offset | type | description |
| ------ | ---------------------- | ----------- |
| `0` | uint8_t[packet_length] | Text |
---
### `S`: **SAVE_WRITEBACK**
**Flushed save data**
This packet is sent when save writeback module is enabled and set to send data to the USB interface with [`W` **WRITEBACK_ENABLE**](#w-writeback_enable) USB command.
Save data is flushed after 1 second delay from the last write to the save region by the app/game running on the N64.
#### `data` (save_contents)
| offset | type | description |
| ------ | -------------------------- | ---------------------------------------------------------------------------------------- |
| `0` | uint32_t | Save type (same as in [**SAVE_TYPE**](./04_config_options.md#6-save_type) config option) |
| `4` | uint8_t[packet_length - 4] | Save data |
---
### `F`: **UPDATE_STATUS**
**Firmware update progress**
This packet is sent during firmware update process to indicate progress and errors.
#### `data` (progress)
| offset | type | description |
| ------ | -------- | ----------- |
| `0` | uint32_t | Progress |
#### Fields details
**Progress**:
| value | description |
| ------ | ------------------------------------------------------- |
| `1` | Update process has started flashing MCU software |
| `2` | Update process has started flashing FPGA firmware |
| `3` | Update process has started flashing bootloader software |
| `0x80` | Firmware update process was successful |
| `0xFF` | Error encountered during firmware update process |

View File

@ -133,9 +133,10 @@ type: *enum* | default: `0`
- `4` - FlashRAM 1 Mib save is enabled
- `5` - SRAM 768 kib save is enabled
- `6` - SRAM 1 Mib save is enabled
- `7` - FakeFlashRAM 1 Mib save is enabled (write/erase timings are not emulated and erase before write is not required)
Use this setting for selecting save type that will be emulated. Only one save type can be enabled.
Any successful write to this config will disable automatic save writeback to USB or SD card when previously enabled.
Any successful write to this config will disable automatic save writeback to the USB or SD card if previously enabled.
---
@ -148,7 +149,7 @@ type: *word* | default: `0xFFFF`
Use this setting to force specific CIC seed.
By setting value `0xFFFF` bootloader will try to guess needed values from loaded ROM IPL3.
This setting is not used when **BOOT_MODE** is set to `3` or `4` (direct boot).
This setting is not used when **BOOT_MODE** is set to `0` (menu), `3` or `4` (direct boot).
---

23
docs/05_fw_and_sw_info.md Normal file
View File

@ -0,0 +1,23 @@
- [Building FW/SW](#building-fwsw)
- [Docker method](#docker-method)
- [Lattice Diamond license](#lattice-diamond-license)
---
## Building FW/SW
### Docker method
Docker method is a preferred option.
Run `./docker_build.sh release` to build all firmware/software and generate release package.
For other options run script without any command to print help about available options.
#### Lattice Diamond license
Lattice Diamond software is used to build the FPGA bitstream.
A free 1 year license is necessary to run the build process.
You can request personal license from the [Lattice website](https://www.latticesemi.com/Support/Licensing).
Build script expects license file to be present in this path: `fw/project/lcmxo2/license.dat`.
Since build is done inside docker container it is required to pass the MAC address, linked with the license file, to a container.
Build script expects it in the `MAC_ADDRESS` environment variable.
For example, run `MAC_ADDRESS=AB:00:00:00:00:00 ./docker_build.sh release` command to start the building process if your license is attached to `AB:00:00:00:00:00` MAC address.

144
docs/06_build_guide.md Normal file
View File

@ -0,0 +1,144 @@
- [Video guide](#video-guide)
- [Step by step guide how to make SC64](#step-by-step-guide-how-to-make-sc64)
- [**PCB manufacturing data**](#pcb-manufacturing-data)
- [**PCB requirements**](#pcb-requirements)
- [**Components**](#components)
- [**Plastic shell**](#plastic-shell)
- [**Putting it together**](#putting-it-together)
- [**Initial programming**](#initial-programming)
- [**Troubleshooting**](#troubleshooting)
- [*`primer.py` threw `No SC64 USB device found` error*](#primerpy-threw-no-sc64-usb-device-found-error)
- [*`primer.py` threw `SDRAM test error...` message*](#primerpy-threw-sdram-test-error-message)
- [*`primer.py` threw other error message*](#primerpy-threw-other-error-message)
---
## Video guide
[![Video guide](https://img.youtube.com/vi/t6hyCFpwqz8/0.jpg)](https://www.youtube.com/watch?v=t6hyCFpwqz8 "How to build and program the SummerCart64")
## Step by step guide how to make SC64
All necessary manufacturing files are packaged in every `sc64-extra-{version}.zip` file in GitHub releases.
Please download latest release before proceeding with the instructions.
---
### **PCB manufacturing data**
1. Locate KiCad project inside `hw/pcb` folder
2. Export gerber/drill files
3. Export BOM spreadsheet
4. Export PnP placement files
5. Send appropriate files to the PCB manufacturer
---
### **PCB requirements**
***Before ordering PCBs make sure you select correct options listed below:***
- PCB thickness: 1.2 mm
- Surface finish (plating): ENIG (Hard gold for edge connector is recommended but it's very expensive)
- PCB contains edge connector: yes
- Beveled edge connector: yes, 45° (other angles also should work OK)
---
### **Components**
1. Locate the interactive BOM file inside `hw/pcb` folder
2. Order all parts listed in the BOM file or use PCB assembly service together with your PCB order
---
### **Plastic shell**
1. Locate `.stl` files inside `hw/shell` folder
2. Use these files in the slicer and 3D printer of your choice or order ready made prints from 3D printing company
3. For screws, M2x10 works great for the top two holes while M2x8 fits well in the bottom two
---
### **Putting it together**
There are no special requirements for soldering components to board.
All chips and connectors can be soldered with standard manual soldering iron, although hot air station is recommended.
Interactive BOM has every component and its value highlighted on PCB drawings and it's strongly recommended to use during assembly process.
You can skip this step if PCB assembly service was used in previous steps.
---
### **Initial programming**
**Please read the following instructions carefully before proceeding with programming.**
***Note:*** This guide assumes you are using Windows 10 or above.
You will require the following hardware:
- A PC running Windows 10 or above (any Linux distro should also work but programming FT232H EEPROM is arguably trickier without an official app).
- A USB to UART (serial) adapter (with 3.3V signaling is required, e.g. TTL-232R-3V3).
You will require the following applications and packages:
- [Latest FTDI drivers](https://ftdichip.com/drivers/)
- [FT_PROG](https://ftdichip.com/utilities/#ft_prog) - FTDI FT232H EEPROM programming software.
- [Python 3](https://www.python.org/downloads/) with `pip3` - necessary for initial programming script: `primer.py` (Windows install: check option add python to PATH).
- [`sc64-extra-{version}.zip`](https://github.com/Polprzewodnikowy/SummerCart64/releases) - programming scripts and firmware files, download the latest version.
**Programming must be done in specific order for `primer.py` script to work correctly.**
Preparations:
1. Install latest FTDI drivers (especially on Windows 10).
2. Install FT_PROG.
3. Install Python 3.
4. Unpack `sc64-extra-{version}.zip` into a folder.
5. Open terminal and navigate to the folder you've unpacked SC64 files.
First, program the ***FT232H EEPROM***:
1. Connect the SC64 board to your PC with a USB-C cable.
2. Locate FT232H EEPROM template `ft232h_config.xml` from the `fw/ftdi/` directory.
3. Launch `FT_PROG` software.
4. Click on `Scan and parse` if no device has shown up.
5. Right click on SC64 device and choose `Apply Template -> From File`.
6. Select previously located `ft232h_config.xml`.
7. Right click on SC64 device and choose `Program Device`.
Your SC64 should be ready for next programming step.
Second, program ***FPGA, microcontroller and bootloader***:
1. Disconnect SC64 board from power (unplug USB-C cable).
2. Connect serial UART/TTL adapter to `TX/RX/GND` pads marked on the PCB. Cross connection `TX -> RX`, `RX -> TX`!
3. Connect serial adapter to the PC.
4. Check in device manager which port number `COMx` is assigned to serial adapter.
5. Connect SC64 board to the PC with USB-C cable (***IMPORTANT:*** connect it to the same computer as serial adapter).
6. Locate `primer.py` script in the root folder.
7. Make sure these files are located in the same folder as `primer.py` script: `requirements.txt`, `sc64-firmware-{version}.bin`.
8. Run `pip3 install -r requirements.txt` in the terminal to install required python packages.
9. Run `python3 primer.py COMx sc64-firmware-{version}.bin` (replace `COMx` with port located in step **4**). On Windows it's `python` instead of `python3`.
10. Follow the instructions on the screen.
11. Wait until programming process has finished (**DO NOT STOP PROGRAMMING PROCESS OR DISCONNECT SC64 BOARD FROM PC**, doing so might irrecoverably break programming through UART header and you would need to program FPGA and/or microcontroller with separate dedicated programming interfaces through *Tag-Connect* connector on the PCB).
Congratulations! Your SC64 flashcart should be ready for use!
---
### **Troubleshooting**
#### *`primer.py` threw `No SC64 USB device found` error*
This issue can be attributed to incorrectly programmed FT232H EEPROM in the first programming step.
Check again in `FT_PROG` application if device was configured properly.
Make sure default FTDI drivers are installed for the SC64 in the device manager (only on Windows OS).
Make sure you have correct access to `/dev/ttyUSBx` device and `ftdi_sio` and `usbserial` modules are loaded (only on Linux OS).
#### *`primer.py` threw `SDRAM test error...` message*
This issue shows up when there's a problem with the connection to the SDRAM chip or the chip itself is malfunctioning.
Check for any solder bridges and unconnected pins on U8/U9 chips.
Once FPGA and microcontroller has been programmed successfully `primer.py` script needs to be run in special mode.
Please use command `python3 primer.py COMx sc64-firmware-{version}.bin --bootloader-only` to test SDRAM again and continue bootloader programming process.
#### *`primer.py` threw other error message*
Due to multiple possible causes of the problem it's best to start visually inspecting SC64's board for any defects, like bad solder work or chips soldered backwards.
If visual inspection didn't yield any obvious culprits then next step would be to check if everything is connected correctly.
Check if TX/RX signals aren't swapped and if SC64 is getting power from the USB cable. Best place to check supply voltage are the exposed test pads on the left of U8 chip.

View File

@ -1,110 +0,0 @@
- [Step by step guide how to make SC64](#step-by-step-guide-how-to-make-sc64)
- [**PCB manufacturing data**](#pcb-manufacturing-data)
- [**PCB requirements**](#pcb-requirements)
- [**Components**](#components)
- [**Plastic shell**](#plastic-shell)
- [**Putting it together**](#putting-it-together)
- [**Initial programming**](#initial-programming)
- [**Troubleshooting**](#troubleshooting)
---
## Step by step guide how to make SC64
All necessary manufacturing files are packaged in every `sc64-extra-{version}.zip` file in GitHub releases.
Please download latest release before proceeding with the instructions.
---
### **PCB manufacturing data**
1. Locate KiCad project inside `hw/pcb` folder
2. Export gerber/drill files
3. Export BOM spreadsheet
4. Export PnP placement files
5. Send appropriate files to the PCB manufacturer
---
### **PCB requirements**
- Thickness: 1.2 mm
- At least ENIG plating or better
- PCB contains edge connector: yes
- Beveled edge connector: yes, 45°
---
### **Components**
1. Locate interactive BOM file inside `hw/pcb` folder
2. Order all parts listed in the BOM file or use PCB assembly service together with your PCB order
---
### **Plastic shell**
1. Locate `.stl` files inside `hw/shell` folder
2. Use these files in the slicer and 3D printer of your choice or order ready made prints from 3D printing company
3. Find matching screws, go to discussions tab for community recommendations
---
### **Putting it together**
There are no special requirements for soldering components to board.
All chips and connectors can be soldered with standard manual soldering iron, although hot air station is recommended.
Interactive BOM has every component and its value highlighted on PCB drawings and it's strongly recommended to use during assembly process.
You can skip this step if PCB assembly service was used in previous steps.
---
### **Initial programming**
**Please read the following instructions carefully before proceeding with programming.**
For initial programming you are going to need a PC and a USB to UART (serial) adapter (3.3V signaling is required).
These steps assume you are using modern Windows OS (version 10 or higher).
As for software here's list of required applications:
- [FT_PROG](https://ftdichip.com/utilities/#ft_prog) - FTDI FT232H EEPROM programming software
- [Python 3](https://www.python.org/downloads/) with `pip3` - necessary for initial programming script: `primer.py`
Programming must be done in specific order for `primer.py` script to work correctly.
First, program FT232H EEPROM:
1. Connect SC64 board to the PC with USB-C cable
2. Locate FT232H EEPROM template `ft232h_config.xml`
3. Launch `FT_PROG` software
4. Click on `Scan and parse` if no device has shown up
5. Right click on SC64 device and choose `Apply Template -> From File`
6. Select previously located `ft232h_config.xml`
7. Right click on SC64 device and choose `Program Device`
Your SC64 should be ready for next programming step.
Second, program FPGA, microcontroller and bootloader:
1. Disconnect SC64 board from power (unplug USB-C cable)
2. Connect serial adapter to `TX/RX/GND` pads marked on the PCB
3. Connect serial adapter to the PC
4. Check in device manager which port number `COMx` is assigned to serial adapter
5. Connect SC64 board to the PC with USB-C cable (***IMPORTANT:*** connect it to the same computer as serial adapter)
6. Locate `primer.py` script in root folder
7. Make sure these files are located in the same folder as `primer.py` script: `requirements.txt`, `sc64-firmware-{version}.bin`
8. Run `pip3 install -r requirements.txt` to install required python packages
9. Run `python3 primer.py COMx sc64-firmware-{version}.bin` (replace `COMx` with port located in step **4**)
10. Follow the instructions on the screen
11. Wait until programming process has finished (**DO NOT STOP PROGRAMMING PROCESS OR DISCONNECT SC64 BOARD FROM PC**, doing so might irrecoverably break programming through UART header and you would need to program FPGA and/or microcontroller with separate dedicated programming interfaces through *Tag-Connect* connector on the PCB)
Congratulations! Your SC64 flashcart should be ready for use!
---
### **Troubleshooting**
*`primer.py` threw error on `Bootloader -> SC64 FLASH` step*
This issue can be attributed to incorrectly programmed FT232H EEPROM in the first programming step.
Check again in `FT_PROG` application if device was configured properly.
Once FPGA and microcontroller has been programmed successfully `primer.py` script needs to be run in special mode.
Please use command `python3 primer.py COMx sc64-firmware-{version}.bin --bootloader-only` to try programming bootloader again.

View File

@ -1,15 +1,12 @@
# SC64 - an open source Nintendo 64 flashcart
[<img src="../assets/sc64_logo_256_160.png" />](../assets/sc64_logo_256_160.png)
---
# SummerCart64 - a fully open source N64 flashcart
[<img src="../assets/sc64_logo.svg" />](../assets/sc64_logo.svg)
## Documentation
- [Quick startup guide](./00_quick_startup_guide.md)
- [Memory map](./01_memory_map.md)
- [USB commands](./02_usb_commands.md)
- [N64 commands](./03_n64_commands.md)
- [N64 commands](./02_n64_commands.md)
- [USB interface](./03_usb_interface.md)
- [Config options](./04_config_options.md)
- [FW/SW building](./05_fw_sw_building.md)
- [Manufacturing guidelines](./06_manufacturing_guidelines.md)
- [FW and SW info](./05_fw_and_sw_info.md)
- [Build guide](./06_build_guide.md)

View File

@ -1,6 +1,7 @@
.recovery
*.dir/
*.ccl
*.dat
*.dmp
*.html
*.ini
@ -11,6 +12,7 @@
*.tcl
*.tpf
*.trc
*.txt
*.xml
impl*/

View File

@ -1,5 +1,33 @@
#!/bin/bash
set -e
source $bindir/diamond_env
printf "[$(hostname)]\nSYSTEM=Linux\nCORENUM=$(nproc --all)\n" > $(dirname $0)/multicore.txt
diamondc build.tcl
MINIMUM_FREQ=$(cat impl1/sc64_impl1.twr \
| grep 'Preference: FREQUENCY NET "clk"' \
| head -1 \
| awk -F ' ' '{print $5}' \
)
DESIGN_FREQ=$(cat impl1/sc64_impl1.twr \
| sed -n '/Preference: FREQUENCY NET "clk"/,$p' \
| grep 'is the maximum frequency for this preference' \
| head -1 \
| awk -F ' ' '{print $2}' \
| sed 's/MHz//' \
)
echo "Minimum required frequency: $MINIMUM_FREQ MHz"
echo "Maximum design frequency: $DESIGN_FREQ MHz"
if (( $(echo "$DESIGN_FREQ < $MINIMUM_FREQ" | bc -l) )); then
echo "Timing error detected, build failed"
exit 1
fi
echo -n "$DESIGN_FREQ MHz" > impl1/fpga_max_frequency.txt

View File

@ -72,6 +72,7 @@
<Property name="PROP_LST_RAMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_ROMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_RemoveDupRegs" value="True" time="0"/>
<Property name="PROP_LST_ReportTrimmedUserNets" value="False" time="0"/>
<Property name="PROP_LST_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_LST_ResourceShare" value="True" time="0"/>
<Property name="PROP_LST_UseIOReg" value="Auto" time="0"/>

View File

@ -1,24 +0,0 @@
FEATURE LSC_BASE lattice 8.0 11-feb-2024 uncounted 1303CFE67866 \
VENDOR_STRING="ispLEVER BASE" HOSTID=f81234567890
FEATURE LSC_SYNPLIFY lattice 8.0 11-feb-2024 uncounted B52A4FF71CC8 \
VENDOR_STRING="ispLEVER System with Synplicity" \
HOSTID=f81234567890
FEATURE LSC_SYNPLIFYPRO1 lattice 10.0 11-feb-2024 uncounted \
30EA214E8213 VENDOR_STRING="ispLEVER System with Synplicity \
Pro 1" HOSTID=f81234567890
FEATURE LSC_ADVANCED_DSP lattice 10.0 11-feb-2024 uncounted \
1BFB494C1D0D VENDOR_STRING="ispLEVER DSP" HOSTID=f81234567890
FEATURE LSC_DIAMOND_A lattice 10.0 11-feb-2024 uncounted 1067C09C10BA \
VENDOR_STRING="Diamond Free" HOSTID=f81234567890
FEATURE LSC_PROGRAMMER_MATURE lattice 10.0 11-feb-2024 uncounted \
4559F34D65AB VENDOR_STRING=Programmer HOSTID=f81234567890
FEATURE LSC_ADVANCED_ORCA lattice 9.0 11-feb-2024 uncounted \
CC7BBC2A3A16 VENDOR_STRING="ispORCA System" \
HOSTID=f81234567890
INCREMENT latticemsim mgcld 2023.09 11-feb-2024 0 6FE612FBCA60340B3076 \
VENDOR_STRING=672C91AB HOSTID=f81234567890 ISSUER="ModelSIM Lattice" \
SN=284862648 SIGN2="1E93 D015 CA8E 6012 81DA 3394 F0EA 3C2F 5482 24AB \
F903 2C13 A952 2697 2AF4 0819 2FA9 8CE8 CC9B 329B F71E C11F C29E A733 \
3D18 B2C3 7983 70EA 2885 F23E"

View File

@ -72,6 +72,7 @@
<Property name="PROP_LST_RAMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_ROMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_RemoveDupRegs" value="True" time="0"/>
<Property name="PROP_LST_ReportTrimmedUserNets" value="False" time="0"/>
<Property name="PROP_LST_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_LST_ResourceShare" value="True" time="0"/>
<Property name="PROP_LST_UseIOReg" value="Auto" time="0"/>
@ -93,12 +94,12 @@
<Property name="PROP_MAP_MapModArgs" value="" time="0"/>
<Property name="PROP_MAP_OvermapDevice" value="False" time="0"/>
<Property name="PROP_MAP_PackLogMapDes" value="" time="0"/>
<Property name="PROP_MAP_RegRetiming" value="False" time="0"/>
<Property name="PROP_MAP_RegRetiming" value="True" time="0"/>
<Property name="PROP_MAP_SigCrossRef" value="False" time="0"/>
<Property name="PROP_MAP_SymCrossRef" value="False" time="0"/>
<Property name="PROP_MAP_TimingDriven" value="False" time="0"/>
<Property name="PROP_MAP_TimingDriven" value="True" time="0"/>
<Property name="PROP_MAP_TimingDrivenNodeRep" value="False" time="0"/>
<Property name="PROP_MAP_TimingDrivenPack" value="False" time="0"/>
<Property name="PROP_MAP_TimingDrivenPack" value="True" time="0"/>
<Property name="PROP_PARSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
<Property name="PROP_PARSTA_AutoTiming" value="True" time="0"/>
<Property name="PROP_PARSTA_CheckUnconstrainedConns" value="False" time="0"/>
@ -117,15 +118,15 @@
<Property name="PROP_PAR_NewRouteParDes" value="NBR" time="0"/>
<Property name="PROP_PAR_PARClockSkew" value="Off" time="0"/>
<Property name="PROP_PAR_PARModArgs" value="" time="0"/>
<Property name="PROP_PAR_ParMultiNodeList" value="" time="0"/>
<Property name="PROP_PAR_ParMultiNodeList" value="multicore.txt" time="0"/>
<Property name="PROP_PAR_ParRunPlaceOnly" value="False" time="0"/>
<Property name="PROP_PAR_PlcIterParDes" value="10" time="0"/>
<Property name="PROP_PAR_PlcIterParDes" value="32" time="0"/>
<Property name="PROP_PAR_PlcStCostTblParDes" value="1" time="0"/>
<Property name="PROP_PAR_PrefErrorOut" value="True" time="0"/>
<Property name="PROP_PAR_RemoveDir" value="True" time="0"/>
<Property name="PROP_PAR_RouteDlyRedParDes" value="0" time="0"/>
<Property name="PROP_PAR_RoutePassParDes" value="10" time="0"/>
<Property name="PROP_PAR_RouteResOptParDes" value="0" time="0"/>
<Property name="PROP_PAR_RouteDlyRedParDes" value="10" time="0"/>
<Property name="PROP_PAR_RoutePassParDes" value="100" time="0"/>
<Property name="PROP_PAR_RouteResOptParDes" value="6" time="0"/>
<Property name="PROP_PAR_RoutingCDP" value="1" time="0"/>
<Property name="PROP_PAR_RoutingCDR" value="1" time="0"/>
<Property name="PROP_PAR_RunParWithTrce" value="False" time="0"/>
@ -172,15 +173,15 @@
<Property name="PROP_SYN_EdfArrangeVHDLFiles" value="True" time="0"/>
<Property name="PROP_SYN_EdfDefEnumEncode" value="Default" time="0"/>
<Property name="PROP_SYN_EdfFanout" value="1000" time="0"/>
<Property name="PROP_SYN_EdfFrequency" value="110" time="0"/>
<Property name="PROP_SYN_EdfFrequency" value="100" time="0"/>
<Property name="PROP_SYN_EdfGSR" value="False" time="0"/>
<Property name="PROP_SYN_EdfInsertIO" value="False" time="0"/>
<Property name="PROP_SYN_EdfNumCritPath" value="" time="0"/>
<Property name="PROP_SYN_EdfNumStartEnd" value="" time="0"/>
<Property name="PROP_SYN_EdfOutNetForm" value="None" time="0"/>
<Property name="PROP_SYN_EdfPushTirstates" value="True" time="0"/>
<Property name="PROP_SYN_EdfResSharing" value="True" time="0"/>
<Property name="PROP_SYN_EdfRunRetiming" value="Pipelining Only" time="0"/>
<Property name="PROP_SYN_EdfResSharing" value="False" time="0"/>
<Property name="PROP_SYN_EdfRunRetiming" value="Pipelining and Retiming" time="0"/>
<Property name="PROP_SYN_EdfSymFSM" value="True" time="0"/>
<Property name="PROP_SYN_EdfUnconsClk" value="False" time="0"/>
<Property name="PROP_SYN_EdfVerilogInput" value="Verilog 2001" time="0"/>

View File

@ -3,9 +3,21 @@
<Options/>
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="synplify" default_strategy="release">
<Options VerilogStandard="System Verilog" def_top="top" top="top"/>
<Source name="../../rtl/memory/dma_scb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/memory/mem_bus.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_scb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/sd/sd_scb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/usb/usb_scb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/fifo/fifo_bus.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
@ -33,9 +45,15 @@
<Source name="../../rtl/memory/memory_sdram.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_reg_bus.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_cfg.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_cic.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_dd.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
@ -48,15 +66,9 @@
<Source name="../../rtl/n64/n64_pi_fifo.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_reg_bus.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_save_counter.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_scb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_si.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
@ -78,9 +90,6 @@
<Source name="../../rtl/sd/sd_dat.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/sd/sd_scb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/sd/sd_top.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
@ -108,6 +117,54 @@
<Source name="../../rtl/vendor/lcmxo2/generated/pll_lattice_generated.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_aligner.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_alu.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_bufreg.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_bufreg2.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_compdec.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_csr.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_ctrl.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_decode.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_immdec.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_mem_if.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_rf_if.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_rf_ram.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_rf_ram_if.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_rf_top.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_state.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/serv/serv_top.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="../../rtl/top.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog" top_module="top"/>
</Source>

View File

@ -21,8 +21,10 @@ IOBUF PORT "inclk" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "mcu_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "mcu_cs" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "mcu_int" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "mcu_miso" IO_TYPE=LVCMOS33 PULLMODE=NONE ;
IOBUF PORT "mcu_mosi" IO_TYPE=LVCMOS33 PULLMODE=NONE ;
IOBUF PORT "mcu_miso" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "mcu_mosi" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_cic_clk" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_cic_dq" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_irq" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_nmi" PULLMODE=DOWN IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_pi_ad[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
@ -48,6 +50,7 @@ IOBUF PORT "n64_pi_write" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_reset" PULLMODE=DOWN IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_si_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_si_dq" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "n64_video_sync" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "sd_dat[0]" PULLMODE=UP IO_TYPE=LVCMOS33 ;
@ -93,6 +96,9 @@ IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "sdram_ras" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "sdram_we" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "test_point[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "test_point[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "test_point[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "usb_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "usb_cs" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "usb_miosi[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
@ -120,6 +126,8 @@ LOCATE COMP "mcu_miso" SITE "119" ;
LOCATE COMP "mcu_mosi" SITE "120" ;
LOCATE COMP "n64_irq" SITE "32" ;
LOCATE COMP "n64_nmi" SITE "28" ;
LOCATE COMP "n64_cic_clk" SITE "34" ;
LOCATE COMP "n64_cic_dq" SITE "35" ;
LOCATE COMP "n64_pi_ad[0]" SITE "60" ;
LOCATE COMP "n64_pi_ad[1]" SITE "58" ;
LOCATE COMP "n64_pi_ad[10]" SITE "42" ;
@ -143,6 +151,7 @@ LOCATE COMP "n64_pi_write" SITE "49" ;
LOCATE COMP "n64_reset" SITE "31" ;
LOCATE COMP "n64_si_clk" SITE "33" ;
LOCATE COMP "n64_si_dq" SITE "27" ;
LOCATE COMP "n64_video_sync" SITE "26" ;
LOCATE COMP "sd_clk" SITE "111" ;
LOCATE COMP "sd_cmd" SITE "112" ;
LOCATE COMP "sd_dat[0]" SITE "110" ;
@ -188,6 +197,9 @@ LOCATE COMP "sdram_dqm[0]" SITE "97" ;
LOCATE COMP "sdram_dqm[1]" SITE "73" ;
LOCATE COMP "sdram_ras" SITE "94" ;
LOCATE COMP "sdram_we" SITE "96" ;
LOCATE COMP "test_point[0]" SITE "23" ;
LOCATE COMP "test_point[1]" SITE "24" ;
LOCATE COMP "test_point[2]" SITE "25" ;
LOCATE COMP "usb_clk" SITE "12" ;
LOCATE COMP "usb_cs" SITE "11" ;
LOCATE COMP "usb_miosi[0]" SITE "22" ;
@ -202,8 +214,48 @@ LOCATE COMP "usb_miso" SITE "10" ;
LOCATE COMP "usb_pwrsav" SITE "2" ;
SYSCONFIG SDM_PORT=DISABLE I2C_PORT=ENABLE ;
VOLTAGE 3.300 V;
FREQUENCY NET "clk" 100.000000 MHz PAR_ADJ 10.000000 ;
FREQUENCY NET "clk" 100.000000 MHz ;
BLOCK PATH TO PORT "mcu_int" ;
BLOCK PATH TO PORT "n64_irq" ;
BLOCK PATH FROM PORT "usb_pwrsav" ;
BLOCK PATH FROM PORT "sd_det" ;
DEFINE PORT GROUP "sdram_output" "sdram_cs"
"sdram_ras"
"sdram_cas"
"sdram_we"
"sdram_ba[1]"
"sdram_ba[0]"
"sdram_a[12]"
"sdram_a[11]"
"sdram_a[10]"
"sdram_a[9]"
"sdram_a[8]"
"sdram_a[7]"
"sdram_a[6]"
"sdram_a[5]"
"sdram_a[4]"
"sdram_a[3]"
"sdram_a[2]"
"sdram_a[1]"
"sdram_a[0]"
"sdram_dqm[1]"
"sdram_dqm[0]" ;
DEFINE PORT GROUP "sdram_bidir" "sdram_dq[15]"
"sdram_dq[14]"
"sdram_dq[13]"
"sdram_dq[12]"
"sdram_dq[11]"
"sdram_dq[10]"
"sdram_dq[9]"
"sdram_dq[8]"
"sdram_dq[7]"
"sdram_dq[6]"
"sdram_dq[5]"
"sdram_dq[4]"
"sdram_dq[3]"
"sdram_dq[2]"
"sdram_dq[1]"
"sdram_dq[0]" ;
INPUT_SETUP GROUP "sdram_bidir"INPUT_DELAY 5.400000 ns HOLD -2.500000 ns CLKNET "clk" CLK_OFFSET -0.250000 X ;
CLOCK_TO_OUT GROUP "sdram_output" OUTPUT_DELAY 1.500000 ns MIN 0.800000 ns CLKNET "clk" CLKOUT PORT "sdram_clk" ;
CLOCK_TO_OUT GROUP "sdram_bidir" OUTPUT_DELAY 1.500000 ns MIN 0.800000 ns CLKNET "clk" CLKOUT PORT "sdram_clk" ;

View File

@ -1,35 +1,29 @@
interface fifo_bus ();
logic rx_empty;
logic rx_almost_empty;
logic rx_read;
logic [7:0] rx_rdata;
logic tx_full;
logic tx_almost_full;
logic tx_write;
logic [7:0] tx_wdata;
modport controller (
input rx_empty,
input rx_almost_empty,
output rx_read,
input rx_rdata,
input tx_full,
input tx_almost_full,
output tx_write,
output tx_wdata
);
modport fifo (
output rx_empty,
output rx_almost_empty,
input rx_read,
output rx_rdata,
output tx_full,
output tx_almost_full,
input tx_write,
input tx_wdata
);

View File

@ -11,16 +11,12 @@ module fifo_junction (
dev_bus.tx_wdata = cfg_bus.tx_write ? cfg_bus.tx_wdata : dma_bus.tx_wdata;
cfg_bus.rx_empty = dev_bus.rx_empty;
cfg_bus.rx_almost_empty = dev_bus.rx_almost_empty;
cfg_bus.rx_rdata = dev_bus.rx_rdata;
cfg_bus.tx_full = dev_bus.tx_full;
cfg_bus.tx_almost_full = dev_bus.tx_almost_full;
dma_bus.rx_empty = dev_bus.rx_empty;
dma_bus.rx_almost_empty = dev_bus.rx_almost_empty;
dma_bus.rx_rdata = dev_bus.rx_rdata;
dma_bus.tx_full = dev_bus.tx_full;
dma_bus.tx_almost_full = dev_bus.tx_almost_full;
end
endmodule

View File

@ -358,15 +358,25 @@ module mcu_top (
REG_VENDOR_SCR,
REG_VENDOR_DATA,
REG_DEBUG_0,
REG_DEBUG_1
REG_DEBUG_1,
REG_CIC_0,
REG_CIC_1,
REG_AUX
} reg_address_e;
logic bootloader_skip;
assign n64_scb.cfg_identifier = 32'h53437632;
assign usb_dma_scb.byte_swap = 1'b0;
logic dd_bm_ack;
logic [31:0] debug_buffer;
logic cic_invalid_region;
logic aux_pending;
// Register read logic
@ -389,13 +399,13 @@ module mcu_top (
REG_USB_SCR: begin
reg_rdata <= {
2'd0,
1'd0,
usb_scb.fifo_flush_busy,
usb_scb.pwrsav,
usb_scb.reset_state,
usb_scb.tx_count,
usb_scb.rx_count,
2'b00,
usb_scb.reset_pending,
3'b000,
~fifo_bus.tx_full,
~fifo_bus.rx_empty,
1'b0
@ -454,7 +464,9 @@ module mcu_top (
REG_CFG_CMD: begin
reg_rdata <= {
23'd0,
19'd0,
aux_pending,
3'd0,
n64_scb.cfg_pending,
n64_scb.cfg_cmd
};
@ -469,7 +481,7 @@ module mcu_top (
18'd0,
n64_scb.flashram_write_or_erase,
n64_scb.flashram_sector_or_all,
n64_scb.flashram_sector,
n64_scb.flashram_page,
n64_scb.flashram_pending,
1'b0
};
@ -501,7 +513,7 @@ module mcu_top (
REG_RTC_TIME_1: begin
reg_rdata <= {
8'd0,
7'd0, n64_scb.rtc_rdata[42],
n64_scb.rtc_rdata[41:34],
3'd0, n64_scb.rtc_rdata[33:29],
2'd0, n64_scb.rtc_rdata[25:20]
@ -577,7 +589,8 @@ module mcu_top (
REG_SD_DMA_SCR: begin
reg_rdata <= {
28'd0,
27'd0,
sd_dma_scb.byte_swap,
sd_dma_scb.busy,
sd_dma_scb.direction,
2'b00
@ -638,15 +651,39 @@ module mcu_top (
end
REG_DEBUG_0: begin
reg_rdata <= n64_scb.pi_debug[31:0];
reg_rdata <= n64_scb.pi_debug_address;
debug_buffer <= {
6'd0,
n64_scb.pi_debug_direction,
n64_scb.pi_debug_rw_count,
n64_scb.cic_debug_step,
n64_scb.pi_debug_fifo_flags
};
end
REG_DEBUG_1: begin
reg_rdata <= debug_buffer;
end
REG_CIC_0: begin
reg_rdata <= {
28'd0,
n64_scb.pi_debug[35:32]
4'd0,
cic_invalid_region,
n64_scb.cic_disabled,
n64_scb.cic_64dd_mode,
n64_scb.cic_region,
n64_scb.cic_seed,
n64_scb.cic_checksum[47:32]
};
end
REG_CIC_1: begin
reg_rdata <= n64_scb.cic_checksum[31:0];
end
REG_AUX: begin
reg_rdata <= n64_scb.aux_rdata;
end
endcase
end
end
@ -658,9 +695,10 @@ module mcu_top (
mem_start <= 1'b0;
mem_stop <= 1'b0;
usb_scb.write_buffer_flush <= 1'b0;
usb_scb.reset_ack <= 1'b0;
usb_scb.fifo_flush <= 1'b0;
usb_scb.write_buffer_flush <= 1'b0;
usb_scb.reset_on_ack <= 1'b0;
usb_scb.reset_off_ack <= 1'b0;
usb_dma_scb.start <= 1'b0;
usb_dma_scb.stop <= 1'b0;
@ -676,7 +714,10 @@ module mcu_top (
n64_scb.cfg_done <= 1'b0;
n64_scb.cfg_error <= 1'b0;
n64_scb.cfg_irq <= 1'b0;
n64_scb.btn_irq <= 1'b0;
n64_scb.usb_irq <= 1'b0;
n64_scb.aux_irq <= 1'b0;
n64_scb.flashram_done <= 1'b0;
@ -703,6 +744,14 @@ module mcu_top (
dd_bm_ack <= 1'b1;
end
if (n64_scb.cic_invalid_region) begin
cic_invalid_region <= 1'b1;
end
if (n64_scb.aux_pending) begin
aux_pending <= 1'b1;
end
if (reset) begin
mcu_int <= 1'b0;
sd_scb.clock_mode <= 2'd0;
@ -721,6 +770,13 @@ module mcu_top (
flash_scb.erase_pending <= 1'b0;
dd_bm_ack <= 1'b0;
n64_scb.rtc_wdata_valid <= 1'b0;
cic_invalid_region <= 1'b0;
n64_scb.cic_disabled <= 1'b0;
n64_scb.cic_64dd_mode <= 1'b0;
n64_scb.cic_region <= 1'b0;
n64_scb.cic_seed <= 8'h3F;
n64_scb.cic_checksum <= 48'hA536C0F1D859;
aux_pending <= 1'b0;
end else if (reg_write) begin
case (address)
REG_MEM_ADDRESS: begin
@ -737,11 +793,11 @@ module mcu_top (
end
REG_USB_SCR: begin
{
usb_scb.write_buffer_flush,
usb_scb.reset_ack,
usb_scb.fifo_flush
} <= {reg_wdata[5:4], reg_wdata[0]};
n64_scb.usb_irq <= reg_wdata[31];
usb_scb.write_buffer_flush <= reg_wdata[5];
usb_scb.reset_off_ack <= reg_wdata[4];
usb_scb.reset_on_ack <= reg_wdata[3];
usb_scb.fifo_flush <= reg_wdata[0];
end
REG_USB_DMA_ADDRESS: begin
@ -787,10 +843,13 @@ module mcu_top (
REG_CFG_CMD: begin
{
n64_scb.cfg_irq,
n64_scb.btn_irq,
n64_scb.cfg_error,
n64_scb.cfg_done
} <= reg_wdata[11:9];
if (reg_wdata[13]) begin
aux_pending <= 1'b0;
end
end
REG_FLASHRAM_SCR: begin
@ -816,6 +875,7 @@ module mcu_top (
REG_RTC_TIME_1: begin
n64_scb.rtc_wdata_valid <= 1'b1;
n64_scb.rtc_wdata[42] <= reg_wdata[24];
n64_scb.rtc_wdata[41:34] <= reg_wdata[23:16];
n64_scb.rtc_wdata[33:29] <= reg_wdata[12:8];
n64_scb.rtc_wdata[25:20] <= reg_wdata[5:0];
@ -855,11 +915,10 @@ module mcu_top (
end
REG_SD_DMA_SCR: begin
{
sd_dma_scb.direction,
sd_dma_scb.stop,
sd_dma_scb.start
} <= reg_wdata[2:0];
sd_dma_scb.byte_swap <= reg_wdata[4];
sd_dma_scb.direction <= reg_wdata[2];
sd_dma_scb.stop <= reg_wdata[1];
sd_dma_scb.start <= reg_wdata[0];
end
REG_DD_SCR: begin
@ -899,6 +958,26 @@ module mcu_top (
REG_VENDOR_DATA: begin
vendor_scb.data_wdata <= reg_wdata;
end
REG_CIC_0: begin
if (reg_wdata[28]) begin
cic_invalid_region <= 1'b0;
end
n64_scb.cic_disabled <= reg_wdata[26];
n64_scb.cic_64dd_mode <= reg_wdata[25];
n64_scb.cic_region <= reg_wdata[24];
n64_scb.cic_seed <= reg_wdata[23:16];
n64_scb.cic_checksum[47:32] <= reg_wdata[15:0];
end
REG_CIC_1: begin
n64_scb.cic_checksum[31:0] <= reg_wdata;
end
REG_AUX: begin
n64_scb.aux_irq <= 1'b1;
n64_scb.aux_wdata <= reg_wdata;
end
endcase
end
end

31
fw/rtl/memory/dma_scb.sv Normal file
View File

@ -0,0 +1,31 @@
interface dma_scb ();
logic start;
logic stop;
logic busy;
logic direction;
logic byte_swap;
logic [26:0] starting_address;
logic [26:0] transfer_length;
modport controller (
output start,
output stop,
input busy,
output direction,
output byte_swap,
output starting_address,
output transfer_length
);
modport dma (
input start,
input stop,
output busy,
input direction,
input byte_swap,
input starting_address,
input transfer_length
);
endinterface

View File

@ -36,11 +36,11 @@ module memory_bram (
eeprom_selected = 1'b0;
dd_selected = 1'b0;
flashram_selected = 1'b0;
if (mem_bus.address[25:24] == 2'b01 && mem_bus.address[23:14] == 10'd0) begin
buffer_selected = mem_bus.address[13] == 1'b0;
eeprom_selected = mem_bus.address[13:11] == 3'b100;
dd_selected = mem_bus.address[13:8] == 6'b101000;
flashram_selected = mem_bus.address[13:7] == 7'b1010010;
if (mem_bus.address[26:24] == 3'h5) begin
buffer_selected = (mem_bus.address[23:0] >= 24'h00_0000 && mem_bus.address[23:0] < 24'h00_2000);
eeprom_selected = (mem_bus.address[23:0] >= 24'h00_2000 && mem_bus.address[23:0] < 24'h00_2800);
dd_selected = (mem_bus.address[23:0] >= 24'h00_2800 && mem_bus.address[23:0] < 24'h00_2C00);
flashram_selected = (mem_bus.address[23:0] >= 24'h00_2C00 && mem_bus.address[23:0] < 24'h00_2C80);
end
end
@ -112,26 +112,26 @@ module memory_bram (
end
// DD memory
// 64DD/MCU buffer memory
logic [15:0] dd_bram [0:127];
logic [15:0] dd_bram [0:511];
logic [15:0] dd_bram_rdata;
always_ff @(posedge clk) begin
if (write && dd_selected) begin
dd_bram[mem_bus.address[7:1]] <= mem_bus.wdata;
dd_bram[mem_bus.address[9:1]] <= mem_bus.wdata;
end
if (n64_scb.dd_write) begin
dd_bram[n64_scb.dd_address] <= n64_scb.dd_wdata;
dd_bram[{2'b00, n64_scb.dd_address}] <= n64_scb.dd_wdata;
end
end
always_ff @(posedge clk) begin
dd_bram_rdata <= dd_bram[mem_bus.address[7:1]];
dd_bram_rdata <= dd_bram[mem_bus.address[9:1]];
end
always_ff @(posedge clk) begin
n64_scb.dd_rdata <= dd_bram[n64_scb.dd_address];
n64_scb.dd_rdata <= dd_bram[{2'b00, n64_scb.dd_address}];
end

View File

@ -1,33 +1,3 @@
interface dma_scb ();
logic start;
logic stop;
logic busy;
logic direction;
logic [26:0] starting_address;
logic [26:0] transfer_length;
modport controller (
output start,
output stop,
input busy,
output direction,
output starting_address,
output transfer_length
);
modport dma (
input start,
input stop,
output busy,
input direction,
input starting_address,
input transfer_length
);
endinterface
module memory_dma (
input clk,
input reset,
@ -38,206 +8,382 @@ module memory_dma (
mem_bus.controller mem_bus
);
// DMA start/stop control
// Start/stop logic
logic dma_start;
logic dma_stop;
always_comb begin
dma_start = dma_scb.start && !dma_scb.stop && !dma_scb.busy;
dma_stop = dma_scb.stop;
always_ff @(posedge clk) begin
dma_start <= 1'b0;
if (dma_scb.stop) begin
dma_stop <= 1'b1;
end else if (dma_scb.start) begin
dma_start <= 1'b1;
dma_stop <= 1'b0;
end
end
// Remaining counter and FIFO enable
// Memory bus controller
logic [26:0] remaining;
logic trx_enabled;
typedef enum bit [1:0] {
MEM_BUS_STATE_IDLE,
MEM_BUS_STATE_WAIT,
MEM_BUS_STATE_TRANSFER
} e_mem_bus_state;
e_mem_bus_state mem_bus_state;
e_mem_bus_state next_mem_bus_state;
logic mem_bus_wdata_ready;
logic mem_bus_wdata_empty;
logic mem_bus_wdata_end;
logic [1:0] mem_bus_wdata_valid;
logic [15:0] mem_bus_wdata_buffer;
logic mem_bus_rdata_ready;
logic mem_bus_rdata_ack;
logic mem_bus_rdata_end;
logic [1:0] mem_bus_rdata_valid;
logic [15:0] mem_bus_rdata_buffer;
logic [26:0] mem_bus_remaining_bytes;
logic mem_bus_last_transfer;
logic mem_bus_almost_last_transfer;
logic mem_bus_unaligned_start;
logic mem_bus_unaligned_end;
always_ff @(posedge clk) begin
if (reset) begin
mem_bus_state <= MEM_BUS_STATE_IDLE;
end else begin
mem_bus_state <= next_mem_bus_state;
end
end
always_comb begin
trx_enabled = remaining > 27'd0;
next_mem_bus_state = mem_bus_state;
mem_bus_last_transfer = (mem_bus_remaining_bytes == 27'd0);
mem_bus_almost_last_transfer = (mem_bus_remaining_bytes <= 27'd2);
mem_bus_wdata_end = mem_bus_last_transfer;
mem_bus_wdata_valid = (mem_bus_unaligned_end && mem_bus_almost_last_transfer) ? 2'b10 :
mem_bus_unaligned_start ? 2'b01 :
2'b11;
case (mem_bus_state)
MEM_BUS_STATE_IDLE: begin
if (dma_start) begin
next_mem_bus_state = MEM_BUS_STATE_WAIT;
end
end
MEM_BUS_STATE_WAIT: begin
if (dma_stop || mem_bus_last_transfer) begin
next_mem_bus_state = MEM_BUS_STATE_IDLE;
end else if (mem_bus_wdata_ready || !mem_bus_wdata_empty || mem_bus_rdata_ready) begin
next_mem_bus_state = MEM_BUS_STATE_TRANSFER;
end
end
MEM_BUS_STATE_TRANSFER: begin
if (mem_bus.ack) begin
if (dma_stop || mem_bus_last_transfer) begin
next_mem_bus_state = MEM_BUS_STATE_IDLE;
end else if (!(mem_bus_wdata_ready || !mem_bus_wdata_empty || mem_bus_rdata_ready)) begin
next_mem_bus_state = MEM_BUS_STATE_WAIT;
end
end
end
default: begin
next_mem_bus_state = MEM_BUS_STATE_IDLE;
end
endcase
end
always_ff @(posedge clk) begin
mem_bus_rdata_ack <= 1'b0;
if (mem_bus.ack) begin
mem_bus.request <= 1'b0;
mem_bus.address <= (mem_bus.address + 26'd2);
mem_bus_rdata_ack <= 1'b1;
mem_bus_rdata_end <= mem_bus_last_transfer;
mem_bus_rdata_valid <= mem_bus.wmask;
mem_bus_rdata_buffer <= mem_bus.rdata;
end
if (mem_bus_wdata_ready) begin
mem_bus_wdata_empty <= 1'b0;
end
case (mem_bus_state)
MEM_BUS_STATE_IDLE: begin
mem_bus.request <= 1'b0;
mem_bus_rdata_end <= 1'b1;
if (dma_start) begin
mem_bus.write <= dma_scb.direction;
mem_bus.address <= {dma_scb.starting_address[26:1], 1'b0};
mem_bus_remaining_bytes <= dma_scb.transfer_length;
mem_bus_unaligned_start <= dma_scb.starting_address[0];
mem_bus_unaligned_end <= (dma_scb.starting_address[0] ^ dma_scb.transfer_length[0]);
mem_bus_rdata_end <= 1'b0;
mem_bus_wdata_empty <= 1'b1;
end
end
MEM_BUS_STATE_WAIT: begin
if (!dma_stop && !mem_bus_last_transfer) begin
if (mem_bus_wdata_ready || !mem_bus_wdata_empty || mem_bus_rdata_ready) begin
mem_bus.request <= 1'b1;
mem_bus_unaligned_start <= 1'b0;
mem_bus.wdata <= (dma_scb.byte_swap ? {mem_bus_wdata_buffer[7:0], mem_bus_wdata_buffer[15:8]} : mem_bus_wdata_buffer);
mem_bus.wmask <= 2'b11;
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd2);
if (mem_bus_unaligned_end && mem_bus_almost_last_transfer) begin
mem_bus.wmask <= 2'b10;
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd1);
end
if (mem_bus_unaligned_start) begin
mem_bus.wmask <= 2'b01;
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd1);
end
mem_bus_wdata_empty <= 1'b1;
end
end
end
MEM_BUS_STATE_TRANSFER: begin
if (!dma_stop && !mem_bus_last_transfer) begin
if (mem_bus.ack && (mem_bus_wdata_ready || !mem_bus_wdata_empty || mem_bus_rdata_ready)) begin
mem_bus.request <= 1'b1;
mem_bus.wdata <= (dma_scb.byte_swap ? {mem_bus_wdata_buffer[7:0], mem_bus_wdata_buffer[15:8]} : mem_bus_wdata_buffer);
mem_bus.wmask <= 2'b11;
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd2);
if (mem_bus_unaligned_end && mem_bus_almost_last_transfer) begin
mem_bus.wmask <= 2'b10;
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd1);
end
mem_bus_wdata_empty <= 1'b1;
end
end
end
default: begin end
endcase
end
// RX FIFO controller
logic rx_rdata_pop;
logic rx_rdata_shift;
logic rx_rdata_valid;
logic [15:0] rx_buffer;
logic rx_buffer_valid;
logic [1:0] rx_buffer_counter;
logic [1:0] rx_buffer_valid_counter;
typedef enum bit [1:0] {
RX_FIFO_BUS_STATE_IDLE,
RX_FIFO_BUS_STATE_TRANSFER_1,
RX_FIFO_BUS_STATE_TRANSFER_2,
RX_FIFO_BUS_STATE_ACK
} e_rx_fifo_bus_state;
e_rx_fifo_bus_state rx_fifo_bus_state;
e_rx_fifo_bus_state next_rx_fifo_bus_state;
logic rx_fifo_shift;
logic rx_fifo_shift_delayed;
always_ff @(posedge clk) begin
if (reset || dma_stop) begin
rx_fifo_bus_state <= RX_FIFO_BUS_STATE_IDLE;
end else begin
rx_fifo_bus_state <= next_rx_fifo_bus_state;
end
end
always_comb begin
rx_buffer_valid = rx_buffer_valid_counter == 2'd2;
next_rx_fifo_bus_state = rx_fifo_bus_state;
rx_fifo_shift = 1'b0;
fifo_bus.rx_read = 1'b0;
case (rx_fifo_bus_state)
RX_FIFO_BUS_STATE_IDLE: begin
if (dma_start && dma_scb.direction) begin
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_TRANSFER_1;
end
end
RX_FIFO_BUS_STATE_TRANSFER_1: begin
fifo_bus.rx_read = (!fifo_bus.rx_empty && mem_bus_wdata_empty && mem_bus_wdata_valid[1] && !mem_bus_wdata_end);
if ((!fifo_bus.rx_empty && mem_bus_wdata_empty) || !mem_bus_wdata_valid[1]) begin
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_TRANSFER_2;
rx_fifo_shift = 1'b1;
end
if (mem_bus_wdata_end) begin
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_IDLE;
end
end
RX_FIFO_BUS_STATE_TRANSFER_2: begin
fifo_bus.rx_read = (!fifo_bus.rx_empty && mem_bus_wdata_valid[0]);
if (!fifo_bus.rx_empty || !mem_bus_wdata_valid[0]) begin
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_ACK;
rx_fifo_shift = 1'b1;
end
end
RX_FIFO_BUS_STATE_ACK: begin
if (mem_bus_wdata_ready) begin
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_TRANSFER_1;
end
end
default: begin
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_IDLE;
end
endcase
end
always_ff @(posedge clk) begin
rx_rdata_pop <= (
!rx_rdata_pop &&
!fifo_bus.rx_read &&
trx_enabled &&
rx_buffer_counter < 2'd2 &&
!fifo_bus.rx_empty &&
mem_bus.write
);
rx_rdata_shift <= 1'b0;
fifo_bus.rx_read <= rx_rdata_pop;
rx_rdata_valid <= fifo_bus.rx_read;
mem_bus_wdata_ready <= 1'b0;
rx_fifo_shift_delayed <= rx_fifo_shift;
if (dma_start) begin
if (dma_scb.starting_address[0]) begin
mem_bus.wmask <= 2'b01;
rx_buffer_counter <= 2'd1;
rx_buffer_valid_counter <= 2'd1;
end else begin
mem_bus.wmask <= 2'b11;
rx_buffer_counter <= 2'd0;
rx_buffer_valid_counter <= 2'd0;
if (rx_fifo_shift_delayed) begin
if (rx_fifo_bus_state == RX_FIFO_BUS_STATE_ACK) begin
mem_bus_wdata_ready <= 1'b1;
end
end
if (rx_rdata_pop) begin
rx_buffer_counter <= rx_buffer_counter + 1'd1;
end
if (rx_rdata_shift || rx_rdata_valid) begin
rx_buffer <= {rx_buffer[7:0], fifo_bus.rx_rdata};
rx_buffer_valid_counter <= rx_buffer_valid_counter + 1'd1;
if (remaining == 27'd0 && rx_buffer_counter == 2'd1) begin
mem_bus.wmask <= 2'b10;
rx_rdata_shift <= 1'b1;
rx_buffer_counter <= rx_buffer_counter + 1'd1;
end
end
if (rx_buffer_valid && !mem_bus.request) begin
rx_buffer_counter <= 2'd0;
rx_buffer_valid_counter <= 2'd0;
mem_bus_wdata_buffer <= {mem_bus_wdata_buffer[7:0], fifo_bus.rx_rdata};
end
end
// TX FIFO controller
logic tx_wdata_push;
logic tx_wdata_first_push;
logic [7:0] tx_buffer;
logic tx_buffer_counter;
logic tx_buffer_ready;
logic tx_buffer_valid;
typedef enum bit [1:0] {
TX_FIFO_BUS_STATE_IDLE,
TX_FIFO_BUS_STATE_WAIT,
TX_FIFO_BUS_STATE_TRANSFER_1,
TX_FIFO_BUS_STATE_TRANSFER_2
} e_tx_fifo_bus_state;
e_tx_fifo_bus_state tx_fifo_bus_state;
e_tx_fifo_bus_state next_tx_fifo_bus_state;
logic tx_fifo_shift;
logic tx_fifo_waiting;
logic [1:0] tx_fifo_valid;
logic [15:0] tx_fifo_buffer;
always_ff @(posedge clk) begin
if (reset || dma_stop) begin
tx_fifo_bus_state <= TX_FIFO_BUS_STATE_IDLE;
end else begin
tx_fifo_bus_state <= next_tx_fifo_bus_state;
end
end
always_comb begin
fifo_bus.tx_write = tx_wdata_push;
end
next_tx_fifo_bus_state = tx_fifo_bus_state;
always_ff @(posedge clk) begin
tx_wdata_push <= (
!tx_wdata_push &&
trx_enabled &&
tx_buffer_valid &&
!fifo_bus.tx_full &&
!mem_bus.write
);
tx_fifo_shift = 1'b0;
if (reset || dma_stop) begin
tx_buffer_ready <= 1'b0;
tx_buffer_valid <= 1'b0;
end
fifo_bus.tx_write = 1'b0;
fifo_bus.tx_wdata = tx_fifo_buffer[15:8];
if (dma_start) begin
tx_wdata_first_push <= 1'b1;
tx_buffer_ready <= 1'b1;
tx_buffer_valid <= 1'b0;
end
if (tx_buffer_ready && mem_bus.request) begin
tx_buffer_ready <= 1'b0;
end
if (mem_bus.ack) begin
tx_wdata_first_push <= 1'b0;
tx_buffer_counter <= 1'd1;
tx_buffer_valid <= 1'b1;
{fifo_bus.tx_wdata, tx_buffer} <= mem_bus.rdata;
if (tx_wdata_first_push && dma_scb.starting_address[0]) begin
fifo_bus.tx_wdata <= mem_bus.rdata[7:0];
tx_buffer_counter <= 1'd0;
end
end
if (tx_wdata_push) begin
tx_buffer_counter <= tx_buffer_counter - 1'd1;
fifo_bus.tx_wdata <= tx_buffer;
if (tx_buffer_counter == 1'd0) begin
tx_buffer_ready <= 1'b1;
tx_buffer_valid <= 1'b0;
end
end
end
// Remaining counter controller
always_ff @(posedge clk) begin
if (reset || dma_stop) begin
remaining <= 27'd0;
end else begin
if (dma_start) begin
remaining <= dma_scb.transfer_length;
case (tx_fifo_bus_state)
TX_FIFO_BUS_STATE_IDLE: begin
if (dma_start && !dma_scb.direction) begin
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_WAIT;
end
end
if ((mem_bus.write && rx_rdata_pop) || (!mem_bus.write && tx_wdata_push)) begin
remaining <= remaining - 1'd1;
TX_FIFO_BUS_STATE_WAIT: begin
if (mem_bus_rdata_ack || tx_fifo_waiting) begin
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_TRANSFER_1;
end else if (mem_bus_rdata_end) begin
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_IDLE;
end
end
end
end
TX_FIFO_BUS_STATE_TRANSFER_1: begin
fifo_bus.tx_write = (!fifo_bus.tx_full && tx_fifo_valid[1]);
if (!fifo_bus.tx_full || !tx_fifo_valid[1]) begin
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_TRANSFER_2;
tx_fifo_shift = 1'b1;
end
end
// Mem bus controller
always_ff @(posedge clk) begin
dma_scb.busy <= mem_bus.request || trx_enabled;
end
always_ff @(posedge clk) begin
if (reset) begin
mem_bus.request <= 1'b0;
end else begin
if (!mem_bus.request) begin
if (mem_bus.write) begin
if (rx_buffer_valid) begin
mem_bus.request <= 1'b1;
mem_bus.wdata <= rx_buffer;
end
end else begin
if (tx_buffer_ready) begin
mem_bus.request <= 1'b1;
TX_FIFO_BUS_STATE_TRANSFER_2: begin
fifo_bus.tx_write = (!fifo_bus.tx_full && tx_fifo_valid[1]);
if (!fifo_bus.tx_full || !tx_fifo_valid[1]) begin
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_WAIT;
tx_fifo_shift = 1'b1;
if (!mem_bus_rdata_ack && !tx_fifo_waiting && mem_bus_rdata_end) begin
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_IDLE;
end
end
end
end
if (mem_bus.ack) begin
mem_bus.request <= 1'b0;
end
default: begin
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_IDLE;
end
endcase
end
always_ff @(posedge clk) begin
if (dma_start) begin
mem_bus.write <= dma_scb.direction;
if (tx_fifo_shift) begin
tx_fifo_valid <= {tx_fifo_valid[0], 1'bX};
tx_fifo_buffer <= {tx_fifo_buffer[7:0], 8'hXX};
end
case (tx_fifo_bus_state)
TX_FIFO_BUS_STATE_IDLE: begin
mem_bus_rdata_ready <= 1'b0;
tx_fifo_waiting <= 1'b0;
if (dma_start) begin
mem_bus_rdata_ready <= !dma_scb.direction;
end
end
TX_FIFO_BUS_STATE_WAIT: begin
if (mem_bus_rdata_ack || tx_fifo_waiting) begin
mem_bus_rdata_ready <= 1'b0;
tx_fifo_waiting <= 1'b0;
tx_fifo_valid <= mem_bus_rdata_valid;
tx_fifo_buffer <= mem_bus_rdata_buffer;
end
end
TX_FIFO_BUS_STATE_TRANSFER_1: begin
if (mem_bus_rdata_ack) begin
tx_fifo_waiting <= 1'b1;
end
end
TX_FIFO_BUS_STATE_TRANSFER_2: begin
if (mem_bus_rdata_ack) begin
tx_fifo_waiting <= 1'b1;
end
if (fifo_bus.tx_write || !tx_fifo_valid[1]) begin
mem_bus_rdata_ready <= !mem_bus_rdata_end;
end
end
default: begin end
endcase
end
always_ff @(posedge clk) begin
if (dma_start) begin
mem_bus.address <= {dma_scb.starting_address[26:1], 1'b0};
end
if (mem_bus.ack) begin
mem_bus.address <= mem_bus.address + 2'd2;
end
// DMA busy indicator
always_ff @(posedge clk) begin
dma_scb.busy <= (
(dma_scb.start && !dma_scb.stop) ||
dma_start ||
(mem_bus_state != MEM_BUS_STATE_IDLE) ||
(rx_fifo_bus_state != RX_FIFO_BUS_STATE_IDLE) ||
(tx_fifo_bus_state != TX_FIFO_BUS_STATE_IDLE)
);
end
endmodule

View File

@ -234,7 +234,7 @@ module memory_flash (
if (reset) begin
state <= STATE_IDLE;
end else begin
if (!busy && (start || finish)) begin
if ((start || finish) && !busy) begin
counter <= counter + 1'd1;
end
@ -248,6 +248,7 @@ module memory_flash (
end else if (mem_bus.request) begin
current_address <= {mem_bus.address[23:1], 1'b0};
if (mem_bus.write) begin
current_address[0] <= (~mem_bus.wmask[1]);
state <= STATE_WRITE_ENABLE;
end else begin
state <= STATE_READ_START;
@ -263,7 +264,7 @@ module memory_flash (
end
3'd1: begin
finish <= 1'b1;
wdata <= 8'd4;
wdata <= 8'd5;
if (!busy) begin
counter <= 3'd0;
if (flash_scb.erase_pending) begin
@ -296,7 +297,7 @@ module memory_flash (
end
3'd4: begin
finish <= 1'b1;
wdata <= 8'd4;
wdata <= 8'd5;
if (!busy) begin
flash_scb.erase_done <= 1'b1;
counter <= 3'd0;
@ -314,17 +315,17 @@ module memory_flash (
end
3'd1: begin
start <= 1'b1;
wdata <= mem_bus.address[23:16];
wdata <= current_address[23:16];
end
3'd2: begin
start <= 1'b1;
wdata <= mem_bus.address[15:8];
wdata <= current_address[15:8];
end
3'd3: begin
start <= 1'b1;
wdata <= mem_bus.address[7:0];
wdata <= current_address[7:0];
if (!busy) begin
counter <= 3'd0;
counter <= 3'd0 + current_address[0];
state <= STATE_PROGRAM;
end
end
@ -336,26 +337,33 @@ module memory_flash (
3'd0: begin
start <= 1'b1;
wdata <= mem_bus.wdata[15:8];
if (start && !busy) begin
current_address <= current_address + 1'd1;
if (!mem_bus.wmask[0]) begin
counter <= 3'd2;
mem_bus.ack <= 1'b1;
end
end
end
3'd1: begin
start <= 1'b1;
wdata <= mem_bus.wdata[7:0];
if (!busy) begin
mem_bus.ack <= 1'b1;
current_address <= current_address + 2'd2;
current_address <= current_address + 1'd1;
end
end
3'd2: begin
if (current_address[7:0] == 8'h00) begin
state <= STATE_PROGRAM_END;
end else if (flash_scb.erase_pending) begin
state <= STATE_PROGRAM_END;
end else if (mem_bus.request && !mem_bus.ack) begin
if (!mem_bus.write || (mem_bus.address[23:0] != current_address)) begin
state <= STATE_PROGRAM_END;
end else begin
if (mem_bus.write && mem_bus.wmask[1] && (mem_bus.address[23:0] == current_address)) begin
counter <= 3'd0;
end else begin
state <= STATE_PROGRAM_END;
end
end else if (!busy) begin
state <= STATE_PROGRAM_END;
end
end
endcase
@ -363,8 +371,8 @@ module memory_flash (
STATE_PROGRAM_END: begin
finish <= 1'b1;
wdata <= 8'd4;
if (!busy) begin
wdata <= 8'd5;
if (finish && !busy) begin
counter <= 3'd0;
state <= STATE_WAIT;
end
@ -407,15 +415,15 @@ module memory_flash (
3'd1: begin
start <= 1'b1;
quad_enable <= 1'b1;
wdata <= mem_bus.address[23:16];
wdata <= current_address[23:16];
end
3'd2: begin
start <= 1'b1;
wdata <= mem_bus.address[15:8];
wdata <= current_address[15:8];
end
3'd3: begin
start <= 1'b1;
wdata <= mem_bus.address[7:0];
wdata <= current_address[7:0];
end
3'd4: begin
start <= 1'b1;

View File

@ -14,29 +14,38 @@ module memory_sdram (
inout [15:0] sdram_dq
);
localparam [2:0] CAS_LATENCY = 3'd2;
// in Hz
localparam real FREQUENCY = 100_000_000.0;
localparam real T_INIT = 100_000.0;
localparam real T_RC = 60.0;
localparam real T_RP = 15.0;
localparam real T_RCD = 15.0;
localparam real T_MRD = 14.0;
localparam real T_REF = 7_800.0;
// in clocks
localparam bit [2:0] CAS_LATENCY = 3'd2;
localparam real T_CLK = (1.0 / 100_000_000) * 1_000_000_000.0;
localparam int C_INIT = int'((T_INIT + T_CLK - 1) / T_CLK);
localparam int C_RC = int'((T_RC + T_CLK - 1) / T_CLK);
localparam int C_RP = int'((T_RP + T_CLK - 1) / T_CLK);
localparam int C_RCD = int'((T_RCD + T_CLK - 1) / T_CLK);
localparam int C_MRD = int'((T_MRD + T_CLK - 1) / T_CLK);
localparam int C_REF = int'((T_REF + T_CLK - 1) / T_CLK);
// in nanoseconds
localparam real T_INIT = 100_000.0;
localparam real T_MRD = 14.0;
localparam real T_RAS = 37.0;
localparam real T_RC = 60.0;
localparam real T_RCD = 15.0;
localparam real T_REF = 7_812.5;
localparam real T_RP = 15.0;
localparam INIT_PRECHARGE = 4'd0;
localparam INIT_REFRESH_1 = C_RP;
localparam INIT_REFRESH_2 = C_RP + C_RC;
localparam INIT_MODE_REG = C_RP + (2 * C_RC);
localparam INIT_DONE = C_RP + (2 * C_RC) + C_MRD;
localparam real T_CLK = (1.0 / FREQUENCY) * 1_000_000_000.0;
const bit [13:0] C_INIT = 14'(int'($ceil(T_INIT / T_CLK)));
const bit [4:0] C_MRD = 5'(int'($ceil(T_MRD / T_CLK)));
const bit [2:0] C_RAS = 3'(int'($ceil(T_RAS / T_CLK)));
const bit [4:0] C_RC = 5'(int'($ceil(T_RC / T_CLK)));
const bit [4:0] C_RCD = 5'(int'($ceil(T_RCD / T_CLK)));
const bit [13:0] C_REF = 14'(int'($ceil(T_REF / T_CLK)));
const bit [4:0] C_RP = 5'(int'($ceil(T_RP / T_CLK)));
const bit [4:0] INIT_PRECHARGE = 5'd0;
const bit [4:0] INIT_REFRESH_1 = INIT_PRECHARGE + C_RP;
const bit [4:0] INIT_REFRESH_2 = INIT_REFRESH_1 + C_RC;
const bit [4:0] INIT_MODE_REG = INIT_REFRESH_2 + C_RC;
const bit [4:0] INIT_DONE = INIT_MODE_REG + C_MRD;
// /CS, /RAS, /CAS, /WE
typedef enum bit [3:0] {
CMD_DESL = 4'b1111,
CMD_NOP = 4'b0111,
@ -58,13 +67,10 @@ module memory_sdram (
always_ff @(posedge clk) begin
{sdram_cs, sdram_ras, sdram_cas, sdram_we} <= 4'(sdram_next_cmd);
{sdram_ba, sdram_a} <= 15'd0;
sdram_dqm <= 2'b00;
sdram_dq_input <= sdram_dq;
sdram_dq_output <= mem_bus.wdata;
sdram_dq_output_enable <= 1'b0;
case (sdram_next_cmd)
@ -76,19 +82,31 @@ module memory_sdram (
CMD_ACT: begin
{sdram_ba, sdram_a} <= mem_bus.address[25:11];
sdram_dqm <= 2'b00;
current_active_bank_row <= mem_bus.address[25:11];
end
CMD_PRE: begin
{sdram_ba, sdram_a} <= {2'b00, 2'b00, 1'b1, 10'd0};
sdram_dqm <= 2'b00;
{sdram_ba, sdram_a} <= {
2'b00, // [BA1:BA0] Don't care
2'b00, // [A12:A11] Don't care
1'b1, // [A10] Precharge all banks
10'd0 // [A9:A0] Don't care
};
end
CMD_MRS: begin
{sdram_ba, sdram_a} <= {2'b00, 1'b0, 1'b0, 2'b00, CAS_LATENCY, 1'b0, 3'b000};
sdram_dqm <= 2'b00;
{sdram_ba, sdram_a} <= {
2'b00, // [BA1:BA0] Reserved = 0
3'b000, // [A12:A10] Reserved = 0
1'b0, // [A9] Write Burst Mode = Programmed Burst Length
2'b00, // [A8:A7] Operating Mode = Standard Operation
CAS_LATENCY, // [A6:A4] Latency Mode = 2
1'b0, // [A3] Burst Type = Sequential
3'b000 // [A2:A0] Burst Length = 1
};
end
default: begin end
endcase
end
@ -121,35 +139,51 @@ module memory_sdram (
end
end
logic [13:0] powerup_coutner;
logic powerup_done;
logic [13:0] refresh_counter;
logic [4:0] wait_counter;
logic [9:0] refresh_counter;
logic [2:0] precharge_counter;
logic powerup_done;
logic pending_refresh;
logic precharge_valid;
always_ff @(posedge clk) begin
if (reset) begin
powerup_coutner <= 14'd0;
powerup_done <= 1'b0;
end else if (powerup_coutner < C_INIT) begin
powerup_coutner <= powerup_coutner + 1'd1;
end else begin
refresh_counter <= refresh_counter + 1'd1;
if (refresh_counter == C_INIT) begin
refresh_counter <= 14'd0;
powerup_done <= 1'b1;
end
if (reset || state != next_state) begin
wait_counter <= 5'd0;
end else begin
wait_counter <= wait_counter + 1'd1;
if (powerup_done && refresh_counter == C_REF - 14'd1) begin
refresh_counter <= 14'd0;
pending_refresh <= 1'b1;
end
if (sdram_next_cmd == CMD_REF) begin
refresh_counter <= 10'd0;
pending_refresh <= 1'b0;
end else if (refresh_counter < C_REF) begin
refresh_counter <= refresh_counter + 1'd1;
end else begin
pending_refresh <= 1'b1;
end
if (reset) begin
refresh_counter <= 14'd0;
powerup_done <= 1'b0;
pending_refresh <= 1'b0;
end
wait_counter <= wait_counter + 1'd1;
if (state != next_state) begin
wait_counter <= 5'd0;
end
precharge_counter <= precharge_counter + 1'd1;
if (precharge_counter >= C_RAS - 2'd2) begin
precharge_valid <= 1'b1;
end
if (sdram_next_cmd == CMD_ACT) begin
precharge_counter <= 3'd0;
precharge_valid <= 1'b0;
end
end
@ -157,6 +191,7 @@ module memory_sdram (
always_ff @(posedge clk) begin
mem_bus.ack <= 1'b0;
read_cmd_ack_delay <= {sdram_next_cmd == CMD_READ, read_cmd_ack_delay[(CAS_LATENCY):1]};
if (sdram_next_cmd == CMD_WRITE || read_cmd_ack_delay[0]) begin
@ -202,20 +237,20 @@ module memory_sdram (
end
S_ACTIVATING: begin
if (wait_counter == C_RCD) begin
if (wait_counter == C_RCD - 5'd2) begin
next_state = S_ACTIVE;
end
end
S_ACTIVE: begin
if (pending_refresh) begin
if (pending_refresh && precharge_valid) begin
next_state = S_PRECHARGE;
sdram_next_cmd = CMD_PRE;
end else if (mem_bus.request) begin
if (request_in_current_active_bank_row) begin
next_state = S_BUSY;
sdram_next_cmd = mem_bus.write ? CMD_WRITE : CMD_READ;
end else begin
end else if (precharge_valid) begin
next_state = S_PRECHARGE;
sdram_next_cmd = CMD_PRE;
end
@ -229,18 +264,13 @@ module memory_sdram (
end
S_PRECHARGE: begin
if (wait_counter == C_RP) begin
if (pending_refresh) begin
next_state = S_REFRESH;
sdram_next_cmd = CMD_REF;
end else begin
next_state = S_IDLE;
end
if (wait_counter == C_RP - 5'd2) begin
next_state = S_IDLE;
end
end
S_REFRESH: begin
if (wait_counter == C_RC) begin
if (wait_counter == C_RC - 5'd2) begin
next_state = S_IDLE;
end
end

View File

@ -9,7 +9,7 @@ module n64_cfg (
output logic irq
);
typedef enum bit [3:0] {
typedef enum bit [3:0] {
REG_STATUS,
REG_COMMAND,
REG_DATA_0_H,
@ -19,10 +19,39 @@ module n64_cfg (
REG_IDENTIFIER_H,
REG_IDENTIFIER_L,
REG_KEY_H,
REG_KEY_L
REG_KEY_L,
REG_IRQ_H,
REG_IRQ_L,
REG_AUX_H,
REG_AUX_L
} e_reg;
logic cfg_error;
logic cmd_error;
logic cmd_irq_request;
logic cmd_irq;
logic btn_irq;
logic usb_irq;
logic aux_irq;
logic btn_irq_mask;
logic cmd_irq_mask;
logic usb_irq_mask;
logic aux_irq_mask;
always_ff @(posedge clk) begin
irq <= (
(btn_irq && btn_irq_mask) ||
(cmd_irq && cmd_irq_mask) ||
(usb_irq && usb_irq_mask) ||
(aux_irq && aux_irq_mask)
);
end
always_comb begin
btn_irq_mask = 1'b1;
cmd_irq_mask = 1'b1;
end
always_comb begin
reg_bus.rdata = 16'd0;
@ -30,11 +59,18 @@ module n64_cfg (
case (reg_bus.address[4:1])
REG_STATUS: reg_bus.rdata = {
n64_scb.cfg_pending,
cfg_error,
irq,
13'd0
cmd_error,
btn_irq,
btn_irq_mask,
cmd_irq,
cmd_irq_mask,
usb_irq,
usb_irq_mask,
aux_irq,
aux_irq_mask,
6'd0
};
REG_COMMAND: reg_bus.rdata = {8'd0, n64_scb.cfg_cmd};
REG_COMMAND: reg_bus.rdata = {7'd0, cmd_irq_request, n64_scb.cfg_cmd};
REG_DATA_0_H: reg_bus.rdata = n64_scb.cfg_wdata[0][31:16];
REG_DATA_0_L: reg_bus.rdata = n64_scb.cfg_wdata[0][15:0];
REG_DATA_1_H: reg_bus.rdata = n64_scb.cfg_wdata[1][31:16];
@ -43,6 +79,10 @@ module n64_cfg (
REG_IDENTIFIER_L: reg_bus.rdata = n64_scb.cfg_identifier[15:0];
REG_KEY_H: reg_bus.rdata = 16'd0;
REG_KEY_L: reg_bus.rdata = 16'd0;
REG_IRQ_H: reg_bus.rdata = 16'd0;
REG_IRQ_L: reg_bus.rdata = 16'd0;
REG_AUX_H: reg_bus.rdata = n64_scb.aux_wdata[31:16];
REG_AUX_L: reg_bus.rdata = n64_scb.aux_wdata[15:0];
endcase
end
end
@ -51,48 +91,145 @@ module n64_cfg (
logic lock_sequence_counter;
always_ff @(posedge clk) begin
if (n64_scb.cfg_done) begin
n64_scb.aux_pending <= 1'b0;
if (n64_scb.cfg_pending && n64_scb.cfg_done) begin
n64_scb.cfg_pending <= 1'b0;
cfg_error <= n64_scb.cfg_error;
cmd_irq <= cmd_irq_request;
cmd_error <= n64_scb.cfg_error;
end
if (n64_scb.cfg_irq) begin
irq <= 1'b1;
if (n64_scb.cfg_unlock) begin
if (n64_scb.btn_irq) begin
btn_irq <= 1'b1;
end
if (n64_scb.usb_irq) begin
usb_irq <= 1'b1;
end
if (n64_scb.aux_irq) begin
aux_irq <= 1'b1;
end
end
if (unlock_flag) begin
n64_scb.cfg_unlock <= 1'b1;
end
if (reset || n64_scb.n64_reset || n64_scb.n64_nmi) begin
if (reset) begin
n64_scb.cfg_unlock <= 1'b0;
n64_scb.cfg_pending <= 1'b0;
n64_scb.cfg_cmd <= 8'h00;
irq <= 1'b0;
cfg_error <= 1'b0;
cmd_error <= 1'b0;
cmd_irq_request <= 1'b0;
btn_irq <= 1'b0;
cmd_irq <= 1'b0;
usb_irq <= 1'b0;
aux_irq <= 1'b0;
usb_irq_mask <= 1'b0;
aux_irq_mask <= 1'b0;
lock_sequence_counter <= 1'd0;
end else if (n64_scb.n64_reset || n64_scb.n64_nmi) begin
n64_scb.cfg_unlock <= 1'b0;
cmd_irq_request <= 1'b0;
btn_irq <= 1'b0;
cmd_irq <= 1'b0;
usb_irq <= 1'b0;
aux_irq <= 1'b0;
usb_irq_mask <= 1'b0;
aux_irq_mask <= 1'b0;
lock_sequence_counter <= 1'd0;
end else if (n64_scb.cfg_unlock) begin
if (reg_bus.write && reg_bus.address[16] && (reg_bus.address[15:5] == 11'd0)) begin
case (reg_bus.address[4:1])
REG_COMMAND: begin
n64_scb.cfg_pending <= 1'b1;
n64_scb.cfg_cmd <= reg_bus.wdata[7:0];
cfg_error <= 1'b0;
if (!n64_scb.cfg_pending) begin
n64_scb.cfg_pending <= 1'b1;
cmd_error <= 1'b0;
cmd_irq_request <= reg_bus.wdata[8];
n64_scb.cfg_cmd <= reg_bus.wdata[7:0];
end
end
REG_DATA_0_H: n64_scb.cfg_rdata[0][31:16] <= reg_bus.wdata;
REG_DATA_0_L: n64_scb.cfg_rdata[0][15:0] <= reg_bus.wdata;
REG_DATA_1_H: n64_scb.cfg_rdata[1][31:16] <= reg_bus.wdata;
REG_DATA_1_L: n64_scb.cfg_rdata[1][15:0] <= reg_bus.wdata;
REG_IDENTIFIER_H: irq <= 1'b0;
REG_DATA_0_H: begin
if (!n64_scb.cfg_pending) begin
n64_scb.cfg_rdata[0][31:16] <= reg_bus.wdata;
end
end
REG_DATA_0_L: begin
if (!n64_scb.cfg_pending) begin
n64_scb.cfg_rdata[0][15:0] <= reg_bus.wdata;
end
end
REG_DATA_1_H: begin
if (!n64_scb.cfg_pending) begin
n64_scb.cfg_rdata[1][31:16] <= reg_bus.wdata;
end
end
REG_DATA_1_L: begin
if (!n64_scb.cfg_pending) begin
n64_scb.cfg_rdata[1][15:0] <= reg_bus.wdata;
end
end
REG_IDENTIFIER_H: begin
btn_irq <= 1'b0;
end
REG_KEY_H, REG_KEY_L: begin
lock_sequence_counter <= lock_sequence_counter + 1'd1;
if (reg_bus.wdata != 16'hFFFF) begin
lock_sequence_counter <= 1'd0;
end
if (lock_sequence_counter == 1'd1) begin
n64_scb.cfg_unlock <= (reg_bus.wdata != 16'hFFFF);
if (reg_bus.wdata == 16'hFFFF) begin
n64_scb.cfg_unlock <= 1'b0;
cmd_irq_request <= 1'b0;
btn_irq <= 1'b0;
cmd_irq <= 1'b0;
usb_irq <= 1'b0;
aux_irq <= 1'b0;
usb_irq_mask <= 1'b0;
aux_irq_mask <= 1'b0;
end
end
end
REG_IRQ_H: begin
btn_irq <= (reg_bus.wdata[15] ? 1'b0 : btn_irq);
cmd_irq <= (reg_bus.wdata[14] ? 1'b0 : cmd_irq);
usb_irq <= (reg_bus.wdata[13] ? 1'b0 : usb_irq);
aux_irq <= (reg_bus.wdata[12] ? 1'b0 : aux_irq);
end
REG_IRQ_L: begin
if (reg_bus.wdata[10]) begin
usb_irq_mask <= 1'b1;
end
if (reg_bus.wdata[11]) begin
usb_irq_mask <= 1'b0;
end
if (reg_bus.wdata[8]) begin
aux_irq_mask <= 1'b1;
end
if (reg_bus.wdata[9]) begin
aux_irq_mask <= 1'b0;
end
end
REG_AUX_H: begin
n64_scb.aux_rdata[31:16] <= reg_bus.wdata;
end
REG_AUX_L: begin
n64_scb.aux_pending <= 1'b1;
n64_scb.aux_rdata[15:0] <= reg_bus.wdata;
end
endcase
end
end

245
fw/rtl/n64/n64_cic.sv Normal file
View File

@ -0,0 +1,245 @@
module n64_cic (
input clk,
input reset,
n64_scb.cic n64_scb,
input n64_reset,
input n64_cic_clk,
inout n64_cic_dq,
input n64_si_clk
);
// Input/output synchronization
logic [1:0] n64_reset_ff;
logic [1:0] n64_cic_clk_ff;
logic [1:0] n64_cic_dq_ff;
logic [1:0] n64_si_clk_ff;
always_ff @(posedge clk) begin
n64_reset_ff <= {n64_reset_ff[0], n64_reset};
n64_cic_clk_ff <= {n64_cic_clk_ff[0], n64_cic_clk};
n64_cic_dq_ff <= {n64_cic_dq_ff[0], n64_cic_dq};
n64_si_clk_ff <= {n64_si_clk_ff[0], n64_si_clk};
end
logic cic_reset;
logic cic_clk;
logic cic_dq;
logic si_clk;
always_comb begin
cic_reset = n64_reset_ff[1];
cic_clk = n64_cic_clk_ff[1];
cic_dq = n64_cic_dq_ff[1];
si_clk = n64_si_clk_ff[1];
end
logic cic_dq_out;
logic cic_dq_oe;
always_ff @(posedge clk) begin
cic_dq_oe <= ~cic_dq_out;
end
assign n64_cic_dq = cic_dq_oe ? 1'b0 : 1'bZ;
// Timer (divider and counter)
logic last_si_clk;
always_ff @(posedge clk) begin
last_si_clk <= si_clk;
end
logic si_clk_rising_edge;
always_comb begin
si_clk_rising_edge = cic_reset && !last_si_clk && si_clk;
end
logic [7:0] timer_divider;
logic [11:0] timer_counter;
logic timer_start;
logic timer_clear;
logic timer_elapsed;
const bit [11:0] TIMEOUT_500MS = 12'd3815; // (62_500_000 / 32 / 256 / 2) = ~500 ms
always_ff @(posedge clk) begin
if (si_clk_rising_edge) begin
timer_divider <= timer_divider + 1'd1;
end
if (si_clk_rising_edge && (&timer_divider) && (timer_counter > 12'd0)) begin
timer_counter <= timer_counter - 1'd1;
if (timer_counter == 12'd1) begin
timer_elapsed <= 1'b1;
end
end
if (timer_start) begin
timer_divider <= 8'd0;
timer_counter <= TIMEOUT_500MS;
timer_elapsed <= 1'b0;
end
if (timer_clear) begin
timer_divider <= 8'd0;
timer_counter <= 12'd0;
timer_elapsed <= 1'b0;
end
end
// SERV RISC-V CPU
logic [31:0] ibus_addr;
logic ibus_cycle;
logic [31:0] ibus_rdata;
logic ibus_ack;
logic [31:0] dbus_addr;
logic [31:0] dbus_wdata;
logic [3:0] dbus_wmask;
logic dbus_write;
logic dbus_cycle;
logic [31:0] dbus_rdata;
logic dbus_ack;
logic [31:0] ext_rs1;
logic [31:0] ext_rs2;
logic [2:0] ext_funct3;
logic mdu_valid;
serv_rf_top #(
.RESET_PC(32'h8000_0000),
.PRE_REGISTER(0),
.WITH_CSR(0)
) serv_rf_top_inst (
.clk(clk),
.i_rst(reset),
.i_timer_irq(1'b0),
.o_ibus_adr(ibus_addr),
.o_ibus_cyc(ibus_cycle),
.i_ibus_rdt(ibus_rdata),
.i_ibus_ack(ibus_ack),
.o_dbus_adr(dbus_addr),
.o_dbus_dat(dbus_wdata),
.o_dbus_sel(dbus_wmask),
.o_dbus_we(dbus_write) ,
.o_dbus_cyc(dbus_cycle),
.i_dbus_rdt(dbus_rdata),
.i_dbus_ack(dbus_ack),
.o_ext_rs1(ext_rs1),
.o_ext_rs2(ext_rs2),
.o_ext_funct3(ext_funct3),
.i_ext_rd(32'd0),
.i_ext_ready(1'b0),
.o_mdu_valid(mdu_valid)
);
// CPU memory
logic [8:0] ram_addr;
logic [31:0] ram [0:511];
logic [31:0] ram_output;
assign ram_addr = ibus_cycle ? ibus_addr[10:2] : dbus_addr[10:2];
assign ibus_rdata = ram_output;
always_ff @(posedge clk) begin
ram_output <= ram[ram_addr];
ibus_ack <= ibus_cycle && !ibus_ack;
end
initial begin
$readmemh("../../../sw/cic/build/cic.mem", ram);
end
// Bus controller
always_ff @(posedge clk) begin
timer_start <= 1'b0;
timer_clear <= 1'b0;
n64_scb.cic_invalid_region <= 1'b0;
dbus_ack <= dbus_cycle && !dbus_ack;
if (dbus_cycle && dbus_write) begin
case (dbus_addr[31:30])
2'b10: begin
if (dbus_wmask[0]) ram[ram_addr][7:0] <= dbus_wdata[7:0];
if (dbus_wmask[1]) ram[ram_addr][15:8] <= dbus_wdata[15:8];
if (dbus_wmask[2]) ram[ram_addr][23:16] <= dbus_wdata[23:16];
if (dbus_wmask[3]) ram[ram_addr][31:24] <= dbus_wdata[31:24];
end
2'b11: begin
case (dbus_addr[3:2])
2'b10: begin
n64_scb.cic_invalid_region <= dbus_wdata[6];
timer_clear <= dbus_wdata[5];
timer_start <= dbus_wdata[4];
cic_dq_out <= dbus_wdata[0];
end
2'b11: begin
n64_scb.cic_debug_step <= dbus_wdata[3:0];
end
endcase
end
endcase
end
if (reset) begin
n64_scb.cic_debug_step <= 3'd0;
end
if (reset || !cic_reset) begin
cic_dq_out <= 1'b1;
end
end
always_comb begin
dbus_rdata = 32'd0;
case (dbus_addr[31:30])
2'b10: begin
dbus_rdata = ram_output;
end
2'b11: begin
case (dbus_addr[3:2])
2'b00: dbus_rdata = {
n64_scb.cic_disabled,
n64_scb.cic_64dd_mode,
n64_scb.cic_region,
n64_scb.cic_seed,
n64_scb.cic_checksum[47:32]
};
2'b01: dbus_rdata = n64_scb.cic_checksum[31:0];
2'b10: dbus_rdata = {
28'd0,
timer_elapsed,
cic_reset,
cic_clk,
cic_dq
};
2'b11: dbus_rdata = {28'd0, n64_scb.cic_debug_step};
endcase
end
endcase
end
endmodule

View File

@ -8,7 +8,7 @@ module n64_flashram (
);
localparam [31:0] FLASH_TYPE_ID = 32'h1111_8001;
localparam [31:0] FLASH_MODEL_ID = 32'h00C2_001D;
localparam [31:0] FLASH_MODEL_ID = 32'h0032_00F1;
typedef enum bit [7:0] {
CMD_STATUS_MODE = 8'hD2,
@ -97,14 +97,14 @@ module n64_flashram (
CMD_ERASE_SECTOR: begin
state <= STATE_STATUS;
erase_enabled <= 1'b1;
n64_scb.flashram_sector <= reg_bus.wdata[9:0];
n64_scb.flashram_page <= reg_bus.wdata[9:0];
n64_scb.flashram_sector_or_all <= 1'b0;
end
CMD_ERASE_CHIP: begin
state <= STATE_STATUS;
erase_enabled <= 1'b1;
n64_scb.flashram_sector <= 10'd0;
n64_scb.flashram_page <= 10'd0;
n64_scb.flashram_sector_or_all <= 1'b1;
end
@ -126,7 +126,7 @@ module n64_flashram (
state <= STATE_STATUS;
status[WRITE_BUSY] <= 1'b1;
status[WRITE_DONE] <= 1'b0;
n64_scb.flashram_sector <= reg_bus.wdata[9:0];
n64_scb.flashram_page <= reg_bus.wdata[9:0];
n64_scb.flashram_pending <= 1'b1;
n64_scb.flashram_write_or_erase <= 1'b0;
n64_scb.flashram_sector_or_all <= 1'b0;
@ -134,9 +134,9 @@ module n64_flashram (
endcase
end
end else begin
if (reg_bus.address[1] && state != STATE_BUFFER) begin
status[ERASE_BUSY] <= reg_bus.wdata[ERASE_BUSY];
status[WRITE_BUSY] <= reg_bus.wdata[WRITE_BUSY];
if (reg_bus.address[1] && state == STATE_STATUS) begin
status[ERASE_DONE] <= 1'b0;
status[WRITE_DONE] <= 1'b0;
end
end
end

View File

@ -20,16 +20,16 @@ module n64_pi (
logic [1:0] n64_reset_ff;
logic [1:0] n64_nmi_ff;
logic [3:0] n64_pi_alel_ff;
logic [3:0] n64_pi_aleh_ff;
logic [2:0] n64_pi_alel_ff;
logic [2:0] n64_pi_aleh_ff;
logic [1:0] n64_pi_read_ff;
logic [2:0] n64_pi_write_ff;
always_ff @(posedge clk) begin
n64_reset_ff <= {n64_reset_ff[0], n64_reset};
n64_nmi_ff <= {n64_nmi_ff[0], n64_nmi};
n64_pi_aleh_ff <= {n64_pi_aleh_ff[2:0], n64_pi_aleh};
n64_pi_alel_ff <= {n64_pi_alel_ff[2:0], n64_pi_alel};
n64_pi_aleh_ff <= {n64_pi_aleh_ff[1:0], n64_pi_aleh};
n64_pi_alel_ff <= {n64_pi_alel_ff[1:0], n64_pi_alel};
n64_pi_read_ff <= {n64_pi_read_ff[0], n64_pi_read};
n64_pi_write_ff <= {n64_pi_write_ff[1:0], n64_pi_write};
end
@ -44,8 +44,8 @@ module n64_pi (
always_comb begin
pi_reset = n64_reset_ff[1];
pi_nmi = n64_nmi_ff[1];
pi_aleh = n64_pi_aleh_ff[3];
pi_alel = n64_pi_alel_ff[3];
pi_aleh = n64_pi_aleh_ff[2];
pi_alel = n64_pi_alel_ff[2];
pi_read = n64_pi_read_ff[1];
pi_write = n64_pi_write_ff[2];
end
@ -98,11 +98,14 @@ module n64_pi (
always_comb begin
n64_scb.n64_reset = !last_reset && pi_reset;
n64_scb.n64_nmi = !last_nmi && pi_nmi;
aleh_op = pi_reset && (last_pi_mode != PI_MODE_HIGH) && (pi_mode == PI_MODE_HIGH);
alel_op = pi_reset && (last_pi_mode == PI_MODE_HIGH) && (pi_mode == PI_MODE_LOW);
read_op = pi_reset && (pi_mode == PI_MODE_VALID) && (read_port != PORT_NONE) && (last_read && !pi_read);
write_op = pi_reset && (pi_mode == PI_MODE_VALID) && (write_port != PORT_NONE) && (last_write && !pi_write);
end_op = pi_reset && (last_pi_mode == PI_MODE_VALID) && (pi_mode != PI_MODE_VALID);
end
always_ff @(posedge clk) begin
aleh_op <= pi_reset && (last_pi_mode != PI_MODE_HIGH) && (pi_mode == PI_MODE_HIGH);
alel_op <= pi_reset && (last_pi_mode == PI_MODE_HIGH) && (pi_mode == PI_MODE_LOW);
read_op <= pi_reset && (pi_mode == PI_MODE_VALID) && (read_port != PORT_NONE) && (last_read && !pi_read);
write_op <= pi_reset && (pi_mode == PI_MODE_VALID) && (write_port != PORT_NONE) && (last_write && !pi_write);
end_op <= pi_reset && (last_pi_mode == PI_MODE_VALID) && (pi_mode != PI_MODE_VALID);
end
@ -124,12 +127,21 @@ module n64_pi (
// Debug: last accessed PI address
logic [15:0] pi_debug_address_buffer;
always_ff @(posedge clk) begin
if (aleh_op) begin
n64_scb.pi_debug[31:16] <= n64_pi_dq_in;
pi_debug_address_buffer <= n64_pi_dq_in;
end
if (alel_op) begin
n64_scb.pi_debug[15:0] <= n64_pi_dq_in;
n64_scb.pi_debug_address <= {pi_debug_address_buffer, n64_pi_dq_in};
n64_scb.pi_debug_rw_count <= 17'd0;
end
if (pi_reset && (pi_mode == PI_MODE_VALID)) begin
if ((last_read && !pi_read) || (last_write && !pi_write)) begin
n64_scb.pi_debug_rw_count <= n64_scb.pi_debug_rw_count + 1'd1;
n64_scb.pi_debug_direction <= !pi_write;
end
end
end
@ -293,11 +305,11 @@ module n64_pi (
.reset(reset),
.flush(reset || !pi_reset || alel_op),
.full(read_fifo_full),
.write(read_fifo_write),
.wdata(read_fifo_wdata),
.empty(read_fifo_empty),
.read(read_fifo_read),
.rdata(read_fifo_rdata)
@ -307,7 +319,7 @@ module n64_pi (
read_fifo_read <= 1'b0;
if (!pi_reset) begin
n64_scb.pi_debug[33:32] <= 2'b00;
n64_scb.pi_debug_fifo_flags[1:0] <= 2'b00;
end
if (reset || !pi_reset || alel_op) begin
@ -318,9 +330,9 @@ module n64_pi (
if (read_op) begin
if (read_fifo_empty) begin
read_fifo_wait <= 1'b1;
n64_scb.pi_debug[32] <= 1'b1;
n64_scb.pi_debug_fifo_flags[0] <= 1'b1;
if (read_fifo_wait) begin
n64_scb.pi_debug[33] <= 1'b1;
n64_scb.pi_debug_fifo_flags[1] <= 1'b1;
end
end else begin
read_fifo_read <= 1'b1;
@ -374,7 +386,7 @@ module n64_pi (
write_fifo_write <= 1'b0;
if (!pi_reset) begin
n64_scb.pi_debug[35:34] <= 2'b00;
n64_scb.pi_debug_fifo_flags[3:2] <= 2'b00;
end
if (reset) begin
@ -385,9 +397,9 @@ module n64_pi (
if (write_op) begin
if (write_fifo_full) begin
write_fifo_wait <= 1'b1;
n64_scb.pi_debug[34] <= 1'b1;
n64_scb.pi_debug_fifo_flags[2] <= 1'b1;
if (write_fifo_wait) begin
n64_scb.pi_debug[35] <= 1'b1;
n64_scb.pi_debug_fifo_flags[3] <= 1'b1;
end
end else begin
write_fifo_write <= 1'b1;
@ -473,7 +485,11 @@ module n64_pi (
// Reg bus controller
logic reg_bus_address_increment;
always_ff @(posedge clk) begin
reg_bus_address_increment <= read_op || write_op;
if (aleh_op) begin
reg_bus.address[16] <= n64_pi_dq_in[0];
end
@ -482,15 +498,13 @@ module n64_pi (
reg_bus.address[15:0] <= n64_pi_dq_in;
end
if (read_op || write_op) begin
if (reg_bus_address_increment) begin
reg_bus.address <= reg_bus.address + 2'd2;
end
end
always_comb begin
reg_bus.read = read_op && (read_port == PORT_REG);
reg_bus.write = write_op && (write_port == PORT_REG);
reg_bus.wdata = n64_pi_dq_in;
reg_bus.read <= read_op && (read_port == PORT_REG);
reg_bus.write <= write_op && (write_port == PORT_REG);
reg_bus.wdata <= n64_pi_dq_in;
end
endmodule

View File

@ -22,7 +22,7 @@ interface n64_scb ();
logic flashram_pending;
logic flashram_done;
logic [9:0] flashram_sector;
logic [9:0] flashram_page;
logic flashram_sector_or_all;
logic flashram_write_or_erase;
logic flashram_read_mode;
@ -40,24 +40,42 @@ interface n64_scb ();
logic rtc_pending;
logic rtc_done;
logic rtc_wdata_valid;
logic [41:0] rtc_rdata;
logic [41:0] rtc_wdata;
logic [42:0] rtc_rdata;
logic [42:0] rtc_wdata;
logic cfg_unlock;
logic cfg_pending;
logic cfg_done;
logic cfg_error;
logic cfg_irq;
logic [7:0] cfg_cmd;
logic [31:0] cfg_rdata [0:1];
logic [31:0] cfg_wdata [0:1];
logic [31:0] cfg_identifier;
logic btn_irq;
logic usb_irq;
logic aux_irq;
logic aux_pending;
logic [31:0] aux_rdata;
logic [31:0] aux_wdata;
logic [15:0] save_count;
logic cic_invalid_region;
logic cic_disabled;
logic cic_64dd_mode;
logic cic_region;
logic [7:0] cic_seed;
logic [47:0] cic_checksum;
logic [3:0] cic_debug_step;
logic pi_sdram_active;
logic pi_flash_active;
logic [35:0] pi_debug;
logic [31:0] pi_debug_address;
logic [16:0] pi_debug_rw_count;
logic pi_debug_direction;
logic [3:0] pi_debug_fifo_flags;
modport controller (
input n64_reset,
@ -77,7 +95,7 @@ interface n64_scb ();
input flashram_pending,
output flashram_done,
input flashram_sector,
input flashram_page,
input flashram_sector_or_all,
input flashram_write_or_erase,
@ -90,15 +108,33 @@ interface n64_scb ();
input cfg_pending,
output cfg_done,
output cfg_error,
output cfg_irq,
input cfg_cmd,
input cfg_rdata,
output cfg_wdata,
output cfg_identifier,
output btn_irq,
output usb_irq,
output aux_irq,
input aux_pending,
input aux_rdata,
output aux_wdata,
input save_count,
input pi_debug
input cic_invalid_region,
output cic_disabled,
output cic_64dd_mode,
output cic_region,
output cic_seed,
output cic_checksum,
input cic_debug_step,
input pi_debug_address,
input pi_debug_rw_count,
input pi_debug_direction,
input pi_debug_fifo_flags
);
modport pi (
@ -123,13 +159,17 @@ interface n64_scb ();
output pi_sdram_active,
output pi_flash_active,
output pi_debug
output pi_debug_address,
output pi_debug_rw_count,
output pi_debug_direction,
output pi_debug_fifo_flags
);
modport flashram (
output flashram_pending,
input flashram_done,
output flashram_sector,
output flashram_page,
output flashram_sector_or_all,
output flashram_write_or_erase,
@ -190,11 +230,18 @@ interface n64_scb ();
output cfg_pending,
input cfg_done,
input cfg_error,
input cfg_irq,
output cfg_cmd,
output cfg_rdata,
input cfg_wdata,
input cfg_identifier
input cfg_identifier,
input btn_irq,
input usb_irq,
input aux_irq,
output aux_pending,
output aux_rdata,
input aux_wdata
);
modport save_counter (
@ -205,6 +252,16 @@ interface n64_scb ();
output save_count
);
modport cic (
output cic_invalid_region,
input cic_disabled,
input cic_64dd_mode,
input cic_region,
input cic_seed,
input cic_checksum,
output cic_debug_step
);
modport arbiter (
input pi_sdram_active,
input pi_flash_active

View File

@ -59,6 +59,7 @@ module n64_si (
// Data falling/rising event generator
logic last_si_dq_in;
logic si_dq_in_inhibit;
always_ff @(posedge clk) begin
if (si_clk_rising_edge) begin
@ -70,14 +71,14 @@ module n64_si (
logic si_dq_rising_edge;
always_comb begin
si_dq_falling_edge = si_clk_rising_edge && last_si_dq_in && !si_dq_in;
si_dq_rising_edge = si_clk_rising_edge && !last_si_dq_in && si_dq_in;
si_dq_falling_edge = si_clk_rising_edge && last_si_dq_in && !si_dq_in && !si_dq_in_inhibit;
si_dq_rising_edge = si_clk_rising_edge && !last_si_dq_in && si_dq_in && !si_dq_in_inhibit;
end
// RX bit generator
logic [3:0] rx_sub_bit_counter;
logic [4:0] rx_sub_bit_counter;
logic rx_timeout;
logic rx_bit_valid;
logic rx_bit_data;
@ -94,7 +95,7 @@ module n64_si (
always_comb begin
rx_timeout = si_clk_rising_edge && si_dq_in && (&rx_sub_bit_counter);
rx_bit_valid = si_dq_rising_edge;
rx_bit_data = (rx_sub_bit_counter >= 4'd3) ? 1'b0 : 1'b1;
rx_bit_data = (rx_sub_bit_counter >= 5'd4) ? 1'b0 : 1'b1;
end
@ -124,7 +125,7 @@ module n64_si (
logic rx_stop;
always_comb begin
rx_stop = si_clk_rising_edge && si_dq_in && (rx_sub_bit_counter == 4'd7) && (rx_bit_counter == 3'd1);
rx_stop = si_clk_rising_edge && si_dq_in && (rx_sub_bit_counter == 5'd15) && (rx_bit_counter == 3'd1);
end
@ -260,7 +261,8 @@ module n64_si (
typedef enum bit [1:0] {
TX_STATE_IDLE,
TX_STATE_DATA,
TX_STATE_STOP
TX_STATE_STOP,
TX_STATE_STOP_WAIT
} e_tx_state;
e_tx_state tx_state;
@ -278,12 +280,14 @@ module n64_si (
if (reset) begin
tx_state <= TX_STATE_IDLE;
si_dq_in_inhibit <= 1'b0;
end else begin
case (tx_state)
TX_STATE_IDLE: begin
if (tx_start) begin
tx_byte_counter <= 4'd0;
tx_state <= TX_STATE_DATA;
si_dq_in_inhibit <= 1'b1;
end
end
@ -299,7 +303,14 @@ module n64_si (
TX_STATE_STOP: begin
tx_stop <= 1'b1;
if (!tx_busy && tx_stop) begin
tx_state <= TX_STATE_STOP_WAIT;
end
end
TX_STATE_STOP_WAIT: begin
if (!tx_busy) begin
tx_state <= TX_STATE_IDLE;
si_dq_in_inhibit <= 1'b0;
end
end
endcase
@ -351,6 +362,7 @@ module n64_si (
logic [2:0] rtc_time_weekday;
logic [4:0] rtc_time_month;
logic [7:0] rtc_time_year;
logic rtc_time_century;
always_ff @(posedge clk) begin
if (reset) begin
@ -366,6 +378,7 @@ module n64_si (
if (!(|rtc_stopped) && !n64_scb.rtc_pending && n64_scb.rtc_wdata_valid && (tx_state != TX_STATE_DATA)) begin
{
rtc_time_century,
rtc_time_year,
rtc_time_month,
rtc_time_weekday,
@ -382,7 +395,7 @@ module n64_si (
4'd1: {rtc_time_wp, rtc_backup_wp} <= rx_byte_data[1:0];
4'd2: begin
rtc_stopped <= rx_byte_data[2:1];
if (rx_byte_data[2:1] == 2'b00) begin
if ((|rtc_stopped) && (rx_byte_data[2:1] == 2'b00)) begin
n64_scb.rtc_pending <= 1'b1;
end
end
@ -397,6 +410,7 @@ module n64_si (
4'd5: rtc_time_weekday <= rx_byte_data[2:0];
4'd6: rtc_time_month <= rx_byte_data[4:0];
4'd7: rtc_time_year <= rx_byte_data;
4'd8: rtc_time_century <= rx_byte_data[0];
endcase
end
end
@ -404,6 +418,7 @@ module n64_si (
always_comb begin
n64_scb.rtc_rdata = {
rtc_time_century,
rtc_time_year,
rtc_time_month,
rtc_time_weekday,
@ -458,7 +473,7 @@ module n64_si (
4'd4: tx_byte_data = {5'd0, rtc_time_weekday};
4'd5: tx_byte_data = {3'd0, rtc_time_month};
4'd6: tx_byte_data = rtc_time_year;
4'd7: tx_byte_data = 8'h01;
4'd7: tx_byte_data = {7'd0, rtc_time_century};
4'd8: tx_byte_data = {(|rtc_stopped), 7'd0};
endcase
end

View File

@ -18,18 +18,27 @@ module n64_top (
inout [15:0] n64_pi_ad,
input n64_si_clk,
inout n64_si_dq
inout n64_si_dq,
input n64_cic_clk,
inout n64_cic_dq
);
logic n64_dd_irq;
logic n64_cfg_irq;
logic n64_irq_oe;
logic irq_data;
logic irq_dq;
logic [1:0] irq_oe;
assign irq_data = (n64_dd_irq || n64_cfg_irq);
always @(posedge clk) begin
n64_irq_oe <= (n64_dd_irq || n64_cfg_irq);
irq_dq <= (~irq_data);
irq_oe <= {irq_oe[0], irq_data};
end
assign n64_irq = n64_irq_oe ? 1'b0 : 1'bZ;
assign n64_irq = irq_oe[1] ? irq_dq : 1'bZ;
n64_reg_bus reg_bus ();
@ -101,4 +110,16 @@ module n64_top (
.n64_scb(n64_scb)
);
n64_cic n64_cic_inst (
.clk(clk),
.reset(reset),
.n64_scb(n64_scb),
.n64_reset(n64_reset),
.n64_cic_clk(n64_cic_clk),
.n64_cic_dq(n64_cic_dq),
.n64_si_clk(n64_si_clk)
);
endmodule

View File

@ -36,12 +36,10 @@ module sd_dat (
// FIFO
logic rx_full;
logic rx_almost_full;
logic rx_write;
logic [7:0] rx_wdata;
logic tx_empty;
logic tx_almost_empty;
logic tx_read;
logic [7:0] tx_rdata;
@ -50,12 +48,10 @@ module sd_dat (
.reset(reset || sd_scb.dat_fifo_flush),
.empty(fifo_bus.rx_empty),
.almost_empty(fifo_bus.rx_almost_empty),
.read(fifo_bus.rx_read),
.rdata(fifo_bus.rx_rdata),
.full(rx_full),
.almost_full(rx_almost_full),
.write(rx_write),
.wdata(rx_wdata),
@ -67,12 +63,10 @@ module sd_dat (
.reset(reset || sd_scb.dat_fifo_flush),
.empty(tx_empty),
.almost_empty(tx_almost_empty),
.read(tx_read),
.rdata(tx_rdata),
.full(fifo_bus.tx_full),
.almost_full(fifo_bus.tx_almost_full),
.write(fifo_bus.tx_write),
.wdata(fifo_bus.tx_wdata),

67
fw/rtl/serv/serv_aligner.v vendored Normal file
View File

@ -0,0 +1,67 @@
module serv_aligner
(
input wire clk,
input wire rst,
// serv_top
input wire [31:0] i_ibus_adr,
input wire i_ibus_cyc,
output wire [31:0] o_ibus_rdt,
output wire o_ibus_ack,
// serv_rf_top
output wire [31:0] o_wb_ibus_adr,
output wire o_wb_ibus_cyc,
input wire [31:0] i_wb_ibus_rdt,
input wire i_wb_ibus_ack);
wire [31:0] ibus_rdt_concat;
wire ack_en;
reg [15:0] lower_hw;
reg ctrl_misal ;
/* From SERV core to Memory
o_wb_ibus_adr: Carries address of instruction to memory. In case of misaligned access,
which is caused by pc+2 due to compressed instruction, next instruction is fetched
by pc+4 and concatenation is done to make the instruction aligned.
o_wb_ibus_cyc: Simply forwarded from SERV to Memory and is only altered by memory or SERV core.
*/
assign o_wb_ibus_adr = ctrl_misal ? (i_ibus_adr+32'b100) : i_ibus_adr;
assign o_wb_ibus_cyc = i_ibus_cyc;
/* From Memory to SERV core
o_ibus_ack: Instruction bus acknowledge is send to SERV only when the aligned instruction,
either compressed or un-compressed, is ready to dispatch.
o_ibus_rdt: Carries the instruction from memory to SERV core. It can be either aligned
instruction coming from memory or made aligned by two bus transactions and concatenation.
*/
assign o_ibus_ack = i_wb_ibus_ack & ack_en;
assign o_ibus_rdt = ctrl_misal ? ibus_rdt_concat : i_wb_ibus_rdt;
/* 16-bit register used to hold the upper half word of the current instruction in-case
concatenation will be required with the upper half word of upcoming instruction
*/
always @(posedge clk) begin
if(i_wb_ibus_ack)begin
lower_hw <= i_wb_ibus_rdt[31:16];
end
end
assign ibus_rdt_concat = {i_wb_ibus_rdt[15:0],lower_hw};
/* Two control signals: ack_en, ctrl_misal are set to control the bus transactions between
SERV core and the memory
*/
assign ack_en = !(i_ibus_adr[1] & !ctrl_misal);
always @(posedge clk ) begin
if(rst)
ctrl_misal <= 0;
else if(i_wb_ibus_ack & i_ibus_adr[1])
ctrl_misal <= !ctrl_misal;
end
endmodule

81
fw/rtl/serv/serv_alu.v vendored Normal file
View File

@ -0,0 +1,81 @@
`default_nettype none
module serv_alu
#(
parameter W = 1,
parameter B = W-1
)
(
input wire clk,
//State
input wire i_en,
input wire i_cnt0,
output wire o_cmp,
//Control
input wire i_sub,
input wire [1:0] i_bool_op,
input wire i_cmp_eq,
input wire i_cmp_sig,
input wire [2:0] i_rd_sel,
//Data
input wire [B:0] i_rs1,
input wire [B:0] i_op_b,
input wire [B:0] i_buf,
output wire [B:0] o_rd);
wire [B:0] result_add;
wire [B:0] result_slt;
reg cmp_r;
wire add_cy;
reg [B:0] add_cy_r;
//Sign-extended operands
wire rs1_sx = i_rs1[B] & i_cmp_sig;
wire op_b_sx = i_op_b[B] & i_cmp_sig;
wire [B:0] add_b = i_op_b^{W{i_sub}};
assign {add_cy,result_add} = i_rs1+add_b+add_cy_r;
wire result_lt = rs1_sx + ~op_b_sx + add_cy;
wire result_eq = !(|result_add) & (cmp_r | i_cnt0);
assign o_cmp = i_cmp_eq ? result_eq : result_lt;
/*
The result_bool expression implements the following operations between
i_rs1 and i_op_b depending on the value of i_bool_op
00 xor
01 0
10 or
11 and
i_bool_op will be 01 during shift operations, so by outputting zero under
this condition we can safely or result_bool with i_buf
*/
wire [B:0] result_bool = ((i_rs1 ^ i_op_b) & ~{W{i_bool_op[0]}}) | ({W{i_bool_op[1]}} & i_op_b & i_rs1);
assign result_slt[0] = cmp_r & i_cnt0;
generate
if (W>1) begin : gen_w_gt_1
assign result_slt[B:1] = {B{1'b0}};
end
endgenerate
assign o_rd = i_buf |
({W{i_rd_sel[0]}} & result_add) |
({W{i_rd_sel[1]}} & result_slt) |
({W{i_rd_sel[2]}} & result_bool);
always @(posedge clk) begin
add_cy_r <= {W{1'b0}};
add_cy_r[0] <= i_en ? add_cy : i_sub;
if (i_en)
cmp_r <= o_cmp;
end
endmodule

51
fw/rtl/serv/serv_bufreg.v vendored Normal file
View File

@ -0,0 +1,51 @@
module serv_bufreg #(
parameter [0:0] MDU = 0
)(
input wire i_clk,
//State
input wire i_cnt0,
input wire i_cnt1,
input wire i_en,
input wire i_init,
input wire i_mdu_op,
output wire [1:0] o_lsb,
//Control
input wire i_rs1_en,
input wire i_imm_en,
input wire i_clr_lsb,
input wire i_sh_signed,
//Data
input wire i_rs1,
input wire i_imm,
output wire o_q,
//External
output wire [31:0] o_dbus_adr,
//Extension
output wire [31:0] o_ext_rs1);
wire c, q;
reg c_r;
reg [31:2] data;
reg [1:0] lsb;
wire clr_lsb = i_cnt0 & i_clr_lsb;
assign {c,q} = {1'b0,(i_rs1 & i_rs1_en)} + {1'b0,(i_imm & i_imm_en & !clr_lsb)} + c_r;
always @(posedge i_clk) begin
//Make sure carry is cleared before loading new data
c_r <= c & i_en;
if (i_en)
data <= {i_init ? q : (data[31] & i_sh_signed), data[31:3]};
if (i_init ? (i_cnt0 | i_cnt1) : i_en)
lsb <= {i_init ? q : data[2],lsb[1]};
end
assign o_q = lsb[0] & i_en;
assign o_dbus_adr = {data, 2'b00};
assign o_ext_rs1 = {o_dbus_adr[31:2],lsb};
assign o_lsb = (MDU & i_mdu_op) ? 2'b00 : lsb;
endmodule

65
fw/rtl/serv/serv_bufreg2.v vendored Normal file
View File

@ -0,0 +1,65 @@
module serv_bufreg2
(
input wire i_clk,
//State
input wire i_en,
input wire i_init,
input wire i_cnt_done,
input wire [1:0] i_lsb,
input wire i_byte_valid,
output wire o_sh_done,
output wire o_sh_done_r,
//Control
input wire i_op_b_sel,
input wire i_shift_op,
//Data
input wire i_rs2,
input wire i_imm,
output wire o_op_b,
output wire o_q,
//External
output wire [31:0] o_dat,
input wire i_load,
input wire [31:0] i_dat);
reg [31:0] dat;
assign o_op_b = i_op_b_sel ? i_rs2 : i_imm;
wire dat_en = i_shift_op | (i_en & i_byte_valid);
/* The dat register has three different use cases for store, load and
shift operations.
store : Data to be written is shifted to the correct position in dat during
init by dat_en and is presented on the data bus as o_wb_dat
load : Data from the bus gets latched into dat during i_wb_ack and is then
shifted out at the appropriate time to end up in the correct
position in rd
shift : Data is shifted in during init. After that, the six LSB are used as
a downcounter (with bit 5 initially set to 0) that triggers
o_sh_done and o_sh_done_r when they wrap around to indicate that
the requested number of shifts have been performed
*/
wire [5:0] dat_shamt = (i_shift_op & !i_init) ?
//Down counter mode
dat[5:0]-1 :
//Shift reg mode with optional clearing of bit 5
{dat[6] & !(i_shift_op & i_cnt_done),dat[5:1]};
assign o_sh_done = dat_shamt[5];
assign o_sh_done_r = dat[5];
assign o_q =
((i_lsb == 2'd3) & dat[24]) |
((i_lsb == 2'd2) & dat[16]) |
((i_lsb == 2'd1) & dat[8]) |
((i_lsb == 2'd0) & dat[0]);
assign o_dat = dat;
always @(posedge i_clk) begin
if (dat_en | i_load)
dat <= i_load ? i_dat : {o_op_b, dat[31:7], dat_shamt};
end
endmodule

234
fw/rtl/serv/serv_compdec.v vendored Normal file
View File

@ -0,0 +1,234 @@
/* Copyright lowRISC contributors.
Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
Licensed under the Apache License, Version 2.0, see LICENSE for details.
SPDX-License-Identifier: Apache-2.0
* Adapted to SERV by @Abdulwadoodd as part of the project under spring '22 LFX Mentorship program */
/* Decodes RISC-V compressed instructions into their RV32i equivalent. */
module serv_compdec
(
input wire i_clk,
input wire [31:0] i_instr,
input wire i_ack,
output wire [31:0] o_instr,
output reg o_iscomp);
localparam OPCODE_LOAD = 7'h03;
localparam OPCODE_OP_IMM = 7'h13;
localparam OPCODE_STORE = 7'h23;
localparam OPCODE_OP = 7'h33;
localparam OPCODE_LUI = 7'h37;
localparam OPCODE_BRANCH = 7'h63;
localparam OPCODE_JALR = 7'h67;
localparam OPCODE_JAL = 7'h6f;
reg [31:0] comp_instr;
reg illegal_instr;
assign o_instr = illegal_instr ? i_instr : comp_instr;
always @(posedge i_clk) begin
if(i_ack)
o_iscomp <= !illegal_instr;
end
always @ (*) begin
// By default, forward incoming instruction, mark it as legal.
comp_instr = i_instr;
illegal_instr = 1'b0;
// Check if incoming instruction is compressed.
case (i_instr[1:0])
// C0
2'b00: begin
case (i_instr[15:14])
2'b00: begin
// c.addi4spn -> addi rd', x2, imm
comp_instr = {2'b0, i_instr[10:7], i_instr[12:11], i_instr[5],
i_instr[6], 2'b00, 5'h02, 3'b000, 2'b01, i_instr[4:2], {OPCODE_OP_IMM}};
end
2'b01: begin
// c.lw -> lw rd', imm(rs1')
comp_instr = {5'b0, i_instr[5], i_instr[12:10], i_instr[6],
2'b00, 2'b01, i_instr[9:7], 3'b010, 2'b01, i_instr[4:2], {OPCODE_LOAD}};
end
2'b11: begin
// c.sw -> sw rs2', imm(rs1')
comp_instr = {5'b0, i_instr[5], i_instr[12], 2'b01, i_instr[4:2],
2'b01, i_instr[9:7], 3'b010, i_instr[11:10], i_instr[6],
2'b00, {OPCODE_STORE}};
end
2'b10: begin
illegal_instr = 1'b1;
end
endcase
end
// C1
// Register address checks for RV32E are performed in the regular instruction decoder.
// If this check fails, an illegal instruction exception is triggered and the controller
// writes the actual faulting instruction to mtval.
2'b01: begin
case (i_instr[15:13])
3'b000: begin
// c.addi -> addi rd, rd, nzimm
// c.nop
comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2],
i_instr[11:7], 3'b0, i_instr[11:7], {OPCODE_OP_IMM}};
end
3'b001, 3'b101: begin
// 001: c.jal -> jal x1, imm
// 101: c.j -> jal x0, imm
comp_instr = {i_instr[12], i_instr[8], i_instr[10:9], i_instr[6],
i_instr[7], i_instr[2], i_instr[11], i_instr[5:3],
{9 {i_instr[12]}}, 4'b0, ~i_instr[15], {OPCODE_JAL}};
end
3'b010: begin
// c.li -> addi rd, x0, nzimm
// (c.li hints are translated into an addi hint)
comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2], 5'b0,
3'b0, i_instr[11:7], {OPCODE_OP_IMM}};
end
3'b011: begin
// c.lui -> lui rd, imm
// (c.lui hints are translated into a lui hint)
comp_instr = {{15 {i_instr[12]}}, i_instr[6:2], i_instr[11:7], {OPCODE_LUI}};
if (i_instr[11:7] == 5'h02) begin
// c.addi16sp -> addi x2, x2, nzimm
comp_instr = {{3 {i_instr[12]}}, i_instr[4:3], i_instr[5], i_instr[2],
i_instr[6], 4'b0, 5'h02, 3'b000, 5'h02, {OPCODE_OP_IMM}};
end
end
3'b100: begin
case (i_instr[11:10])
2'b00,
2'b01: begin
// 00: c.srli -> srli rd, rd, shamt
// 01: c.srai -> srai rd, rd, shamt
// (c.srli/c.srai hints are translated into a srli/srai hint)
comp_instr = {1'b0, i_instr[10], 5'b0, i_instr[6:2], 2'b01, i_instr[9:7],
3'b101, 2'b01, i_instr[9:7], {OPCODE_OP_IMM}};
end
2'b10: begin
// c.andi -> andi rd, rd, imm
comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2], 2'b01, i_instr[9:7],
3'b111, 2'b01, i_instr[9:7], {OPCODE_OP_IMM}};
end
2'b11: begin
case (i_instr[6:5])
2'b00: begin
// c.sub -> sub rd', rd', rs2'
comp_instr = {2'b01, 5'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7],
3'b000, 2'b01, i_instr[9:7], {OPCODE_OP}};
end
2'b01: begin
// c.xor -> xor rd', rd', rs2'
comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b100,
2'b01, i_instr[9:7], {OPCODE_OP}};
end
2'b10: begin
// c.or -> or rd', rd', rs2'
comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b110,
2'b01, i_instr[9:7], {OPCODE_OP}};
end
2'b11: begin
// c.and -> and rd', rd', rs2'
comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b111,
2'b01, i_instr[9:7], {OPCODE_OP}};
end
endcase
end
endcase
end
3'b110, 3'b111: begin
// 0: c.beqz -> beq rs1', x0, imm
// 1: c.bnez -> bne rs1', x0, imm
comp_instr = {{4 {i_instr[12]}}, i_instr[6:5], i_instr[2], 5'b0, 2'b01,
i_instr[9:7], 2'b00, i_instr[13], i_instr[11:10], i_instr[4:3],
i_instr[12], {OPCODE_BRANCH}};
end
endcase
end
// C2
// Register address checks for RV32E are performed in the regular instruction decoder.
// If this check fails, an illegal instruction exception is triggered and the controller
// writes the actual faulting instruction to mtval.
2'b10: begin
case (i_instr[15:14])
2'b00: begin
// c.slli -> slli rd, rd, shamt
// (c.ssli hints are translated into a slli hint)
comp_instr = {7'b0, i_instr[6:2], i_instr[11:7], 3'b001, i_instr[11:7], {OPCODE_OP_IMM}};
end
2'b01: begin
// c.lwsp -> lw rd, imm(x2)
comp_instr = {4'b0, i_instr[3:2], i_instr[12], i_instr[6:4], 2'b00, 5'h02,
3'b010, i_instr[11:7], OPCODE_LOAD};
end
2'b10: begin
if (i_instr[12] == 1'b0) begin
if (i_instr[6:2] != 5'b0) begin
// c.mv -> add rd/rs1, x0, rs2
// (c.mv hints are translated into an add hint)
comp_instr = {7'b0, i_instr[6:2], 5'b0, 3'b0, i_instr[11:7], {OPCODE_OP}};
end else begin
// c.jr -> jalr x0, rd/rs1, 0
comp_instr = {12'b0, i_instr[11:7], 3'b0, 5'b0, {OPCODE_JALR}};
end
end else begin
if (i_instr[6:2] != 5'b0) begin
// c.add -> add rd, rd, rs2
// (c.add hints are translated into an add hint)
comp_instr = {7'b0, i_instr[6:2], i_instr[11:7], 3'b0, i_instr[11:7], {OPCODE_OP}};
end else begin
if (i_instr[11:7] == 5'b0) begin
// c.ebreak -> ebreak
comp_instr = {32'h00_10_00_73};
end else begin
// c.jalr -> jalr x1, rs1, 0
comp_instr = {12'b0, i_instr[11:7], 3'b000, 5'b00001, {OPCODE_JALR}};
end
end
end
end
2'b11: begin
// c.swsp -> sw rs2, imm(x2)
comp_instr = {4'b0, i_instr[8:7], i_instr[12], i_instr[6:2], 5'h02, 3'b010,
i_instr[11:9], 2'b00, {OPCODE_STORE}};
end
endcase
end
// Incoming instruction is not compressed.
2'b11: illegal_instr = 1'b1;
endcase
end
endmodule

142
fw/rtl/serv/serv_csr.v vendored Normal file
View File

@ -0,0 +1,142 @@
`default_nettype none
module serv_csr
#(parameter RESET_STRATEGY = "MINI")
(
input wire i_clk,
input wire i_rst,
//State
input wire i_trig_irq,
input wire i_en,
input wire i_cnt0to3,
input wire i_cnt3,
input wire i_cnt7,
input wire i_cnt_done,
input wire i_mem_op,
input wire i_mtip,
input wire i_trap,
output reg o_new_irq,
//Control
input wire i_e_op,
input wire i_ebreak,
input wire i_mem_cmd,
input wire i_mstatus_en,
input wire i_mie_en,
input wire i_mcause_en,
input wire [1:0] i_csr_source,
input wire i_mret,
input wire i_csr_d_sel,
//Data
input wire i_rf_csr_out,
output wire o_csr_in,
input wire i_csr_imm,
input wire i_rs1,
output wire o_q);
localparam [1:0]
CSR_SOURCE_CSR = 2'b00,
CSR_SOURCE_EXT = 2'b01,
CSR_SOURCE_SET = 2'b10,
CSR_SOURCE_CLR = 2'b11;
reg mstatus_mie;
reg mstatus_mpie;
reg mie_mtie;
reg mcause31;
reg [3:0] mcause3_0;
wire mcause;
wire csr_in;
wire csr_out;
reg timer_irq_r;
wire d = i_csr_d_sel ? i_csr_imm : i_rs1;
assign csr_in = (i_csr_source == CSR_SOURCE_EXT) ? d :
(i_csr_source == CSR_SOURCE_SET) ? csr_out | d :
(i_csr_source == CSR_SOURCE_CLR) ? csr_out & ~d :
(i_csr_source == CSR_SOURCE_CSR) ? csr_out :
1'bx;
assign csr_out = (i_mstatus_en & mstatus_mie & i_cnt3) |
i_rf_csr_out |
(i_mcause_en & i_en & mcause);
assign o_q = csr_out;
wire timer_irq = i_mtip & mstatus_mie & mie_mtie;
assign mcause = i_cnt0to3 ? mcause3_0[0] : //[3:0]
i_cnt_done ? mcause31 //[31]
: 1'b0;
assign o_csr_in = csr_in;
always @(posedge i_clk) begin
if (i_trig_irq) begin
timer_irq_r <= timer_irq;
o_new_irq <= timer_irq & !timer_irq_r;
end
if (i_mie_en & i_cnt7)
mie_mtie <= csr_in;
/*
The mie bit in mstatus gets updated under three conditions
When a trap is taken, the bit is cleared
During an mret instruction, the bit is restored from mpie
During a mstatus CSR access instruction it's assigned when
bit 3 gets updated
These conditions are all mutually exclusibe
*/
if ((i_trap & i_cnt_done) | i_mstatus_en & i_cnt3 | i_mret)
mstatus_mie <= !i_trap & (i_mret ? mstatus_mpie : csr_in);
/*
Note: To save resources mstatus_mpie (mstatus bit 7) is not
readable or writable from sw
*/
if (i_trap & i_cnt_done)
mstatus_mpie <= mstatus_mie;
/*
The four lowest bits in mcause hold the exception code
These bits get updated under three conditions
During an mcause CSR access function, they are assigned when
bits 0 to 3 gets updated
During an external interrupt the exception code is set to
7, since SERV only support timer interrupts
During an exception, the exception code is assigned to indicate
if it was caused by an ebreak instruction (3),
ecall instruction (11), misaligned load (4), misaligned store (6)
or misaligned jump (0)
The expressions below are derived from the following truth table
irq => 0111 (timer=7)
e_op => x011 (ebreak=3, ecall=11)
mem => 01x0 (store=6, load=4)
ctrl => 0000 (jump=0)
*/
if (i_mcause_en & i_en & i_cnt0to3 | (i_trap & i_cnt_done)) begin
mcause3_0[3] <= (i_e_op & !i_ebreak) | (!i_trap & csr_in);
mcause3_0[2] <= o_new_irq | i_mem_op | (!i_trap & mcause3_0[3]);
mcause3_0[1] <= o_new_irq | i_e_op | (i_mem_op & i_mem_cmd) | (!i_trap & mcause3_0[2]);
mcause3_0[0] <= o_new_irq | i_e_op | (!i_trap & mcause3_0[1]);
end
if (i_mcause_en & i_cnt_done | i_trap)
mcause31 <= i_trap ? o_new_irq : csr_in;
if (i_rst)
if (RESET_STRATEGY != "NONE") begin
o_new_irq <= 1'b0;
mie_mtie <= 1'b0;
end
end
endmodule

84
fw/rtl/serv/serv_ctrl.v vendored Normal file
View File

@ -0,0 +1,84 @@
`default_nettype none
module serv_ctrl
#(parameter RESET_STRATEGY = "MINI",
parameter RESET_PC = 32'd0,
parameter WITH_CSR = 1)
(
input wire clk,
input wire i_rst,
//State
input wire i_pc_en,
input wire i_cnt12to31,
input wire i_cnt0,
input wire i_cnt1,
input wire i_cnt2,
//Control
input wire i_jump,
input wire i_jal_or_jalr,
input wire i_utype,
input wire i_pc_rel,
input wire i_trap,
input wire i_iscomp,
//Data
input wire i_imm,
input wire i_buf,
input wire i_csr_pc,
output wire o_rd,
output wire o_bad_pc,
//External
output reg [31:0] o_ibus_adr);
wire pc_plus_4;
wire pc_plus_4_cy;
reg pc_plus_4_cy_r;
wire pc_plus_offset;
wire pc_plus_offset_cy;
reg pc_plus_offset_cy_r;
wire pc_plus_offset_aligned;
wire plus_4;
wire pc = o_ibus_adr[0];
wire new_pc;
wire offset_a;
wire offset_b;
/* If i_iscomp=1: increment pc by 2 else increment pc by 4 */
assign plus_4 = i_iscomp ? i_cnt1 : i_cnt2;
assign o_bad_pc = pc_plus_offset_aligned;
assign {pc_plus_4_cy,pc_plus_4} = pc+plus_4+pc_plus_4_cy_r;
generate
if (|WITH_CSR) begin : gen_csr
assign new_pc = i_trap ? (i_csr_pc & !i_cnt0) : i_jump ? pc_plus_offset_aligned : pc_plus_4;
end else begin : gen_no_csr
assign new_pc = i_jump ? pc_plus_offset_aligned : pc_plus_4;
end
endgenerate
assign o_rd = (i_utype & pc_plus_offset_aligned) | (pc_plus_4 & i_jal_or_jalr);
assign offset_a = i_pc_rel & pc;
assign offset_b = i_utype ? (i_imm & i_cnt12to31): i_buf;
assign {pc_plus_offset_cy,pc_plus_offset} = offset_a+offset_b+pc_plus_offset_cy_r;
assign pc_plus_offset_aligned = pc_plus_offset & !i_cnt0;
initial if (RESET_STRATEGY == "NONE") o_ibus_adr = RESET_PC;
always @(posedge clk) begin
pc_plus_4_cy_r <= i_pc_en & pc_plus_4_cy;
pc_plus_offset_cy_r <= i_pc_en & pc_plus_offset_cy;
if (RESET_STRATEGY == "NONE") begin
if (i_pc_en)
o_ibus_adr <= {new_pc, o_ibus_adr[31:1]};
end else begin
if (i_pc_en | i_rst)
o_ibus_adr <= i_rst ? RESET_PC : {new_pc, o_ibus_adr[31:1]};
end
end
endmodule

365
fw/rtl/serv/serv_decode.v vendored Normal file
View File

@ -0,0 +1,365 @@
`default_nettype none
module serv_decode
#(parameter [0:0] PRE_REGISTER = 1,
parameter [0:0] MDU = 0)
(
input wire clk,
//Input
input wire [31:2] i_wb_rdt,
input wire i_wb_en,
//To state
output reg o_sh_right,
output reg o_bne_or_bge,
output reg o_cond_branch,
output reg o_e_op,
output reg o_ebreak,
output reg o_branch_op,
output reg o_shift_op,
output reg o_slt_or_branch,
output reg o_rd_op,
output reg o_two_stage_op,
output reg o_dbus_en,
//MDU
output reg o_mdu_op,
//Extension
output reg [2:0] o_ext_funct3,
//To bufreg
output reg o_bufreg_rs1_en,
output reg o_bufreg_imm_en,
output reg o_bufreg_clr_lsb,
output reg o_bufreg_sh_signed,
//To ctrl
output reg o_ctrl_jal_or_jalr,
output reg o_ctrl_utype,
output reg o_ctrl_pc_rel,
output reg o_ctrl_mret,
//To alu
output reg o_alu_sub,
output reg [1:0] o_alu_bool_op,
output reg o_alu_cmp_eq,
output reg o_alu_cmp_sig,
output reg [2:0] o_alu_rd_sel,
//To mem IF
output reg o_mem_signed,
output reg o_mem_word,
output reg o_mem_half,
output reg o_mem_cmd,
//To CSR
output reg o_csr_en,
output reg [1:0] o_csr_addr,
output reg o_csr_mstatus_en,
output reg o_csr_mie_en,
output reg o_csr_mcause_en,
output reg [1:0] o_csr_source,
output reg o_csr_d_sel,
output reg o_csr_imm_en,
output reg o_mtval_pc,
//To top
output reg [3:0] o_immdec_ctrl,
output reg [3:0] o_immdec_en,
output reg o_op_b_source,
//To RF IF
output reg o_rd_mem_en,
output reg o_rd_csr_en,
output reg o_rd_alu_en);
reg [4:0] opcode;
reg [2:0] funct3;
reg op20;
reg op21;
reg op22;
reg op26;
reg imm25;
reg imm30;
wire co_mdu_op = MDU & (opcode == 5'b01100) & imm25;
wire co_two_stage_op =
~opcode[2] | (funct3[0] & ~funct3[1] & ~opcode[0] & ~opcode[4]) |
(funct3[1] & ~funct3[2] & ~opcode[0] & ~opcode[4]) | co_mdu_op;
wire co_shift_op = (opcode[2] & ~funct3[1]) & !co_mdu_op;
wire co_slt_or_branch = (opcode[4] | (funct3[1] & opcode[2]) | (imm30 & opcode[2] & opcode[3] & ~funct3[2])) & !co_mdu_op;
wire co_branch_op = opcode[4];
wire co_dbus_en = ~opcode[2] & ~opcode[4];
wire co_mtval_pc = opcode[4];
wire co_mem_word = funct3[1];
wire co_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4] & !co_mdu_op;
wire co_rd_mem_en = (!opcode[2] & !opcode[0]) | co_mdu_op;
wire [2:0] co_ext_funct3 = funct3;
//jal,branch = imm
//jalr = rs1+imm
//mem = rs1+imm
//shift = rs1
wire co_bufreg_rs1_en = !opcode[4] | (!opcode[1] & opcode[0]);
wire co_bufreg_imm_en = !opcode[2];
//Clear LSB of immediate for BRANCH and JAL ops
//True for BRANCH and JAL
//False for JALR/LOAD/STORE/OP/OPIMM?
wire co_bufreg_clr_lsb = opcode[4] & ((opcode[1:0] == 2'b00) | (opcode[1:0] == 2'b11));
//Conditional branch
//True for BRANCH
//False for JAL/JALR
wire co_cond_branch = !opcode[0];
wire co_ctrl_utype = !opcode[4] & opcode[2] & opcode[0];
wire co_ctrl_jal_or_jalr = opcode[4] & opcode[0];
//PC-relative operations
//True for jal, b* auipc, ebreak
//False for jalr, lui
wire co_ctrl_pc_rel = (opcode[2:0] == 3'b000) |
(opcode[1:0] == 2'b11) |
(opcode[4] & opcode[2]) & op20|
(opcode[4:3] == 2'b00);
//Write to RD
//True for OP-IMM, AUIPC, OP, LUI, SYSTEM, JALR, JAL, LOAD
//False for STORE, BRANCH, MISC-MEM
wire co_rd_op = (opcode[2] |
(!opcode[2] & opcode[4] & opcode[0]) |
(!opcode[2] & !opcode[3] & !opcode[0]));
//
//funct3
//
wire co_sh_right = funct3[2];
wire co_bne_or_bge = funct3[0];
//Matches system ops except eceall/ebreak/mret
wire csr_op = opcode[4] & opcode[2] & (|funct3);
//op20
wire co_ebreak = op20;
//opcode & funct3 & op21
wire co_ctrl_mret = opcode[4] & opcode[2] & op21 & !(|funct3);
//Matches system opcodes except CSR accesses (funct3 == 0)
//and mret (!op21)
wire co_e_op = opcode[4] & opcode[2] & !op21 & !(|funct3);
//opcode & funct3 & imm30
wire co_bufreg_sh_signed = imm30;
/*
True for sub, b*, slt*
False for add*
op opcode f3 i30
b* 11000 xxx x t
addi 00100 000 x f
slt* 0x100 01x x t
add 01100 000 0 f
sub 01100 000 1 t
*/
wire co_alu_sub = funct3[1] | funct3[0] | (opcode[3] & imm30) | opcode[4];
/*
Bits 26, 22, 21 and 20 are enough to uniquely identify the eight supported CSR regs
mtvec, mscratch, mepc and mtval are stored externally (normally in the RF) and are
treated differently from mstatus, mie and mcause which are stored in serv_csr.
The former get a 2-bit address as seen below while the latter get a
one-hot enable signal each.
Hex|2 222|Reg |csr
adr|6 210|name |addr
---|-----|--------|----
300|0_000|mstatus | xx
304|0_100|mie | xx
305|0_101|mtvec | 01
340|1_000|mscratch| 00
341|1_001|mepc | 10
342|1_010|mcause | xx
343|1_011|mtval | 11
*/
//true for mtvec,mscratch,mepc and mtval
//false for mstatus, mie, mcause
wire csr_valid = op20 | (op26 & !op21);
wire co_rd_csr_en = csr_op;
wire co_csr_en = csr_op & csr_valid;
wire co_csr_mstatus_en = csr_op & !op26 & !op22;
wire co_csr_mie_en = csr_op & !op26 & op22 & !op20;
wire co_csr_mcause_en = csr_op & op21 & !op20;
wire [1:0] co_csr_source = funct3[1:0];
wire co_csr_d_sel = funct3[2];
wire co_csr_imm_en = opcode[4] & opcode[2] & funct3[2];
wire [1:0] co_csr_addr = {op26 & op20, !op26 | op21};
wire co_alu_cmp_eq = funct3[2:1] == 2'b00;
wire co_alu_cmp_sig = ~((funct3[0] & funct3[1]) | (funct3[1] & funct3[2]));
wire co_mem_cmd = opcode[3];
wire co_mem_signed = ~funct3[2];
wire co_mem_half = funct3[0];
wire [1:0] co_alu_bool_op = funct3[1:0];
wire [3:0] co_immdec_ctrl;
//True for S (STORE) or B (BRANCH) type instructions
//False for J type instructions
assign co_immdec_ctrl[0] = opcode[3:0] == 4'b1000;
//True for OP-IMM, LOAD, STORE, JALR (I S)
//False for LUI, AUIPC, JAL (U J)
assign co_immdec_ctrl[1] = (opcode[1:0] == 2'b00) | (opcode[2:1] == 2'b00);
assign co_immdec_ctrl[2] = opcode[4] & !opcode[0];
assign co_immdec_ctrl[3] = opcode[4];
wire [3:0] co_immdec_en;
assign co_immdec_en[3] = opcode[4] | opcode[3] | opcode[2] | !opcode[0]; //B I J S U
assign co_immdec_en[2] = (opcode[4] & opcode[2]) | !opcode[3] | opcode[0]; // I J U
assign co_immdec_en[1] = (opcode[2:1] == 2'b01) | (opcode[2] & opcode[0]) | co_csr_imm_en;// J U
assign co_immdec_en[0] = ~co_rd_op; //B S
wire [2:0] co_alu_rd_sel;
assign co_alu_rd_sel[0] = (funct3 == 3'b000); // Add/sub
assign co_alu_rd_sel[1] = (funct3[2:1] == 2'b01); //SLT*
assign co_alu_rd_sel[2] = funct3[2]; //Bool
//0 (OP_B_SOURCE_IMM) when OPIMM
//1 (OP_B_SOURCE_RS2) when BRANCH or OP
wire co_op_b_source = opcode[3];
generate
if (PRE_REGISTER) begin : gen_pre_register
always @(posedge clk) begin
if (i_wb_en) begin
funct3 <= i_wb_rdt[14:12];
imm30 <= i_wb_rdt[30];
imm25 <= i_wb_rdt[25];
opcode <= i_wb_rdt[6:2];
op20 <= i_wb_rdt[20];
op21 <= i_wb_rdt[21];
op22 <= i_wb_rdt[22];
op26 <= i_wb_rdt[26];
end
end
always @(*) begin
o_sh_right = co_sh_right;
o_bne_or_bge = co_bne_or_bge;
o_cond_branch = co_cond_branch;
o_dbus_en = co_dbus_en;
o_mtval_pc = co_mtval_pc;
o_two_stage_op = co_two_stage_op;
o_e_op = co_e_op;
o_ebreak = co_ebreak;
o_branch_op = co_branch_op;
o_shift_op = co_shift_op;
o_slt_or_branch = co_slt_or_branch;
o_rd_op = co_rd_op;
o_mdu_op = co_mdu_op;
o_ext_funct3 = co_ext_funct3;
o_bufreg_rs1_en = co_bufreg_rs1_en;
o_bufreg_imm_en = co_bufreg_imm_en;
o_bufreg_clr_lsb = co_bufreg_clr_lsb;
o_bufreg_sh_signed = co_bufreg_sh_signed;
o_ctrl_jal_or_jalr = co_ctrl_jal_or_jalr;
o_ctrl_utype = co_ctrl_utype;
o_ctrl_pc_rel = co_ctrl_pc_rel;
o_ctrl_mret = co_ctrl_mret;
o_alu_sub = co_alu_sub;
o_alu_bool_op = co_alu_bool_op;
o_alu_cmp_eq = co_alu_cmp_eq;
o_alu_cmp_sig = co_alu_cmp_sig;
o_alu_rd_sel = co_alu_rd_sel;
o_mem_signed = co_mem_signed;
o_mem_word = co_mem_word;
o_mem_half = co_mem_half;
o_mem_cmd = co_mem_cmd;
o_csr_en = co_csr_en;
o_csr_addr = co_csr_addr;
o_csr_mstatus_en = co_csr_mstatus_en;
o_csr_mie_en = co_csr_mie_en;
o_csr_mcause_en = co_csr_mcause_en;
o_csr_source = co_csr_source;
o_csr_d_sel = co_csr_d_sel;
o_csr_imm_en = co_csr_imm_en;
o_immdec_ctrl = co_immdec_ctrl;
o_immdec_en = co_immdec_en;
o_op_b_source = co_op_b_source;
o_rd_csr_en = co_rd_csr_en;
o_rd_alu_en = co_rd_alu_en;
o_rd_mem_en = co_rd_mem_en;
end
end else begin : gen_post_register
always @(*) begin
funct3 = i_wb_rdt[14:12];
imm30 = i_wb_rdt[30];
imm25 = i_wb_rdt[25];
opcode = i_wb_rdt[6:2];
op20 = i_wb_rdt[20];
op21 = i_wb_rdt[21];
op22 = i_wb_rdt[22];
op26 = i_wb_rdt[26];
end
always @(posedge clk) begin
if (i_wb_en) begin
o_sh_right <= co_sh_right;
o_bne_or_bge <= co_bne_or_bge;
o_cond_branch <= co_cond_branch;
o_e_op <= co_e_op;
o_ebreak <= co_ebreak;
o_two_stage_op <= co_two_stage_op;
o_dbus_en <= co_dbus_en;
o_mtval_pc <= co_mtval_pc;
o_branch_op <= co_branch_op;
o_shift_op <= co_shift_op;
o_slt_or_branch <= co_slt_or_branch;
o_rd_op <= co_rd_op;
o_mdu_op <= co_mdu_op;
o_ext_funct3 <= co_ext_funct3;
o_bufreg_rs1_en <= co_bufreg_rs1_en;
o_bufreg_imm_en <= co_bufreg_imm_en;
o_bufreg_clr_lsb <= co_bufreg_clr_lsb;
o_bufreg_sh_signed <= co_bufreg_sh_signed;
o_ctrl_jal_or_jalr <= co_ctrl_jal_or_jalr;
o_ctrl_utype <= co_ctrl_utype;
o_ctrl_pc_rel <= co_ctrl_pc_rel;
o_ctrl_mret <= co_ctrl_mret;
o_alu_sub <= co_alu_sub;
o_alu_bool_op <= co_alu_bool_op;
o_alu_cmp_eq <= co_alu_cmp_eq;
o_alu_cmp_sig <= co_alu_cmp_sig;
o_alu_rd_sel <= co_alu_rd_sel;
o_mem_signed <= co_mem_signed;
o_mem_word <= co_mem_word;
o_mem_half <= co_mem_half;
o_mem_cmd <= co_mem_cmd;
o_csr_en <= co_csr_en;
o_csr_addr <= co_csr_addr;
o_csr_mstatus_en <= co_csr_mstatus_en;
o_csr_mie_en <= co_csr_mie_en;
o_csr_mcause_en <= co_csr_mcause_en;
o_csr_source <= co_csr_source;
o_csr_d_sel <= co_csr_d_sel;
o_csr_imm_en <= co_csr_imm_en;
o_immdec_ctrl <= co_immdec_ctrl;
o_immdec_en <= co_immdec_en;
o_op_b_source <= co_op_b_source;
o_rd_csr_en <= co_rd_csr_en;
o_rd_alu_en <= co_rd_alu_en;
o_rd_mem_en <= co_rd_mem_en;
end
end
end
endgenerate
endmodule

95
fw/rtl/serv/serv_immdec.v vendored Normal file
View File

@ -0,0 +1,95 @@
`default_nettype none
module serv_immdec
#(parameter SHARED_RFADDR_IMM_REGS = 1)
(
input wire i_clk,
//State
input wire i_cnt_en,
input wire i_cnt_done,
//Control
input wire [3:0] i_immdec_en,
input wire i_csr_imm_en,
input wire [3:0] i_ctrl,
output wire [4:0] o_rd_addr,
output wire [4:0] o_rs1_addr,
output wire [4:0] o_rs2_addr,
//Data
output wire o_csr_imm,
output wire o_imm,
//External
input wire i_wb_en,
input wire [31:7] i_wb_rdt);
reg imm31;
reg [8:0] imm19_12_20;
reg imm7;
reg [5:0] imm30_25;
reg [4:0] imm24_20;
reg [4:0] imm11_7;
assign o_csr_imm = imm19_12_20[4];
wire signbit = imm31 & !i_csr_imm_en;
generate
if (SHARED_RFADDR_IMM_REGS) begin : gen_shared_imm_regs
assign o_rs1_addr = imm19_12_20[8:4];
assign o_rs2_addr = imm24_20;
assign o_rd_addr = imm11_7;
always @(posedge i_clk) begin
if (i_wb_en) begin
/* CSR immediates are always zero-extended, hence clear the signbit */
imm31 <= i_wb_rdt[31];
end
if (i_wb_en | (i_cnt_en & i_immdec_en[1]))
imm19_12_20 <= i_wb_en ? {i_wb_rdt[19:12],i_wb_rdt[20]} : {i_ctrl[3] ? signbit : imm24_20[0], imm19_12_20[8:1]};
if (i_wb_en | (i_cnt_en))
imm7 <= i_wb_en ? i_wb_rdt[7] : signbit;
if (i_wb_en | (i_cnt_en & i_immdec_en[3]))
imm30_25 <= i_wb_en ? i_wb_rdt[30:25] : {i_ctrl[2] ? imm7 : i_ctrl[1] ? signbit : imm19_12_20[0], imm30_25[5:1]};
if (i_wb_en | (i_cnt_en & i_immdec_en[2]))
imm24_20 <= i_wb_en ? i_wb_rdt[24:20] : {imm30_25[0], imm24_20[4:1]};
if (i_wb_en | (i_cnt_en & i_immdec_en[0]))
imm11_7 <= i_wb_en ? i_wb_rdt[11:7] : {imm30_25[0], imm11_7[4:1]};
end
end else begin : gen_separate_imm_regs
reg [4:0] rd_addr;
reg [4:0] rs1_addr;
reg [4:0] rs2_addr;
assign o_rd_addr = rd_addr;
assign o_rs1_addr = rs1_addr;
assign o_rs2_addr = rs2_addr;
always @(posedge i_clk) begin
if (i_wb_en) begin
/* CSR immediates are always zero-extended, hence clear the signbit */
imm31 <= i_wb_rdt[31];
imm19_12_20 <= {i_wb_rdt[19:12],i_wb_rdt[20]};
imm7 <= i_wb_rdt[7];
imm30_25 <= i_wb_rdt[30:25];
imm24_20 <= i_wb_rdt[24:20];
imm11_7 <= i_wb_rdt[11:7];
rd_addr <= i_wb_rdt[11:7];
rs1_addr <= i_wb_rdt[19:15];
rs2_addr <= i_wb_rdt[24:20];
end
if (i_cnt_en) begin
imm19_12_20 <= {i_ctrl[3] ? signbit : imm24_20[0], imm19_12_20[8:1]};
imm7 <= signbit;
imm30_25 <= {i_ctrl[2] ? imm7 : i_ctrl[1] ? signbit : imm19_12_20[0], imm30_25[5:1]};
imm24_20 <= {imm30_25[0], imm24_20[4:1]};
imm11_7 <= {imm30_25[0], imm11_7[4:1]};
end
end
end
endgenerate
assign o_imm = i_cnt_done ? signbit : i_ctrl[0] ? imm11_7[0] : imm24_20[0];
endmodule

69
fw/rtl/serv/serv_mem_if.v vendored Normal file
View File

@ -0,0 +1,69 @@
`default_nettype none
module serv_mem_if
#(
parameter [0:0] WITH_CSR = 1,
parameter W = 1,
parameter B = W-1
)
(
input wire i_clk,
//State
input wire [1:0] i_bytecnt,
input wire [1:0] i_lsb,
output wire o_byte_valid,
output wire o_misalign,
//Control
input wire i_signed,
input wire i_word,
input wire i_half,
//MDU
input wire i_mdu_op,
//Data
input wire [B:0] i_bufreg2_q,
output wire [B:0] o_rd,
//External interface
output wire [3:0] o_wb_sel);
reg signbit;
/*
Before a store operation, the data to be written needs to be shifted into
place. Depending on the address alignment, we need to shift different
amounts. One formula for calculating this is to say that we shift when
i_lsb + i_bytecnt < 4. Unfortunately, the synthesis tools don't seem to be
clever enough so the hideous expression below is used to achieve the same
thing in a more optimal way.
*/
assign o_byte_valid
= (!i_lsb[0] & !i_lsb[1]) |
(!i_bytecnt[0] & !i_bytecnt[1]) |
(!i_bytecnt[1] & !i_lsb[1]) |
(!i_bytecnt[1] & !i_lsb[0]) |
(!i_bytecnt[0] & !i_lsb[1]);
wire dat_valid =
i_mdu_op |
i_word |
(i_bytecnt == 2'b00) |
(i_half & !i_bytecnt[1]);
assign o_rd = dat_valid ? i_bufreg2_q : {W{i_signed & signbit}};
assign o_wb_sel[3] = (i_lsb == 2'b11) | i_word | (i_half & i_lsb[1]);
assign o_wb_sel[2] = (i_lsb == 2'b10) | i_word;
assign o_wb_sel[1] = (i_lsb == 2'b01) | i_word | (i_half & !i_lsb[1]);
assign o_wb_sel[0] = (i_lsb == 2'b00);
always @(posedge i_clk) begin
if (dat_valid)
signbit <= i_bufreg2_q[B];
end
/*
mem_misalign is checked after the init stage to decide whether to do a data
bus transaction or go to the trap state. It is only guaranteed to be correct
at this time
*/
assign o_misalign = WITH_CSR & ((i_lsb[0] & (i_word | i_half)) | (i_lsb[1] & i_word));
endmodule

149
fw/rtl/serv/serv_rf_if.v vendored Normal file
View File

@ -0,0 +1,149 @@
`default_nettype none
module serv_rf_if
#(parameter WITH_CSR = 1)
(//RF Interface
input wire i_cnt_en,
output wire [4+WITH_CSR:0] o_wreg0,
output wire [4+WITH_CSR:0] o_wreg1,
output wire o_wen0,
output wire o_wen1,
output wire o_wdata0,
output wire o_wdata1,
output wire [4+WITH_CSR:0] o_rreg0,
output wire [4+WITH_CSR:0] o_rreg1,
input wire i_rdata0,
input wire i_rdata1,
//Trap interface
input wire i_trap,
input wire i_mret,
input wire i_mepc,
input wire i_mtval_pc,
input wire i_bufreg_q,
input wire i_bad_pc,
output wire o_csr_pc,
//CSR interface
input wire i_csr_en,
input wire [1:0] i_csr_addr,
input wire i_csr,
output wire o_csr,
//RD write port
input wire i_rd_wen,
input wire [4:0] i_rd_waddr,
input wire i_ctrl_rd,
input wire i_alu_rd,
input wire i_rd_alu_en,
input wire i_csr_rd,
input wire i_rd_csr_en,
input wire i_mem_rd,
input wire i_rd_mem_en,
//RS1 read port
input wire [4:0] i_rs1_raddr,
output wire o_rs1,
//RS2 read port
input wire [4:0] i_rs2_raddr,
output wire o_rs2);
/*
********** Write side ***********
*/
wire rd_wen = i_rd_wen & (|i_rd_waddr);
generate
if (|WITH_CSR) begin : gen_csr
wire rd = (i_ctrl_rd ) |
(i_alu_rd & i_rd_alu_en) |
(i_csr_rd & i_rd_csr_en) |
(i_mem_rd & i_rd_mem_en);
wire mtval = i_mtval_pc ? i_bad_pc : i_bufreg_q;
assign o_wdata0 = i_trap ? mtval : rd;
assign o_wdata1 = i_trap ? i_mepc : i_csr;
/* Port 0 handles writes to mtval during traps and rd otherwise
* Port 1 handles writes to mepc during traps and csr accesses otherwise
*
* GPR registers are mapped to address 0-31 (bits 0xxxxx).
* Following that are four CSR registers
* mscratch 100000
* mtvec 100001
* mepc 100010
* mtval 100011
*/
assign o_wreg0 = i_trap ? {6'b100011} : {1'b0,i_rd_waddr};
assign o_wreg1 = i_trap ? {6'b100010} : {4'b1000,i_csr_addr};
assign o_wen0 = i_cnt_en & (i_trap | rd_wen);
assign o_wen1 = i_cnt_en & (i_trap | i_csr_en);
/*
********** Read side ***********
*/
//0 : RS1
//1 : RS2 / CSR
assign o_rreg0 = {1'b0, i_rs1_raddr};
/*
The address of the second read port (o_rreg1) can get assigned from four
different sources
Normal operations : i_rs2_raddr
CSR access : i_csr_addr
trap : MTVEC
mret : MEPC
Address 0-31 in the RF are assigned to the GPRs. After that follows the four
CSRs on addresses 32-35
32 MSCRATCH
33 MTVEC
34 MEPC
35 MTVAL
The expression below is an optimized version of this logic
*/
wire sel_rs2 = !(i_trap | i_mret | i_csr_en);
assign o_rreg1 = {~sel_rs2,
i_rs2_raddr[4:2] & {3{sel_rs2}},
{1'b0,i_trap} | {i_mret,1'b0} | ({2{i_csr_en}} & i_csr_addr) | ({2{sel_rs2}} & i_rs2_raddr[1:0])};
assign o_rs1 = i_rdata0;
assign o_rs2 = i_rdata1;
assign o_csr = i_rdata1 & i_csr_en;
assign o_csr_pc = i_rdata1;
end else begin : gen_no_csr
wire rd = (i_ctrl_rd ) |
(i_alu_rd & i_rd_alu_en) |
(i_mem_rd & i_rd_mem_en);
assign o_wdata0 = rd;
assign o_wdata1 = 1'b0;
assign o_wreg0 = i_rd_waddr;
assign o_wreg1 = 5'd0;
assign o_wen0 = i_cnt_en & rd_wen;
assign o_wen1 = 1'b0;
/*
********** Read side ***********
*/
assign o_rreg0 = i_rs1_raddr;
assign o_rreg1 = i_rs2_raddr;
assign o_rs1 = i_rdata0;
assign o_rs2 = i_rdata1;
assign o_csr = 1'b0;
assign o_csr_pc = 1'b0;
end // else: !if(WITH_CSR)
endgenerate
endmodule

45
fw/rtl/serv/serv_rf_ram.v vendored Normal file
View File

@ -0,0 +1,45 @@
module serv_rf_ram
#(parameter width=0,
parameter csr_regs=4,
parameter depth=32*(32+csr_regs)/width)
(input wire i_clk,
input wire [$clog2(depth)-1:0] i_waddr,
input wire [width-1:0] i_wdata,
input wire i_wen,
input wire [$clog2(depth)-1:0] i_raddr,
input wire i_ren,
output wire [width-1:0] o_rdata);
reg [width-1:0] memory [0:depth-1];
reg [width-1:0] rdata ;
always @(posedge i_clk) begin
if (i_wen)
memory[i_waddr] <= i_wdata;
rdata <= i_ren ? memory[i_raddr] : {width{1'bx}};
end
/* Reads from reg x0 needs to return 0
Check that the part of the read address corresponding to the register
is zero and gate the output
width LSB of reg index $clog2(width)
2 4 1
4 3 2
8 2 3
16 1 4
32 0 5
*/
reg regzero;
always @(posedge i_clk)
regzero <= !(|i_raddr[$clog2(depth)-1:5-$clog2(width)]);
assign o_rdata = rdata & ~{width{regzero}};
`ifdef SERV_CLEAR_RAM
integer i;
initial
for (i=0;i<depth;i=i+1)
memory[i] = {width{1'd0}};
`endif
endmodule

174
fw/rtl/serv/serv_rf_ram_if.v vendored Normal file
View File

@ -0,0 +1,174 @@
`default_nettype none
module serv_rf_ram_if
#(//Data width. Adjust to preferred width of SRAM data interface
parameter width=8,
//Select reset strategy.
// "MINI" for resetting minimally required FFs
// "NONE" for relying on FFs having a defined value on startup
parameter reset_strategy="MINI",
//Number of CSR registers. These are allocated after the normal
// GPR registers in the RAM.
parameter csr_regs=4,
//Internal parameters calculated from above values. Do not change
parameter raw=$clog2(32+csr_regs), //Register address width
parameter l2w=$clog2(width), //log2 of width
parameter aw=5+raw-l2w) //Address width
(
//SERV side
input wire i_clk,
input wire i_rst,
input wire i_wreq,
input wire i_rreq,
output wire o_ready,
input wire [raw-1:0] i_wreg0,
input wire [raw-1:0] i_wreg1,
input wire i_wen0,
input wire i_wen1,
input wire i_wdata0,
input wire i_wdata1,
input wire [raw-1:0] i_rreg0,
input wire [raw-1:0] i_rreg1,
output wire o_rdata0,
output wire o_rdata1,
//RAM side
output wire [aw-1:0] o_waddr,
output wire [width-1:0] o_wdata,
output wire o_wen,
output wire [aw-1:0] o_raddr,
output wire o_ren,
input wire [width-1:0] i_rdata);
reg rgnt;
assign o_ready = rgnt | i_wreq;
reg [4:0] rcnt;
reg rtrig1;
/*
********** Write side ***********
*/
wire [4:0] wcnt;
reg [width-1:0] wdata0_r;
reg [width-0:0] wdata1_r;
reg wen0_r;
reg wen1_r;
wire wtrig0;
wire wtrig1;
assign wtrig0 = rtrig1;
generate if (width == 2) begin : gen_w_eq_2
assign wtrig1 = wcnt[0];
end else begin : gen_w_neq_2
reg wtrig0_r;
always @(posedge i_clk) wtrig0_r <= wtrig0;
assign wtrig1 = wtrig0_r;
end
endgenerate
assign o_wdata = wtrig1 ?
wdata1_r[width-1:0] :
wdata0_r;
wire [raw-1:0] wreg = wtrig1 ? i_wreg1 : i_wreg0;
generate if (width == 32) begin : gen_w_eq_32
assign o_waddr = wreg;
end else begin : gen_w_neq_32
assign o_waddr = {wreg, wcnt[4:l2w]};
end
endgenerate
assign o_wen = (wtrig0 & wen0_r) | (wtrig1 & wen1_r);
assign wcnt = rcnt-4;
always @(posedge i_clk) begin
if (wcnt[0]) begin
wen0_r <= i_wen0;
wen1_r <= i_wen1;
end
wdata0_r <= {i_wdata0,wdata0_r[width-1:1]};
wdata1_r <= {i_wdata1,wdata1_r[width-0:1]};
end
/*
********** Read side ***********
*/
wire rtrig0;
wire [raw-1:0] rreg = rtrig0 ? i_rreg1 : i_rreg0;
generate if (width == 32) begin : gen_rreg_eq_32
assign o_raddr = rreg;
end else begin : gen_rreg_neq_32
assign o_raddr = {rreg, rcnt[4:l2w]};
end
endgenerate
reg [width-1:0] rdata0;
reg [width-2:0] rdata1;
reg rgate;
assign o_rdata0 = rdata0[0];
assign o_rdata1 = rtrig1 ? i_rdata[0] : rdata1[0];
assign rtrig0 = (rcnt[l2w-1:0] == 1);
generate if (width == 2) begin : gen_ren_w_eq_2
assign o_ren = rgate;
end else begin : gen_ren_w_neq_2
assign o_ren = rgate & (rcnt[l2w-1:1] == 0);
end
endgenerate
reg rreq_r;
generate if (width>2) begin : gen_rdata1_w_neq_2
always @(posedge i_clk) begin
rdata1 <= {1'b0,rdata1[width-2:1]}; //Optimize?
if (rtrig1)
rdata1[width-2:0] <= i_rdata[width-1:1];
end
end else begin : gen_rdata1_w_eq_2
always @(posedge i_clk) if (rtrig1) rdata1 <= i_rdata[1];
end
endgenerate
always @(posedge i_clk) begin
if (&rcnt | i_rreq)
rgate <= i_rreq;
rtrig1 <= rtrig0;
rcnt <= rcnt+5'd1;
if (i_rreq | i_wreq)
rcnt <= {3'd0,i_wreq,1'b0};
rreq_r <= i_rreq;
rgnt <= rreq_r;
rdata0 <= {1'b0,rdata0[width-1:1]};
if (rtrig0)
rdata0 <= i_rdata;
if (i_rst) begin
if (reset_strategy != "NONE") begin
rgate <= 1'b0;
rgnt <= 1'b0;
rreq_r <= 1'b0;
rcnt <= 5'd0;
end
end
end
endmodule

216
fw/rtl/serv/serv_rf_top.v vendored Normal file
View File

@ -0,0 +1,216 @@
`default_nettype none
module serv_rf_top
#(parameter RESET_PC = 32'd0,
/* COMPRESSED=1: Enable the compressed decoder and allowed misaligned jump of pc
COMPRESSED=0: Disable the compressed decoder and does not allow the misaligned jump of pc
*/
parameter [0:0] COMPRESSED = 0,
/*
ALIGN = 1: Fetch the aligned instruction by making two bus transactions if the misaligned address
is given to the instruction bus.
*/
parameter [0:0] ALIGN = COMPRESSED,
/* Multiplication and Division Unit
This parameter enables the interface for connecting SERV and MDU
*/
parameter [0:0] MDU = 0,
/* Register signals before or after the decoder
0 : Register after the decoder. Faster but uses more resources
1 : (default) Register before the decoder. Slower but uses less resources
*/
parameter PRE_REGISTER = 1,
/* Amount of reset applied to design
"NONE" : No reset at all. Relies on a POR to set correct initialization
values and that core isn't reset during runtime
"MINI" : Standard setting. Resets the minimal amount of FFs needed to
restart execution from the instruction at RESET_PC
*/
parameter RESET_STRATEGY = "MINI",
parameter WITH_CSR = 1,
parameter RF_WIDTH = 2,
parameter RF_L2D = $clog2((32+(WITH_CSR*4))*32/RF_WIDTH))
(
input wire clk,
input wire i_rst,
input wire i_timer_irq,
`ifdef RISCV_FORMAL
output wire rvfi_valid,
output wire [63:0] rvfi_order,
output wire [31:0] rvfi_insn,
output wire rvfi_trap,
output wire rvfi_halt,
output wire rvfi_intr,
output wire [1:0] rvfi_mode,
output wire [1:0] rvfi_ixl,
output wire [4:0] rvfi_rs1_addr,
output wire [4:0] rvfi_rs2_addr,
output wire [31:0] rvfi_rs1_rdata,
output wire [31:0] rvfi_rs2_rdata,
output wire [4:0] rvfi_rd_addr,
output wire [31:0] rvfi_rd_wdata,
output wire [31:0] rvfi_pc_rdata,
output wire [31:0] rvfi_pc_wdata,
output wire [31:0] rvfi_mem_addr,
output wire [3:0] rvfi_mem_rmask,
output wire [3:0] rvfi_mem_wmask,
output wire [31:0] rvfi_mem_rdata,
output wire [31:0] rvfi_mem_wdata,
`endif
output wire [31:0] o_ibus_adr,
output wire o_ibus_cyc,
input wire [31:0] i_ibus_rdt,
input wire i_ibus_ack,
output wire [31:0] o_dbus_adr,
output wire [31:0] o_dbus_dat,
output wire [3:0] o_dbus_sel,
output wire o_dbus_we ,
output wire o_dbus_cyc,
input wire [31:0] i_dbus_rdt,
input wire i_dbus_ack,
// Extension
output wire [31:0] o_ext_rs1,
output wire [31:0] o_ext_rs2,
output wire [ 2:0] o_ext_funct3,
input wire [31:0] i_ext_rd,
input wire i_ext_ready,
// MDU
output wire o_mdu_valid);
localparam CSR_REGS = WITH_CSR*4;
wire rf_wreq;
wire rf_rreq;
wire [4+WITH_CSR:0] wreg0;
wire [4+WITH_CSR:0] wreg1;
wire wen0;
wire wen1;
wire wdata0;
wire wdata1;
wire [4+WITH_CSR:0] rreg0;
wire [4+WITH_CSR:0] rreg1;
wire rf_ready;
wire rdata0;
wire rdata1;
wire [RF_L2D-1:0] waddr;
wire [RF_WIDTH-1:0] wdata;
wire wen;
wire [RF_L2D-1:0] raddr;
wire ren;
wire [RF_WIDTH-1:0] rdata;
serv_rf_ram_if
#(.width (RF_WIDTH),
.reset_strategy (RESET_STRATEGY),
.csr_regs (CSR_REGS))
rf_ram_if
(.i_clk (clk),
.i_rst (i_rst),
.i_wreq (rf_wreq),
.i_rreq (rf_rreq),
.o_ready (rf_ready),
.i_wreg0 (wreg0),
.i_wreg1 (wreg1),
.i_wen0 (wen0),
.i_wen1 (wen1),
.i_wdata0 (wdata0),
.i_wdata1 (wdata1),
.i_rreg0 (rreg0),
.i_rreg1 (rreg1),
.o_rdata0 (rdata0),
.o_rdata1 (rdata1),
.o_waddr (waddr),
.o_wdata (wdata),
.o_wen (wen),
.o_raddr (raddr),
.o_ren (ren),
.i_rdata (rdata));
serv_rf_ram
#(.width (RF_WIDTH),
.csr_regs (CSR_REGS))
rf_ram
(.i_clk (clk),
.i_waddr (waddr),
.i_wdata (wdata),
.i_wen (wen),
.i_raddr (raddr),
.i_ren (ren),
.o_rdata (rdata));
serv_top
#(.RESET_PC (RESET_PC),
.PRE_REGISTER (PRE_REGISTER),
.RESET_STRATEGY (RESET_STRATEGY),
.WITH_CSR (WITH_CSR),
.MDU(MDU),
.COMPRESSED(COMPRESSED),
.ALIGN(ALIGN))
cpu
(
.clk (clk),
.i_rst (i_rst),
.i_timer_irq (i_timer_irq),
`ifdef RISCV_FORMAL
.rvfi_valid (rvfi_valid ),
.rvfi_order (rvfi_order ),
.rvfi_insn (rvfi_insn ),
.rvfi_trap (rvfi_trap ),
.rvfi_halt (rvfi_halt ),
.rvfi_intr (rvfi_intr ),
.rvfi_mode (rvfi_mode ),
.rvfi_ixl (rvfi_ixl ),
.rvfi_rs1_addr (rvfi_rs1_addr ),
.rvfi_rs2_addr (rvfi_rs2_addr ),
.rvfi_rs1_rdata (rvfi_rs1_rdata),
.rvfi_rs2_rdata (rvfi_rs2_rdata),
.rvfi_rd_addr (rvfi_rd_addr ),
.rvfi_rd_wdata (rvfi_rd_wdata ),
.rvfi_pc_rdata (rvfi_pc_rdata ),
.rvfi_pc_wdata (rvfi_pc_wdata ),
.rvfi_mem_addr (rvfi_mem_addr ),
.rvfi_mem_rmask (rvfi_mem_rmask),
.rvfi_mem_wmask (rvfi_mem_wmask),
.rvfi_mem_rdata (rvfi_mem_rdata),
.rvfi_mem_wdata (rvfi_mem_wdata),
`endif
.o_rf_rreq (rf_rreq),
.o_rf_wreq (rf_wreq),
.i_rf_ready (rf_ready),
.o_wreg0 (wreg0),
.o_wreg1 (wreg1),
.o_wen0 (wen0),
.o_wen1 (wen1),
.o_wdata0 (wdata0),
.o_wdata1 (wdata1),
.o_rreg0 (rreg0),
.o_rreg1 (rreg1),
.i_rdata0 (rdata0),
.i_rdata1 (rdata1),
.o_ibus_adr (o_ibus_adr),
.o_ibus_cyc (o_ibus_cyc),
.i_ibus_rdt (i_ibus_rdt),
.i_ibus_ack (i_ibus_ack),
.o_dbus_adr (o_dbus_adr),
.o_dbus_dat (o_dbus_dat),
.o_dbus_sel (o_dbus_sel),
.o_dbus_we (o_dbus_we),
.o_dbus_cyc (o_dbus_cyc),
.i_dbus_rdt (i_dbus_rdt),
.i_dbus_ack (i_dbus_ack),
//Extension
.o_ext_funct3 (o_ext_funct3),
.i_ext_ready (i_ext_ready),
.i_ext_rd (i_ext_rd),
.o_ext_rs1 (o_ext_rs1),
.o_ext_rs2 (o_ext_rs2),
//MDU
.o_mdu_valid (o_mdu_valid));
endmodule
`default_nettype wire

224
fw/rtl/serv/serv_state.v vendored Normal file
View File

@ -0,0 +1,224 @@
module serv_state
#(parameter RESET_STRATEGY = "MINI",
parameter [0:0] WITH_CSR = 1,
parameter [0:0] ALIGN =0,
parameter [0:0] MDU = 0,
parameter W = 1
)
(
input wire i_clk,
input wire i_rst,
//State
input wire i_new_irq,
input wire i_alu_cmp,
output wire o_init,
output reg o_cnt_en,
output wire o_cnt0to3,
output wire o_cnt12to31,
output wire o_cnt0,
output wire o_cnt1,
output wire o_cnt2,
output wire o_cnt3,
output wire o_cnt7,
output wire o_cnt_done,
output wire o_bufreg_en,
output wire o_ctrl_pc_en,
output reg o_ctrl_jump,
output wire o_ctrl_trap,
input wire i_ctrl_misalign,
input wire i_sh_done,
input wire i_sh_done_r,
output wire [1:0] o_mem_bytecnt,
input wire i_mem_misalign,
//Control
input wire i_bne_or_bge,
input wire i_cond_branch,
input wire i_dbus_en,
input wire i_two_stage_op,
input wire i_branch_op,
input wire i_shift_op,
input wire i_sh_right,
input wire i_slt_or_branch,
input wire i_e_op,
input wire i_rd_op,
//MDU
input wire i_mdu_op,
output wire o_mdu_valid,
//Extension
input wire i_mdu_ready,
//External
output wire o_dbus_cyc,
input wire i_dbus_ack,
output wire o_ibus_cyc,
input wire i_ibus_ack,
//RF Interface
output wire o_rf_rreq,
output wire o_rf_wreq,
input wire i_rf_ready,
output wire o_rf_rd_en);
reg stage_two_req;
reg init_done;
wire misalign_trap_sync;
reg [4:2] o_cnt;
reg [3:0] cnt_r;
reg ibus_cyc;
//Update PC in RUN or TRAP states
assign o_ctrl_pc_en = o_cnt_en & !o_init;
assign o_mem_bytecnt = o_cnt[4:3];
assign o_cnt0to3 = (o_cnt[4:2] == 3'd0);
assign o_cnt12to31 = (o_cnt[4] | (o_cnt[3:2] == 2'b11));
assign o_cnt0 = (o_cnt[4:2] == 3'd0) & cnt_r[0];
assign o_cnt1 = (o_cnt[4:2] == 3'd0) & cnt_r[1];
assign o_cnt2 = (o_cnt[4:2] == 3'd0) & cnt_r[2];
assign o_cnt3 = (o_cnt[4:2] == 3'd0) & cnt_r[3];
assign o_cnt7 = (o_cnt[4:2] == 3'd1) & cnt_r[3];
//Take branch for jump or branch instructions (opcode == 1x0xx) if
//a) It's an unconditional branch (opcode[0] == 1)
//b) It's a conditional branch (opcode[0] == 0) of type beq,blt,bltu (funct3[0] == 0) and ALU compare is true
//c) It's a conditional branch (opcode[0] == 0) of type bne,bge,bgeu (funct3[0] == 1) and ALU compare is false
//Only valid during the last cycle of INIT, when the branch condition has
//been calculated.
wire take_branch = i_branch_op & (!i_cond_branch | (i_alu_cmp^i_bne_or_bge));
//valid signal for mdu
assign o_mdu_valid = MDU & !o_cnt_en & init_done & i_mdu_op;
//Prepare RF for writes when everything is ready to enter stage two
// and the first stage didn't cause a misalign exception
assign o_rf_wreq = !misalign_trap_sync & !o_cnt_en & init_done &
((i_shift_op & (i_sh_done | !i_sh_right)) |
i_dbus_ack | (MDU & i_mdu_ready) |
i_slt_or_branch);
assign o_dbus_cyc = !o_cnt_en & init_done & i_dbus_en & !i_mem_misalign;
//Prepare RF for reads when a new instruction is fetched
// or when stage one caused an exception (rreq implies a write request too)
assign o_rf_rreq = i_ibus_ack | (stage_two_req & misalign_trap_sync);
assign o_rf_rd_en = i_rd_op & !o_init;
/*
bufreg is used during mem. branch and shift operations
mem : bufreg is used for dbus address. Shift in data during phase 1.
Shift out during phase 2 if there was an misalignment exception.
branch : Shift in during phase 1. Shift out during phase 2
shift : Shift in during phase 1. Continue shifting between phases (except
for the first cycle after init). Shift out during phase 2
*/
assign o_bufreg_en = (o_cnt_en & (o_init | ((o_ctrl_trap | i_branch_op) & i_two_stage_op))) | (i_shift_op & !stage_two_req & (i_sh_right | i_sh_done_r) & init_done);
assign o_ibus_cyc = ibus_cyc & !i_rst;
assign o_init = i_two_stage_op & !i_new_irq & !init_done;
assign o_cnt_done = (o_cnt[4:2] == 3'b111) & cnt_r[3];
always @(posedge i_clk) begin
//ibus_cyc changes on three conditions.
//1. i_rst is asserted. Together with the async gating above, o_ibus_cyc
// will be asserted as soon as the reset is released. This is how the
// first instruction is fetced
//2. o_cnt_done and o_ctrl_pc_en are asserted. This means that SERV just
// finished updating the PC, is done with the current instruction and
// o_ibus_cyc gets asserted to fetch a new instruction
//3. When i_ibus_ack, a new instruction is fetched and o_ibus_cyc gets
// deasserted to finish the transaction
if (i_ibus_ack | o_cnt_done | i_rst)
ibus_cyc <= o_ctrl_pc_en | i_rst;
if (o_cnt_done) begin
init_done <= o_init & !init_done;
o_ctrl_jump <= o_init & take_branch;
end
//Need a strobe for the first cycle in the IDLE state after INIT
stage_two_req <= o_cnt_done & o_init;
if (i_rst) begin
if (RESET_STRATEGY != "NONE") begin
init_done <= 1'b0;
o_ctrl_jump <= 1'b0;
stage_two_req <= 1'b0;
end
end
end
always @(posedge i_clk) begin
/*
Because SERV is 32-bit bit-serial we need a counter than can count 0-31
to keep track of which bit we are currently processing. o_cnt and cnt_r
are used together to create such a counter.
The top three bits (o_cnt) are implemented as a normal counter, but
instead of the two LSB, cnt_r is a 4-bit shift register which loops 0-3
When cnt_r[3] is 1, o_cnt will be increased.
The counting starts when the core is idle and the i_rf_ready signal
comes in from the RF module by shifting in the i_rf_ready bit as LSB of
the shift register. Counting is stopped by using o_cnt_done to block the
bit that was supposed to be shifted into bit 0 of cnt_r.
There are two benefit of doing the counter this way
1. We only need to check four bits instead of five when we want to check
if the counter is at a certain value. For 4-LUT architectures this means
we only need one LUT instead of two for each comparison.
2. We don't need a separate enable signal to turn on and off the counter
between stages, which saves an extra FF and a unique control signal. We
just need to check if cnt_r is not zero to see if the counter is
currently running
*/
if (W == 4) begin
if (i_rf_ready) o_cnt_en <= 1; else
if (o_cnt_done) o_cnt_en <= 0;
o_cnt <= o_cnt + { 2'b0, o_cnt_en };
end else if (W == 1) begin
o_cnt <= o_cnt + {2'd0,cnt_r[3]};
cnt_r <= {cnt_r[2:0],(cnt_r[3] & !o_cnt_done) | (i_rf_ready & !o_cnt_en)};
end
if (i_rst) begin
if (RESET_STRATEGY != "NONE") begin
o_cnt <= 3'd0;
if (W == 1)
cnt_r <= 4'b0000;
else if (W == 4)
o_cnt_en <= 1'b0;
end
end
end
always @(*)
if (W == 1)
o_cnt_en = |cnt_r;
else if (W == 4)
cnt_r = 4'b1111;
assign o_ctrl_trap = WITH_CSR & (i_e_op | i_new_irq | misalign_trap_sync);
generate
if (WITH_CSR) begin : gen_csr
reg misalign_trap_sync_r;
//trap_pending is only guaranteed to have correct value during the
// last cycle of the init stage
wire trap_pending = WITH_CSR & ((take_branch & i_ctrl_misalign & !ALIGN) |
(i_dbus_en & i_mem_misalign));
always @(posedge i_clk) begin
if (i_ibus_ack | o_cnt_done | i_rst)
misalign_trap_sync_r <= !(i_ibus_ack | i_rst) & ((trap_pending & o_init) | misalign_trap_sync_r);
end
assign misalign_trap_sync = misalign_trap_sync_r;
end else begin : gen_no_csr
assign misalign_trap_sync = 1'b0;
end
endgenerate
endmodule

659
fw/rtl/serv/serv_top.v vendored Normal file
View File

@ -0,0 +1,659 @@
`default_nettype none
module serv_top
#(parameter WITH_CSR = 1,
parameter PRE_REGISTER = 1,
parameter RESET_STRATEGY = "MINI",
parameter RESET_PC = 32'd0,
parameter [0:0] MDU = 1'b0,
parameter [0:0] COMPRESSED=0,
parameter [0:0] ALIGN = COMPRESSED)
(
input wire clk,
input wire i_rst,
input wire i_timer_irq,
`ifdef RISCV_FORMAL
output reg rvfi_valid = 1'b0,
output reg [63:0] rvfi_order = 64'd0,
output reg [31:0] rvfi_insn = 32'd0,
output reg rvfi_trap = 1'b0,
output reg rvfi_halt = 1'b0,
output reg rvfi_intr = 1'b0,
output reg [1:0] rvfi_mode = 2'b11,
output reg [1:0] rvfi_ixl = 2'b01,
output reg [4:0] rvfi_rs1_addr,
output reg [4:0] rvfi_rs2_addr,
output reg [31:0] rvfi_rs1_rdata,
output reg [31:0] rvfi_rs2_rdata,
output reg [4:0] rvfi_rd_addr,
output reg [31:0] rvfi_rd_wdata,
output reg [31:0] rvfi_pc_rdata,
output reg [31:0] rvfi_pc_wdata,
output reg [31:0] rvfi_mem_addr,
output reg [3:0] rvfi_mem_rmask,
output reg [3:0] rvfi_mem_wmask,
output reg [31:0] rvfi_mem_rdata,
output reg [31:0] rvfi_mem_wdata,
`endif
//RF Interface
output wire o_rf_rreq,
output wire o_rf_wreq,
input wire i_rf_ready,
output wire [4+WITH_CSR:0] o_wreg0,
output wire [4+WITH_CSR:0] o_wreg1,
output wire o_wen0,
output wire o_wen1,
output wire o_wdata0,
output wire o_wdata1,
output wire [4+WITH_CSR:0] o_rreg0,
output wire [4+WITH_CSR:0] o_rreg1,
input wire i_rdata0,
input wire i_rdata1,
output wire [31:0] o_ibus_adr,
output wire o_ibus_cyc,
input wire [31:0] i_ibus_rdt,
input wire i_ibus_ack,
output wire [31:0] o_dbus_adr,
output wire [31:0] o_dbus_dat,
output wire [3:0] o_dbus_sel,
output wire o_dbus_we ,
output wire o_dbus_cyc,
input wire [31:0] i_dbus_rdt,
input wire i_dbus_ack,
//Extension
output wire [ 2:0] o_ext_funct3,
input wire i_ext_ready,
input wire [31:0] i_ext_rd,
output wire [31:0] o_ext_rs1,
output wire [31:0] o_ext_rs2,
//MDU
output wire o_mdu_valid);
wire [4:0] rd_addr;
wire [4:0] rs1_addr;
wire [4:0] rs2_addr;
wire [3:0] immdec_ctrl;
wire [3:0] immdec_en;
wire sh_right;
wire bne_or_bge;
wire cond_branch;
wire two_stage_op;
wire e_op;
wire ebreak;
wire branch_op;
wire shift_op;
wire slt_or_branch;
wire rd_op;
wire mdu_op;
wire rd_alu_en;
wire rd_csr_en;
wire rd_mem_en;
wire ctrl_rd;
wire alu_rd;
wire mem_rd;
wire csr_rd;
wire mtval_pc;
wire ctrl_pc_en;
wire jump;
wire jal_or_jalr;
wire utype;
wire mret;
wire imm;
wire trap;
wire pc_rel;
wire iscomp;
wire init;
wire cnt_en;
wire cnt0to3;
wire cnt12to31;
wire cnt0;
wire cnt1;
wire cnt2;
wire cnt3;
wire cnt7;
wire cnt_done;
wire bufreg_en;
wire bufreg_sh_signed;
wire bufreg_rs1_en;
wire bufreg_imm_en;
wire bufreg_clr_lsb;
wire bufreg_q;
wire bufreg2_q;
wire [31:0] dbus_rdt;
wire dbus_ack;
wire alu_sub;
wire [1:0] alu_bool_op;
wire alu_cmp_eq;
wire alu_cmp_sig;
wire alu_cmp;
wire [2:0] alu_rd_sel;
wire rs1;
wire rs2;
wire rd_en;
wire op_b;
wire op_b_sel;
wire mem_signed;
wire mem_word;
wire mem_half;
wire [1:0] mem_bytecnt;
wire sh_done;
wire sh_done_r;
wire byte_valid;
wire mem_misalign;
wire bad_pc;
wire csr_mstatus_en;
wire csr_mie_en;
wire csr_mcause_en;
wire [1:0] csr_source;
wire csr_imm;
wire csr_d_sel;
wire csr_en;
wire [1:0] csr_addr;
wire csr_pc;
wire csr_imm_en;
wire csr_in;
wire rf_csr_out;
wire dbus_en;
wire new_irq;
wire [1:0] lsb;
wire [31:0] i_wb_rdt;
wire [31:0] wb_ibus_adr;
wire wb_ibus_cyc;
wire [31:0] wb_ibus_rdt;
wire wb_ibus_ack;
generate
if (ALIGN) begin : gen_align
serv_aligner align
(
.clk(clk),
.rst(i_rst),
// serv_rf_top
.i_ibus_adr(wb_ibus_adr),
.i_ibus_cyc(wb_ibus_cyc),
.o_ibus_rdt(wb_ibus_rdt),
.o_ibus_ack(wb_ibus_ack),
// servant_arbiter
.o_wb_ibus_adr(o_ibus_adr),
.o_wb_ibus_cyc(o_ibus_cyc),
.i_wb_ibus_rdt(i_ibus_rdt),
.i_wb_ibus_ack(i_ibus_ack));
end else begin : gen_no_align
assign o_ibus_adr = wb_ibus_adr;
assign o_ibus_cyc = wb_ibus_cyc;
assign wb_ibus_rdt = i_ibus_rdt;
assign wb_ibus_ack = i_ibus_ack;
end
endgenerate
generate
if (COMPRESSED) begin : gen_compressed
serv_compdec compdec
(
.i_clk(clk),
.i_instr(wb_ibus_rdt),
.i_ack(wb_ibus_ack),
.o_instr(i_wb_rdt),
.o_iscomp(iscomp));
end else begin : gen_no_compressed
assign i_wb_rdt = wb_ibus_rdt;
assign iscomp = 1'b0;
end
endgenerate
serv_state
#(.RESET_STRATEGY (RESET_STRATEGY),
.WITH_CSR (WITH_CSR[0:0]),
.MDU(MDU),
.ALIGN(ALIGN))
state
(
.i_clk (clk),
.i_rst (i_rst),
//State
.i_new_irq (new_irq),
.i_alu_cmp (alu_cmp),
.o_init (init),
.o_cnt_en (cnt_en),
.o_cnt0to3 (cnt0to3),
.o_cnt12to31 (cnt12to31),
.o_cnt0 (cnt0),
.o_cnt1 (cnt1),
.o_cnt2 (cnt2),
.o_cnt3 (cnt3),
.o_cnt7 (cnt7),
.o_cnt_done (cnt_done),
.o_bufreg_en (bufreg_en),
.o_ctrl_pc_en (ctrl_pc_en),
.o_ctrl_jump (jump),
.o_ctrl_trap (trap),
.i_ctrl_misalign(lsb[1]),
.i_sh_done (sh_done),
.i_sh_done_r (sh_done_r),
.o_mem_bytecnt (mem_bytecnt),
.i_mem_misalign (mem_misalign),
//Control
.i_bne_or_bge (bne_or_bge),
.i_cond_branch (cond_branch),
.i_dbus_en (dbus_en),
.i_two_stage_op (two_stage_op),
.i_branch_op (branch_op),
.i_shift_op (shift_op),
.i_sh_right (sh_right),
.i_slt_or_branch (slt_or_branch),
.i_e_op (e_op),
.i_rd_op (rd_op),
//MDU
.i_mdu_op (mdu_op),
.o_mdu_valid (o_mdu_valid),
//Extension
.i_mdu_ready (i_ext_ready),
//External
.o_dbus_cyc (o_dbus_cyc),
.i_dbus_ack (i_dbus_ack),
.o_ibus_cyc (wb_ibus_cyc),
.i_ibus_ack (wb_ibus_ack),
//RF Interface
.o_rf_rreq (o_rf_rreq),
.o_rf_wreq (o_rf_wreq),
.i_rf_ready (i_rf_ready),
.o_rf_rd_en (rd_en));
serv_decode
#(.PRE_REGISTER (PRE_REGISTER),
.MDU(MDU))
decode
(
.clk (clk),
//Input
.i_wb_rdt (i_wb_rdt[31:2]),
.i_wb_en (wb_ibus_ack),
//To state
.o_bne_or_bge (bne_or_bge),
.o_cond_branch (cond_branch),
.o_dbus_en (dbus_en),
.o_e_op (e_op),
.o_ebreak (ebreak),
.o_branch_op (branch_op),
.o_shift_op (shift_op),
.o_slt_or_branch (slt_or_branch),
.o_rd_op (rd_op),
.o_sh_right (sh_right),
.o_mdu_op (mdu_op),
.o_two_stage_op (two_stage_op),
//Extension
.o_ext_funct3 (o_ext_funct3),
//To bufreg
.o_bufreg_rs1_en (bufreg_rs1_en),
.o_bufreg_imm_en (bufreg_imm_en),
.o_bufreg_clr_lsb (bufreg_clr_lsb),
.o_bufreg_sh_signed (bufreg_sh_signed),
//To bufreg2
.o_op_b_source (op_b_sel),
//To ctrl
.o_ctrl_jal_or_jalr (jal_or_jalr),
.o_ctrl_utype (utype),
.o_ctrl_pc_rel (pc_rel),
.o_ctrl_mret (mret),
//To alu
.o_alu_sub (alu_sub),
.o_alu_bool_op (alu_bool_op),
.o_alu_cmp_eq (alu_cmp_eq),
.o_alu_cmp_sig (alu_cmp_sig),
.o_alu_rd_sel (alu_rd_sel),
//To mem IF
.o_mem_cmd (o_dbus_we),
.o_mem_signed (mem_signed),
.o_mem_word (mem_word),
.o_mem_half (mem_half),
//To CSR
.o_csr_en (csr_en),
.o_csr_addr (csr_addr),
.o_csr_mstatus_en (csr_mstatus_en),
.o_csr_mie_en (csr_mie_en),
.o_csr_mcause_en (csr_mcause_en),
.o_csr_source (csr_source),
.o_csr_d_sel (csr_d_sel),
.o_csr_imm_en (csr_imm_en),
.o_mtval_pc (mtval_pc ),
//To top
.o_immdec_ctrl (immdec_ctrl),
.o_immdec_en (immdec_en),
//To RF IF
.o_rd_mem_en (rd_mem_en),
.o_rd_csr_en (rd_csr_en),
.o_rd_alu_en (rd_alu_en));
serv_immdec immdec
(
.i_clk (clk),
//State
.i_cnt_en (cnt_en),
.i_cnt_done (cnt_done),
//Control
.i_immdec_en (immdec_en),
.i_csr_imm_en (csr_imm_en),
.i_ctrl (immdec_ctrl),
.o_rd_addr (rd_addr),
.o_rs1_addr (rs1_addr),
.o_rs2_addr (rs2_addr),
//Data
.o_csr_imm (csr_imm),
.o_imm (imm),
//External
.i_wb_en (wb_ibus_ack),
.i_wb_rdt (i_wb_rdt[31:7]));
serv_bufreg
#(.MDU(MDU))
bufreg
(
.i_clk (clk),
//State
.i_cnt0 (cnt0),
.i_cnt1 (cnt1),
.i_en (bufreg_en),
.i_init (init),
.i_mdu_op (mdu_op),
.o_lsb (lsb),
//Control
.i_sh_signed (bufreg_sh_signed),
.i_rs1_en (bufreg_rs1_en),
.i_imm_en (bufreg_imm_en),
.i_clr_lsb (bufreg_clr_lsb),
//Data
.i_rs1 (rs1),
.i_imm (imm),
.o_q (bufreg_q),
//External
.o_dbus_adr (o_dbus_adr),
.o_ext_rs1 (o_ext_rs1));
serv_bufreg2 bufreg2
(
.i_clk (clk),
//State
.i_en (cnt_en),
.i_init (init),
.i_cnt_done (cnt_done),
.i_lsb (lsb),
.i_byte_valid (byte_valid),
.o_sh_done (sh_done),
.o_sh_done_r (sh_done_r),
//Control
.i_op_b_sel (op_b_sel),
.i_shift_op (shift_op),
//Data
.i_rs2 (rs2),
.i_imm (imm),
.o_op_b (op_b),
.o_q (bufreg2_q),
//External
.o_dat (o_dbus_dat),
.i_load (dbus_ack),
.i_dat (dbus_rdt));
serv_ctrl
#(.RESET_PC (RESET_PC),
.RESET_STRATEGY (RESET_STRATEGY),
.WITH_CSR (WITH_CSR))
ctrl
(
.clk (clk),
.i_rst (i_rst),
//State
.i_pc_en (ctrl_pc_en),
.i_cnt12to31 (cnt12to31),
.i_cnt0 (cnt0),
.i_cnt1 (cnt1),
.i_cnt2 (cnt2),
//Control
.i_jump (jump),
.i_jal_or_jalr (jal_or_jalr),
.i_utype (utype),
.i_pc_rel (pc_rel),
.i_trap (trap | mret),
.i_iscomp (iscomp),
//Data
.i_imm (imm),
.i_buf (bufreg_q),
.i_csr_pc (csr_pc),
.o_rd (ctrl_rd),
.o_bad_pc (bad_pc),
//External
.o_ibus_adr (wb_ibus_adr));
serv_alu alu
(
.clk (clk),
//State
.i_en (cnt_en),
.i_cnt0 (cnt0),
.o_cmp (alu_cmp),
//Control
.i_sub (alu_sub),
.i_bool_op (alu_bool_op),
.i_cmp_eq (alu_cmp_eq),
.i_cmp_sig (alu_cmp_sig),
.i_rd_sel (alu_rd_sel),
//Data
.i_rs1 (rs1),
.i_op_b (op_b),
.i_buf (bufreg_q),
.o_rd (alu_rd));
serv_rf_if
#(.WITH_CSR (WITH_CSR))
rf_if
(//RF interface
.i_cnt_en (cnt_en),
.o_wreg0 (o_wreg0),
.o_wreg1 (o_wreg1),
.o_wen0 (o_wen0),
.o_wen1 (o_wen1),
.o_wdata0 (o_wdata0),
.o_wdata1 (o_wdata1),
.o_rreg0 (o_rreg0),
.o_rreg1 (o_rreg1),
.i_rdata0 (i_rdata0),
.i_rdata1 (i_rdata1),
//Trap interface
.i_trap (trap),
.i_mret (mret),
.i_mepc (wb_ibus_adr[0]),
.i_mtval_pc (mtval_pc),
.i_bufreg_q (bufreg_q),
.i_bad_pc (bad_pc),
.o_csr_pc (csr_pc),
//CSR write port
.i_csr_en (csr_en),
.i_csr_addr (csr_addr),
.i_csr (csr_in),
//RD write port
.i_rd_wen (rd_en),
.i_rd_waddr (rd_addr),
.i_ctrl_rd (ctrl_rd),
.i_alu_rd (alu_rd),
.i_rd_alu_en (rd_alu_en),
.i_csr_rd (csr_rd),
.i_rd_csr_en (rd_csr_en),
.i_mem_rd (mem_rd),
.i_rd_mem_en (rd_mem_en),
//RS1 read port
.i_rs1_raddr (rs1_addr),
.o_rs1 (rs1),
//RS2 read port
.i_rs2_raddr (rs2_addr),
.o_rs2 (rs2),
//CSR read port
.o_csr (rf_csr_out));
serv_mem_if
#(.WITH_CSR (WITH_CSR[0:0]))
mem_if
(
.i_clk (clk),
//State
.i_bytecnt (mem_bytecnt),
.i_lsb (lsb),
.o_byte_valid (byte_valid),
.o_misalign (mem_misalign),
//Control
.i_mdu_op (mdu_op),
.i_signed (mem_signed),
.i_word (mem_word),
.i_half (mem_half),
//Data
.i_bufreg2_q (bufreg2_q),
.o_rd (mem_rd),
//External interface
.o_wb_sel (o_dbus_sel));
generate
if (|WITH_CSR) begin : gen_csr
serv_csr
#(.RESET_STRATEGY (RESET_STRATEGY))
csr
(
.i_clk (clk),
.i_rst (i_rst),
//State
.i_trig_irq (wb_ibus_ack),
.i_en (cnt_en),
.i_cnt0to3 (cnt0to3),
.i_cnt3 (cnt3),
.i_cnt7 (cnt7),
.i_cnt_done (cnt_done),
.i_mem_op (!mtval_pc),
.i_mtip (i_timer_irq),
.i_trap (trap),
.o_new_irq (new_irq),
//Control
.i_e_op (e_op),
.i_ebreak (ebreak),
.i_mem_cmd (o_dbus_we),
.i_mstatus_en (csr_mstatus_en),
.i_mie_en (csr_mie_en ),
.i_mcause_en (csr_mcause_en ),
.i_csr_source (csr_source),
.i_mret (mret),
.i_csr_d_sel (csr_d_sel),
//Data
.i_rf_csr_out (rf_csr_out),
.o_csr_in (csr_in),
.i_csr_imm (csr_imm),
.i_rs1 (rs1),
.o_q (csr_rd));
end else begin : gen_no_csr
assign csr_in = 1'b0;
assign csr_rd = 1'b0;
assign new_irq = 1'b0;
end
endgenerate
`ifdef RISCV_FORMAL
reg [31:0] pc = RESET_PC;
wire rs_en = two_stage_op ? init : ctrl_pc_en;
always @(posedge clk) begin
/* End of instruction */
rvfi_valid <= cnt_done & ctrl_pc_en & !i_rst;
rvfi_order <= rvfi_order + {63'd0,rvfi_valid};
/* Get instruction word when it's fetched from ibus */
if (wb_ibus_cyc & wb_ibus_ack)
rvfi_insn <= i_wb_rdt;
/* Store data written to rd */
if (o_wen0)
rvfi_rd_wdata <= {o_wdata0,rvfi_rd_wdata[31:1]};
if (cnt_done & ctrl_pc_en) begin
rvfi_pc_rdata <= pc;
if (!(rd_en & (|rd_addr))) begin
rvfi_rd_addr <= 5'd0;
rvfi_rd_wdata <= 32'd0;
end
end
rvfi_trap <= trap;
if (rvfi_valid) begin
rvfi_trap <= 1'b0;
pc <= rvfi_pc_wdata;
end
/* Not used */
rvfi_halt <= 1'b0;
rvfi_intr <= 1'b0;
rvfi_mode <= 2'd3;
rvfi_ixl = 2'd1;
/* RS1 not valid during J, U instructions (immdec_en[1]) */
/* RS2 not valid during I, J, U instructions (immdec_en[2]) */
if (i_rf_ready) begin
rvfi_rs1_addr <= !immdec_en[1] ? rs1_addr : 5'd0;
rvfi_rs2_addr <= !immdec_en[2] /*rs2_valid*/ ? rs2_addr : 5'd0;
rvfi_rd_addr <= rd_addr;
end
if (rs_en) begin
rvfi_rs1_rdata <= {!immdec_en[1] & rs1,rvfi_rs1_rdata[31:1]};
rvfi_rs2_rdata <= {!immdec_en[2] & rs2,rvfi_rs2_rdata[31:1]};
end
if (i_dbus_ack) begin
rvfi_mem_addr <= o_dbus_adr;
rvfi_mem_rmask <= o_dbus_we ? 4'b0000 : o_dbus_sel;
rvfi_mem_wmask <= o_dbus_we ? o_dbus_sel : 4'b0000;
rvfi_mem_rdata <= i_dbus_rdt;
rvfi_mem_wdata <= o_dbus_dat;
end
if (wb_ibus_ack) begin
rvfi_mem_rmask <= 4'b0000;
rvfi_mem_wmask <= 4'b0000;
end
end
/* verilator lint_off COMBDLY */
always @(wb_ibus_adr)
rvfi_pc_wdata <= wb_ibus_adr;
/* verilator lint_on COMBDLY */
`endif
generate
if (MDU) begin: gen_mdu
assign dbus_rdt = i_ext_ready ? i_ext_rd:i_dbus_rdt;
assign dbus_ack = i_dbus_ack | i_ext_ready;
end else begin : gen_no_mdu
assign dbus_rdt = i_dbus_rdt;
assign dbus_ack = i_dbus_ack;
end
assign o_ext_rs2 = o_dbus_dat;
endgenerate
endmodule
`default_nettype wire

View File

@ -14,6 +14,9 @@ module top (
input n64_si_clk,
inout n64_si_dq,
input n64_cic_clk,
inout n64_cic_dq,
input usb_pwrsav,
output usb_clk,
output usb_cs,
@ -45,7 +48,13 @@ module top (
input mcu_clk,
input mcu_cs,
input mcu_mosi,
output mcu_miso
output mcu_miso,
// Unused I/O
output n64_video_sync,
output [2:0] test_point
);
logic clk;
@ -132,7 +141,10 @@ module top (
.n64_pi_ad(n64_pi_ad),
.n64_si_clk(n64_si_clk),
.n64_si_dq(n64_si_dq)
.n64_si_dq(n64_si_dq),
.n64_cic_clk(n64_cic_clk),
.n64_cic_dq(n64_cic_dq)
);
@ -264,4 +276,11 @@ module top (
.vendor_scb(vendor_scb)
);
// Unused I/O
assign n64_video_sync = 1'bZ;
assign test_point = 3'b000;
endmodule

View File

@ -1,39 +1,3 @@
interface usb_scb ();
logic fifo_flush;
logic reset_pending;
logic reset_ack;
logic write_buffer_flush;
logic [10:0] rx_count;
logic [10:0] tx_count;
logic pwrsav;
logic reset_state;
modport controller (
output fifo_flush,
input reset_pending,
output reset_ack,
output write_buffer_flush,
input rx_count,
input tx_count,
input pwrsav,
input reset_state
);
modport usb (
input fifo_flush,
output reset_pending,
input reset_ack,
input write_buffer_flush,
output rx_count,
output tx_count,
output pwrsav,
output reset_state
);
endinterface
module usb_ft1248 (
input clk,
input reset,
@ -50,27 +14,25 @@ module usb_ft1248 (
);
logic rx_full;
logic rx_almost_full;
logic rx_write;
logic rx_write_delayed;
logic [7:0] rx_wdata;
logic tx_empty;
logic tx_almost_empty;
logic tx_read;
logic [7:0] tx_rdata;
logic fifo_flush;
fifo_8kb fifo_8kb_rx_inst (
.clk(clk),
.reset(reset || usb_scb.fifo_flush),
.reset(fifo_flush),
.empty(fifo_bus.rx_empty),
.almost_empty(fifo_bus.rx_almost_empty),
.read(fifo_bus.rx_read),
.rdata(fifo_bus.rx_rdata),
.full(rx_full),
.almost_full(rx_almost_full),
.write(rx_write),
.write(rx_write_delayed),
.wdata(rx_wdata),
.count(usb_scb.rx_count)
@ -78,15 +40,13 @@ module usb_ft1248 (
fifo_8kb fifo_8kb_tx_inst (
.clk(clk),
.reset(reset || usb_scb.fifo_flush),
.reset(fifo_flush),
.empty(tx_empty),
.almost_empty(tx_almost_empty),
.read(tx_read),
.rdata(tx_rdata),
.full(fifo_bus.tx_full),
.almost_full(fifo_bus.tx_almost_full),
.write(fifo_bus.tx_write),
.wdata(fifo_bus.tx_wdata),
@ -140,9 +100,10 @@ module usb_ft1248 (
e_cmd cmd;
e_cmd next_cmd;
logic [3:0] phase;
logic rx_write;
logic last_rx_failed;
logic last_tx_failed;
logic reset_reply;
logic last_reset_status;
logic [4:0] modem_status_counter;
logic write_modem_status_pending;
logic write_buffer_flush_pending;
@ -152,7 +113,9 @@ module usb_ft1248 (
cmd <= next_cmd;
usb_scb.pwrsav <= !ft_pwrsav;
usb_scb.reset_state <= last_reset_status;
fifo_flush <= 1'b0;
rx_write_delayed <= rx_write;
phase <= {phase[2:0], phase[3]};
if (state == STATE_IDLE) begin
@ -160,25 +123,49 @@ module usb_ft1248 (
end
if (reset) begin
usb_scb.fifo_flush_busy <= 1'b0;
usb_scb.reset_state <= 1'b0;
last_rx_failed <= 1'b0;
last_tx_failed <= 1'b0;
usb_scb.reset_pending <= 1'b0;
last_reset_status <= 1'b0;
reset_reply <= 1'b0;
modem_status_counter <= 5'd0;
write_modem_status_pending <= 1'b0;
write_modem_status_pending <= 1'b1;
write_buffer_flush_pending <= 1'b0;
end else begin
if (usb_scb.reset_ack) begin
usb_scb.reset_pending <= 1'b0;
if (usb_scb.fifo_flush) begin
usb_scb.fifo_flush_busy <= 1'b1;
end
if (usb_scb.reset_on_ack) begin
reset_reply <= 1'b1;
write_modem_status_pending <= 1'b1;
end
if (usb_scb.reset_off_ack) begin
reset_reply <= 1'b0;
write_modem_status_pending <= 1'b1;
end
if (usb_scb.write_buffer_flush) begin
write_buffer_flush_pending <= 1'b1;
end
if (state == STATE_IDLE) begin
modem_status_counter <= modem_status_counter + 1'd1;
if (usb_scb.fifo_flush_busy) begin
usb_scb.fifo_flush_busy <= 1'b0;
fifo_flush <= 1'b1;
last_rx_failed <= 1'b0;
last_tx_failed <= 1'b0;
end else if (last_rx_failed && !rx_full) begin
last_rx_failed <= 1'b0;
rx_write_delayed <= 1'b1;
end
end
if ((state == STATE_DATA) && (cmd == CMD_READ) && phase[3]) begin
rx_wdata <= ft_miosi_in;
last_rx_failed <= !ft_miso && rx_full;
end
if ((state == STATE_DATA) && (cmd == CMD_WRITE) && phase[3]) begin
@ -187,14 +174,7 @@ module usb_ft1248 (
if (!ft_miso && (state == STATE_DATA) && phase[3]) begin
if (cmd == CMD_READ_MODEM_STATUS) begin
last_reset_status <= ft_miosi_in[0];
if (!last_reset_status && ft_miosi_in[0]) begin
usb_scb.reset_pending <= 1'b1;
end
if (last_reset_status && !ft_miosi_in[0]) begin
reset_reply <= 1'b0;
write_modem_status_pending <= 1'b1;
end
usb_scb.reset_state <= ft_miosi_in[0];
end
if (cmd == CMD_WRITE_MODEM_STATUS) begin
write_modem_status_pending <= 1'b0;
@ -252,8 +232,6 @@ module usb_ft1248 (
rx_write = 1'b0;
tx_read = 1'b0;
rx_wdata = ft_miosi_in;
if (!ft_miso && phase[3]) begin
case (state)
STATE_STATUS: begin
@ -263,13 +241,15 @@ module usb_ft1248 (
end
STATE_DATA: begin
if (cmd == CMD_READ) begin
if (cmd == CMD_READ && !rx_full) begin
rx_write = 1'b1;
end
if (cmd == CMD_WRITE && !tx_empty) begin
tx_read = 1'b1;
end
end
default: begin end
endcase
end
end
@ -283,7 +263,7 @@ module usb_ft1248 (
end else begin
case (state)
STATE_IDLE: begin
if (ft_pwrsav) begin
if (ft_pwrsav && !(usb_scb.fifo_flush || usb_scb.fifo_flush_busy || fifo_flush)) begin
if (write_modem_status_pending) begin
next_state = STATE_SELECT;
next_cmd = CMD_WRITE_MODEM_STATUS;
@ -330,7 +310,7 @@ module usb_ft1248 (
if (ft_miso) begin
next_state = STATE_DESELECT;
end else if (cmd == CMD_READ) begin
if (rx_almost_full) begin
if (rx_full) begin
next_state = STATE_DESELECT;
end
end else if (cmd == CMD_WRITE) begin

37
fw/rtl/usb/usb_scb.sv Normal file
View File

@ -0,0 +1,37 @@
interface usb_scb ();
logic fifo_flush;
logic fifo_flush_busy;
logic write_buffer_flush;
logic [10:0] rx_count;
logic [10:0] tx_count;
logic pwrsav;
logic reset_state;
logic reset_on_ack;
logic reset_off_ack;
modport controller (
output fifo_flush,
input fifo_flush_busy,
output write_buffer_flush,
input rx_count,
input tx_count,
input pwrsav,
input reset_state,
output reset_on_ack,
output reset_off_ack
);
modport usb (
input fifo_flush,
output fifo_flush_busy,
input write_buffer_flush,
output rx_count,
output tx_count,
output pwrsav,
output reset_state,
input reset_on_ack,
input reset_off_ack
);
endinterface

View File

@ -3,18 +3,19 @@ module fifo_8kb (
input reset,
output empty,
output almost_empty,
input read,
output [7:0] rdata,
output full,
output almost_full,
input write,
input [7:0] wdata,
output logic [10:0] count
);
logic almost_empty;
logic almost_full;
fifo_8kb_lattice_generated fifo_8kb_lattice_generated_inst (
.Data(wdata),
.WrClock(clk),
@ -25,7 +26,7 @@ module fifo_8kb (
.RPReset(reset),
.Q(rdata),
.Empty(empty),
.Full(full),
.Full(full),
.AlmostEmpty(almost_empty),
.AlmostFull(almost_full)
);

View File

@ -1,7 +1,7 @@
/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.12.1.454 */
/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.13.0.56.2 */
/* Module Version: 5.7 */
/* C:\lscc\diamond\3.12\ispfpga\bin\nt64\scuba.exe -w -n pll_lattice_generated -lang verilog -synth synplify -arch xo2c00 -type pll -fin 50 -fclkop 100 -fclkop_tol 0.0 -fclkos 100 -fclkos_tol 0.0 -trimp 0 -phasep 0 -trimp_r -trims 0 -phases 90 -trims_r -phase_cntl STATIC -fb_mode 1 -lock */
/* Sat Mar 19 17:10:12 2022 */
/* C:\lscc\diamond\3.13\ispfpga\bin\nt64\scuba.exe -w -n pll_lattice_generated -lang verilog -synth synplify -arch xo2c00 -type pll -fin 50 -fclkop 100 -fclkop_tol 0.0 -fclkos 100 -fclkos_tol 0.0 -trimp 0 -phasep 0 -trimp_r -trims 0 -phases 270 -trims_r -phase_cntl STATIC -fb_mode 1 -lock */
/* Sun May 05 06:07:05 2024 */
`timescale 1 ns / 1 ps
@ -29,8 +29,8 @@ module pll_lattice_generated (CLKI, CLKOP, CLKOS, LOCK)/* synthesis NGD_DRC_MASK
defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
defparam PLLInst_0.CLKOS_FPHASE = 2 ;
defparam PLLInst_0.CLKOS_CPHASE = 5 ;
defparam PLLInst_0.CLKOS_FPHASE = 6 ;
defparam PLLInst_0.CLKOS_CPHASE = 7 ;
defparam PLLInst_0.CLKOP_FPHASE = 0 ;
defparam PLLInst_0.CLKOP_CPHASE = 4 ;
defparam PLLInst_0.PLL_LOCK_MODE = 0 ;

View File

@ -17,8 +17,8 @@ module pll (
);
ODDRXE oddrxe_sdram_clk_inst (
.D0(1'b0),
.D1(1'b1),
.D0(1'b1),
.D1(1'b0),
.SCLK(pll_sdram_clk),
.RST(1'b0),
.Q(buf_sdram_clk)

1
fw/tests/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

35
fw/tests/Makefile Normal file
View File

@ -0,0 +1,35 @@
RTL_DIR = ../rtl
BENCHES_DIR = benches
MOCKS_DIR = mocks
BUILD_DIR = build
SRC_DIRS = \
$(RTL_DIR)/fifo \
$(RTL_DIR)/mcu \
$(RTL_DIR)/memory \
$(RTL_DIR)/n64 \
$(RTL_DIR)/sd \
$(RTL_DIR)/serv \
$(RTL_DIR)/usb \
$(RTL_DIR)/vendor \
$(RTL_DIR) \
$(MOCKS_DIR)/vendor \
$(MOCKS_DIR)
INC_DIRS = $(addprefix -I, $(SRC_DIRS))
TEST_FILES = $(shell find "./$(BENCHES_DIR)" -not -path "$(BUILD_DIR)/*" -type f -name "*_tb.sv")
TESTS = $(addprefix $(BUILD_DIR)/, $(basename $(TEST_FILES)))
VERILATOR_FLAGS = --binary --trace --timescale 10ns/1ns -j --quiet $(INC_DIRS)
$(BUILD_DIR)/%: %.sv
@echo "[VERILATOR] $<"
@mkdir -p $@.obj
@verilator $(VERILATOR_FLAGS) -Mdir $@.obj $< > /dev/null
@$@.obj/V$(notdir $@)
tests: $(TESTS)
clean:
@rm -rf ./$(BUILD_DIR)
.PHONY: tests

View File

@ -0,0 +1,126 @@
module memory_dma_tb;
logic clk;
logic reset;
dma_scb dma_scb ();
fifo_bus fifo_bus ();
mem_bus mem_bus ();
logic start;
logic stop;
logic direction;
logic byte_swap;
logic [26:0] starting_address;
logic [26:0] transfer_length;
logic flush;
logic rx_fill_enabled;
logic tx_drain_enabled;
memory_dma memory_dma (
.clk(clk),
.reset(reset),
.dma_scb(dma_scb),
.fifo_bus(fifo_bus),
.mem_bus(mem_bus)
);
dma_controller_mock dma_controller_mock (
.clk(clk),
.reset(reset),
.dma_scb(dma_scb),
.start(start),
.stop(stop),
.direction(direction),
.byte_swap(byte_swap),
.starting_address(starting_address),
.transfer_length(transfer_length)
);
fifo_bus_fifo_mock #(
.DEPTH(8),
.FILL_RATE(3),
.DRAIN_RATE(3)
) fifo_bus_fifo_mock (
.clk(clk),
.reset(reset),
.fifo_bus(fifo_bus),
.flush(flush),
.rx_fill_enabled(rx_fill_enabled),
.tx_drain_enabled(tx_drain_enabled)
);
memory_sdram_mock memory_sdram_mock (
.clk(clk),
.reset(reset),
.mem_bus(mem_bus)
);
initial begin
clk = 1'b0;
forever begin
clk = ~clk; #0.5;
end
end
initial begin
reset = 1'b0;
#10;
reset = 1'b1;
#10;
reset = 1'b0;
end
initial begin
$dumpfile("traces/memory_dma_tb.vcd");
#10000;
$dumpvars();
#100;
start = 1'b1;
direction = 1'b0;
byte_swap = 1'b0;
starting_address = 27'hFFF1;
transfer_length = 27'd64;
#1;
start = 1'b0;
#9;
tx_drain_enabled = 1'b1;
#490;
stop = 1'b1;
#1;
stop = 1'b0;
#165;
start = 1'b1;
direction = 1'b1;
#1;
start = 1'b0;
#9;
rx_fill_enabled = 1'b1;
#490;
stop = 1'b1;
#1;
stop = 1'b0;
#99;
$finish;
end
endmodule

View File

@ -0,0 +1,119 @@
module usb_ft1248_tb;
logic clk;
logic reset;
usb_scb usb_scb ();
fifo_bus fifo_bus ();
logic usb_pwrsav;
logic usb_clk;
logic usb_cs;
logic usb_miso;
logic [7:0] usb_miosi;
usb_ft1248 usb_ft1248 (
.clk(clk),
.reset(reset),
.usb_scb(usb_scb),
.fifo_bus(fifo_bus),
.usb_pwrsav(usb_pwrsav),
.usb_clk(usb_clk),
.usb_cs(usb_cs),
.usb_miso(usb_miso),
.usb_miosi(usb_miosi)
);
initial begin
clk = 1'b0;
forever begin
clk = ~clk; #0.5;
end
end
initial begin
reset = 1'b1;
#10;
reset = 1'b0;
end
initial begin
$dumpfile("traces/usb_ft1248_tb.vcd");
$dumpvars();
usb_pwrsav = 1'b1;
usb_miso = 1'b1;
#100;
fifo_bus.tx_write = 1'b1;
#100;
fifo_bus.tx_write = 1'b0;
#103;
usb_miso = 1'b0;
#80;
usb_scb.write_buffer_flush = 1'b1;
#1;
usb_scb.write_buffer_flush = 1'b0;
#20;
usb_miso = 1'b1;
#26;
usb_miso = 1'b0;
#4430;
usb_miso = 1'b1;
#13;
usb_miso = 1'b0;
#79;
fifo_bus.rx_read = 1'b1;
#1;
fifo_bus.rx_read = 1'b0;
#10;
fifo_bus.rx_read = 1'b1;
#1;
fifo_bus.rx_read = 1'b0;
#80;
fifo_bus.rx_read = 1'b1;
#1;
fifo_bus.rx_read = 1'b0;
#200;
usb_scb.reset_on_ack = 1'b1;
#1;
usb_scb.reset_on_ack = 1'b0;
#200;
usb_scb.reset_off_ack = 1'b1;
#1;
usb_scb.reset_off_ack = 1'b0;
#200;
usb_scb.fifo_flush = 1'b1;
#1;
usb_scb.fifo_flush = 1'b0;
#3000;
usb_scb.fifo_flush = 1'b1;
#1;
usb_scb.fifo_flush = 1'b0;
#6000;
$finish;
end
endmodule

22
fw/tests/docker_run.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
pushd $(dirname $0) > /dev/null
docker run \
-it \
--rm \
--user $(id -u):$(id -g) \
-v "$(pwd)":/work \
-v "$(pwd)/../rtl":/rtl \
-e CCACHE_DIR=/tmp/ccache \
--entrypoint /bin/bash \
verilator/verilator:latest \
-c "make -j"
BUILD_ERROR=$?
popd > /dev/null
if [ $BUILD_ERROR -ne 0 ]; then
exit -1
fi

View File

@ -0,0 +1,39 @@
module dma_controller_mock (
input clk,
input reset,
dma_scb.controller dma_scb,
input start,
input stop,
input direction,
input byte_swap,
input [26:0] starting_address,
input [26:0] transfer_length
);
always_ff @(posedge clk) begin
dma_scb.start <= 1'b0;
dma_scb.stop <= 1'b0;
if (reset) begin
dma_scb.direction <= 1'b0;
dma_scb.byte_swap <= 1'b0;
dma_scb.starting_address <= 27'd0;
dma_scb.transfer_length <= 27'd0;
end else begin
if (start) begin
dma_scb.start <= 1'b1;
dma_scb.direction <= direction;
dma_scb.byte_swap <= byte_swap;
dma_scb.starting_address <= starting_address;
dma_scb.transfer_length <= transfer_length;
end
if (stop) begin
dma_scb.stop <= 1'b1;
end
end
end
endmodule

View File

@ -0,0 +1,145 @@
module fifo_bus_fifo_mock #(
parameter int DEPTH = 1024,
parameter int FILL_RATE = 3,
parameter int DRAIN_RATE = 3
) (
input clk,
input reset,
fifo_bus.fifo fifo_bus,
input flush,
input rx_fill_enabled,
input tx_drain_enabled
);
localparam int PTR_BITS = $clog2(DEPTH);
// RX FIFO mock
logic rx_full;
logic rx_write;
logic [7:0] rx_wdata;
logic [PTR_BITS:0] rx_count;
fifo_mock #(
.DEPTH(DEPTH)
) fifo_rx (
.clk(clk),
.reset(reset),
.empty(fifo_bus.rx_empty),
.read(fifo_bus.rx_read),
.rdata(fifo_bus.rx_rdata),
.full(rx_full),
.write(rx_write),
.wdata(rx_wdata),
.count(rx_count)
);
localparam int FILL_BITS = $clog2(FILL_RATE);
logic [FILL_BITS:0] fill_counter;
logic rx_fill;
always_ff @(posedge clk) begin
rx_fill <= rx_fill_enabled;
end
generate;
if (FILL_RATE == 0) begin
always_comb begin
rx_write = rx_fill && !rx_full;
end
end else begin
always_comb begin
rx_write = rx_fill && !rx_full && (fill_counter == (FILL_BITS + 1)'(FILL_RATE));
end
always_ff @(posedge clk) begin
if (fill_counter < (FILL_BITS + 1)'(FILL_RATE)) begin
fill_counter <= fill_counter + (FILL_BITS + 1)'('d1);
end
if (reset) begin
fill_counter <= (FILL_BITS + 1)'('d0);
end else begin
if (rx_write) begin
fill_counter <= (FILL_BITS + 1)'('d0);
end
end
end
end
endgenerate
always_ff @(posedge clk) begin
if (reset) begin
rx_wdata <= 8'h01;
end else begin
if (rx_write) begin
rx_wdata <= rx_wdata + 8'h01;
end
end
end
// TX FIFO mock
logic tx_empty;
logic tx_read;
logic [7:0] tx_rdata;
logic [PTR_BITS:0] tx_count;
fifo_mock #(
.DEPTH(DEPTH)
) fifo_tx (
.clk(clk),
.reset(reset),
.empty(tx_empty),
.read(tx_read),
.rdata(tx_rdata),
.full(fifo_bus.tx_full),
.write(fifo_bus.tx_write),
.wdata(fifo_bus.tx_wdata),
.count(tx_count)
);
localparam int DRAIN_BITS = $clog2(DRAIN_RATE);
logic [DRAIN_BITS:0] drain_counter;
logic tx_drain;
always_ff @(posedge clk) begin
tx_drain <= tx_drain_enabled;
end
generate;
if (DRAIN_RATE == 0) begin
always_comb begin
tx_read = tx_drain && !tx_empty;
end
end else begin
always_comb begin
tx_read = tx_drain && !tx_empty && (drain_counter == (DRAIN_BITS + 1)'(DRAIN_RATE));
end
always_ff @(posedge clk) begin
if (drain_counter < (DRAIN_BITS + 1)'(DRAIN_RATE)) begin
drain_counter <= drain_counter + (DRAIN_BITS + 1)'('d1);
end
if (reset) begin
drain_counter <= (DRAIN_BITS + 1)'('d0);
end else begin
if (tx_read) begin
drain_counter <= (DRAIN_BITS + 1)'('d0);
end
end
end
end
endgenerate
endmodule

View File

@ -0,0 +1,49 @@
module fifo_mock #(
parameter int DEPTH = 1024,
localparam int PTR_BITS = $clog2(DEPTH)
) (
input clk,
input reset,
output logic empty,
input read,
output [7:0] rdata,
output logic full,
input write,
input [7:0] wdata,
output logic [PTR_BITS:0] count
);
logic [7:0] fifo_mem [0:(DEPTH - 1)];
logic [(PTR_BITS - 1):0] fifo_rptr;
logic [(PTR_BITS - 1):0] fifo_wptr;
always_comb begin
full = count >= (PTR_BITS + 1)'(DEPTH);
empty = count == (PTR_BITS + 1)'('d0);
end
always_ff @(posedge clk) begin
if (read) begin
rdata <= fifo_mem[fifo_rptr];
fifo_rptr <= fifo_rptr + PTR_BITS'('d1);
count <= count - (PTR_BITS + 1)'('d1);
end
if (write) begin
fifo_mem[fifo_wptr] <= wdata;
fifo_wptr <= fifo_wptr + PTR_BITS'('d1);
count <= count + (PTR_BITS + 1)'('d1);
end
if (read && write) begin
count <= count;
end
if (reset) begin
count <= (PTR_BITS + 1)'('d0);
fifo_rptr <= PTR_BITS'('d0);
fifo_wptr <= PTR_BITS'('d0);
end
end
endmodule

View File

@ -0,0 +1,70 @@
module memory_sdram_mock (
input clk,
input reset,
mem_bus.memory mem_bus
);
logic sdram_cs;
logic sdram_ras;
logic sdram_cas;
logic sdram_we;
logic [1:0] sdram_ba;
logic [12:0] sdram_a;
logic [1:0] sdram_dqm;
logic [15:0] sdram_dq;
memory_sdram memory_sdram_inst (
.clk(clk),
.reset(reset),
.mem_bus(mem_bus),
.sdram_cs(sdram_cs),
.sdram_ras(sdram_ras),
.sdram_cas(sdram_cas),
.sdram_we(sdram_we),
.sdram_ba(sdram_ba),
.sdram_a(sdram_a),
.sdram_dqm(sdram_dqm),
.sdram_dq(sdram_dq)
);
logic [1:0] cas_delay;
logic [15:0] data_from_sdram;
logic [15:0] data_to_sdram;
logic [15:0] sdram_dq_driven;
assign sdram_dq = sdram_dq_driven;
always_ff @(posedge clk) begin
if (reset) begin
cas_delay <= 2'b00;
data_from_sdram <= 16'h0102;
data_to_sdram <= 16'hFFFF;
end else begin
cas_delay <= {cas_delay[0], 1'b0};
if ({sdram_cs, sdram_ras, sdram_cas, sdram_we} == 4'b0101) begin
cas_delay[0] <= 1'b1;
end
if (cas_delay[1]) begin
data_from_sdram <= data_from_sdram + 16'h0202;
end
if ({sdram_cs, sdram_ras, sdram_cas, sdram_we} == 4'b0100) begin
if (!sdram_dqm[0]) data_to_sdram[7:0] <= sdram_dq[7:0];
if (!sdram_dqm[1]) data_to_sdram[15:8] <= sdram_dq[15:8];
end
end
end
always_comb begin
sdram_dq_driven = 16'hXXXX;
if (cas_delay[1]) begin
sdram_dq_driven = data_from_sdram;
end
end
endmodule

33
fw/tests/mocks/vendor/fifo_8kb.sv vendored Normal file
View File

@ -0,0 +1,33 @@
module fifo_8kb (
input clk,
input reset,
output empty,
input read,
output [7:0] rdata,
output full,
input write,
input [7:0] wdata,
output logic [10:0] count
);
fifo_mock #(
.DEPTH(1024)
) fifo_8kb (
.clk(clk),
.reset(reset),
.empty(empty),
.read(read),
.rdata(rdata),
.full(full),
.write(write),
.wdata(wdata),
.count(count)
);
endmodule

2
fw/tests/traces/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.vcd
*.gtkw

2
hw/pcb/.gitignore vendored
View File

@ -1,5 +1,7 @@
*.lck
**/*-backups
**/*-bak
**/*.3dshapes
**/*.csv
**/*.gerbers
**/*.kicad_prl

289
hw/pcb/LICENSE Normal file
View File

@ -0,0 +1,289 @@
CERN Open Hardware Licence Version 2 - Strongly Reciprocal
Preamble
CERN has developed this licence to promote collaboration among
hardware designers and to provide a legal tool which supports the
freedom to use, study, modify, share and distribute hardware designs
and products based on those designs. Version 2 of the CERN Open
Hardware Licence comes in three variants: CERN-OHL-P (permissive); and
two reciprocal licences: CERN-OHL-W (weakly reciprocal) and this
licence, CERN-OHL-S (strongly reciprocal).
The CERN-OHL-S is copyright CERN 2020. Anyone is welcome to use it, in
unmodified form only.
Use of this Licence does not imply any endorsement by CERN of any
Licensor or their designs nor does it imply any involvement by CERN in
their development.
1 Definitions
1.1 'Licence' means this CERN-OHL-S.
1.2 'Compatible Licence' means
a) any earlier version of the CERN Open Hardware licence, or
b) any version of the CERN-OHL-S, or
c) any licence which permits You to treat the Source to which
it applies as licensed under CERN-OHL-S provided that on
Conveyance of any such Source, or any associated Product You
treat the Source in question as being licensed under
CERN-OHL-S.
1.3 'Source' means information such as design materials or digital
code which can be applied to Make or test a Product or to
prepare a Product for use, Conveyance or sale, regardless of its
medium or how it is expressed. It may include Notices.
1.4 'Covered Source' means Source that is explicitly made available
under this Licence.
1.5 'Product' means any device, component, work or physical object,
whether in finished or intermediate form, arising from the use,
application or processing of Covered Source.
1.6 'Make' means to create or configure something, whether by
manufacture, assembly, compiling, loading or applying Covered
Source or another Product or otherwise.
1.7 'Available Component' means any part, sub-assembly, library or
code which:
a) is licensed to You as Complete Source under a Compatible
Licence; or
b) is available, at the time a Product or the Source containing
it is first Conveyed, to You and any other prospective
licensees
i) as a physical part with sufficient rights and
information (including any configuration and
programming files and information about its
characteristics and interfaces) to enable it either to
be Made itself, or to be sourced and used to Make the
Product; or
ii) as part of the normal distribution of a tool used to
design or Make the Product.
1.8 'Complete Source' means the set of all Source necessary to Make
a Product, in the preferred form for making modifications,
including necessary installation and interfacing information
both for the Product, and for any included Available Components.
If the format is proprietary, it must also be made available in
a format (if the proprietary tool can create it) which is
viewable with a tool available to potential licensees and
licensed under a licence approved by the Free Software
Foundation or the Open Source Initiative. Complete Source need
not include the Source of any Available Component, provided that
You include in the Complete Source sufficient information to
enable a recipient to Make or source and use the Available
Component to Make the Product.
1.9 'Source Location' means a location where a Licensor has placed
Covered Source, and which that Licensor reasonably believes will
remain easily accessible for at least three years for anyone to
obtain a digital copy.
1.10 'Notice' means copyright, acknowledgement and trademark notices,
Source Location references, modification notices (subsection
3.3(b)) and all notices that refer to this Licence and to the
disclaimer of warranties that are included in the Covered
Source.
1.11 'Licensee' or 'You' means any person exercising rights under
this Licence.
1.12 'Licensor' means a natural or legal person who creates or
modifies Covered Source. A person may be a Licensee and a
Licensor at the same time.
1.13 'Convey' means to communicate to the public or distribute.
2 Applicability
2.1 This Licence governs the use, copying, modification, Conveying
of Covered Source and Products, and the Making of Products. By
exercising any right granted under this Licence, You irrevocably
accept these terms and conditions.
2.2 This Licence is granted by the Licensor directly to You, and
shall apply worldwide and without limitation in time.
2.3 You shall not attempt to restrict by contract or otherwise the
rights granted under this Licence to other Licensees.
2.4 This Licence is not intended to restrict fair use, fair dealing,
or any other similar right.
3 Copying, Modifying and Conveying Covered Source
3.1 You may copy and Convey verbatim copies of Covered Source, in
any medium, provided You retain all Notices.
3.2 You may modify Covered Source, other than Notices, provided that
You irrevocably undertake to make that modified Covered Source
available from a Source Location should You Convey a Product in
circumstances where the recipient does not otherwise receive a
copy of the modified Covered Source. In each case subsection 3.3
shall apply.
You may only delete Notices if they are no longer applicable to
the corresponding Covered Source as modified by You and You may
add additional Notices applicable to Your modifications.
Including Covered Source in a larger work is modifying the
Covered Source, and the larger work becomes modified Covered
Source.
3.3 You may Convey modified Covered Source (with the effect that You
shall also become a Licensor) provided that You:
a) retain Notices as required in subsection 3.2;
b) add a Notice to the modified Covered Source stating that You
have modified it, with the date and brief description of how
You have modified it;
c) add a Source Location Notice for the modified Covered Source
if You Convey in circumstances where the recipient does not
otherwise receive a copy of the modified Covered Source; and
d) license the modified Covered Source under the terms and
conditions of this Licence (or, as set out in subsection
8.3, a later version, if permitted by the licence of the
original Covered Source). Such modified Covered Source must
be licensed as a whole, but excluding Available Components
contained in it, which remain licensed under their own
applicable licences.
4 Making and Conveying Products
You may Make Products, and/or Convey them, provided that You either
provide each recipient with a copy of the Complete Source or ensure
that each recipient is notified of the Source Location of the Complete
Source. That Complete Source is Covered Source, and You must
accordingly satisfy Your obligations set out in subsection 3.3. If
specified in a Notice, the Product must visibly and securely display
the Source Location on it or its packaging or documentation in the
manner specified in that Notice.
5 Research and Development
You may Convey Covered Source, modified Covered Source or Products to
a legal entity carrying out development, testing or quality assurance
work on Your behalf provided that the work is performed on terms which
prevent the entity from both using the Source or Products for its own
internal purposes and Conveying the Source or Products or any
modifications to them to any person other than You. Any modifications
made by the entity shall be deemed to be made by You pursuant to
subsection 3.2.
6 DISCLAIMER AND LIABILITY
6.1 DISCLAIMER OF WARRANTY -- The Covered Source and any Products
are provided 'as is' and any express or implied warranties,
including, but not limited to, implied warranties of
merchantability, of satisfactory quality, non-infringement of
third party rights, and fitness for a particular purpose or use
are disclaimed in respect of any Source or Product to the
maximum extent permitted by law. The Licensor makes no
representation that any Source or Product does not or will not
infringe any patent, copyright, trade secret or other
proprietary right. The entire risk as to the use, quality, and
performance of any Source or Product shall be with You and not
the Licensor. This disclaimer of warranty is an essential part
of this Licence and a condition for the grant of any rights
granted under this Licence.
6.2 EXCLUSION AND LIMITATION OF LIABILITY -- The Licensor shall, to
the maximum extent permitted by law, have no liability for
direct, indirect, special, incidental, consequential, exemplary,
punitive or other damages of any character including, without
limitation, procurement of substitute goods or services, loss of
use, data or profits, or business interruption, however caused
and on any theory of contract, warranty, tort (including
negligence), product liability or otherwise, arising in any way
in relation to the Covered Source, modified Covered Source
and/or the Making or Conveyance of a Product, even if advised of
the possibility of such damages, and You shall hold the
Licensor(s) free and harmless from any liability, costs,
damages, fees and expenses, including claims by third parties,
in relation to such use.
7 Patents
7.1 Subject to the terms and conditions of this Licence, each
Licensor hereby grants to You a perpetual, worldwide,
non-exclusive, no-charge, royalty-free, irrevocable (except as
stated in subsections 7.2 and 8.4) patent licence to Make, have
Made, use, offer to sell, sell, import, and otherwise transfer
the Covered Source and Products, where such licence applies only
to those patent claims licensable by such Licensor that are
necessarily infringed by exercising rights under the Covered
Source as Conveyed by that Licensor.
7.2 If You institute patent litigation against any entity (including
a cross-claim or counterclaim in a lawsuit) alleging that the
Covered Source or a Product constitutes direct or contributory
patent infringement, or You seek any declaration that a patent
licensed to You under this Licence is invalid or unenforceable
then any rights granted to You under this Licence shall
terminate as of the date such process is initiated.
8 General
8.1 If any provisions of this Licence are or subsequently become
invalid or unenforceable for any reason, the remaining
provisions shall remain effective.
8.2 You shall not use any of the name (including acronyms and
abbreviations), image, or logo by which the Licensor or CERN is
known, except where needed to comply with section 3, or where
the use is otherwise allowed by law. Any such permitted use
shall be factual and shall not be made so as to suggest any kind
of endorsement or implication of involvement by the Licensor or
its personnel.
8.3 CERN may publish updated versions and variants of this Licence
which it considers to be in the spirit of this version, but may
differ in detail to address new problems or concerns. New
versions will be published with a unique version number and a
variant identifier specifying the variant. If the Licensor has
specified that a given variant applies to the Covered Source
without specifying a version, You may treat that Covered Source
as being released under any version of the CERN-OHL with that
variant. If no variant is specified, the Covered Source shall be
treated as being released under CERN-OHL-S. The Licensor may
also specify that the Covered Source is subject to a specific
version of the CERN-OHL or any later version in which case You
may apply this or any later version of CERN-OHL with the same
variant identifier published by CERN.
8.4 This Licence shall terminate with immediate effect if You fail
to comply with any of its terms and conditions.
8.5 However, if You cease all breaches of this Licence, then Your
Licence from any Licensor is reinstated unless such Licensor has
terminated this Licence by giving You, while You remain in
breach, a notice specifying the breach and requiring You to cure
it within 30 days, and You have failed to come into compliance
in all material respects by the end of the 30 day period. Should
You repeat the breach after receipt of a cure notice and
subsequent reinstatement, this Licence will terminate
immediately and permanently. Section 6 shall continue to apply
after any termination.
8.6 This Licence shall not be enforceable except by a Licensor
acting as such, and third party beneficiary rights are
specifically excluded.

31
hw/pcb/ibom.config.ini Normal file
View File

@ -0,0 +1,31 @@
[html_defaults]
dark_mode=1
show_pads=1
show_fabrication=0
show_silkscreen=1
redraw_on_drag=1
highlight_pin1=selected
board_rotation=0
offset_back_rotation=0
checkboxes=Sourced,Placed
bom_view=left-right
layer_view=FB
compression=1
open_browser=0
[general]
bom_dest_dir=.
bom_name_format=%f_bom
component_sort_order=C,R,L,D,U,Y,X,F,SW,A,~,HS,CNN,J,P,NT,MH
component_blacklist=
blacklist_virtual=1
blacklist_empty_val=0
include_tracks=0
include_nets=0
[fields]
show_fields=Value,Footprint,Notes
group_fields=Value,Footprint
normalize_field_case=0
board_variant_field=
board_variant_whitelist=
board_variant_blacklist=
dnp_field=kicad_dnp

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -3,14 +3,17 @@
"3dviewports": [],
"design_settings": {
"defaults": {
"board_outline_line_width": 0.09999999999999999,
"copper_line_width": 0.19999999999999998,
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.1,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
@ -21,7 +24,7 @@
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
@ -34,9 +37,9 @@
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.762,
"height": 1.524,
"width": 1.524
"drill": 2.5,
"height": 2.5,
"width": 2.5
},
"silk_line_width": 0.15,
"silk_text_italic": false,
@ -63,20 +66,28 @@
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
@ -86,9 +97,14 @@
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "ignore",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
@ -97,7 +113,6 @@
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zone_has_empty_net": "error",
"zones_intersect": "error"
},
"rules": {
@ -105,25 +120,99 @@
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.127,
"min_copper_edge_clearance": 0.19999999999999998,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.2,
"min_hole_clearance": 0.254,
"min_hole_to_hole": 0.5,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.127,
"min_via_annular_width": 0.13,
"min_via_diameter": 0.6,
"solder_mask_clearance": 0.0,
"solder_mask_min_width": 0.0,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0,
0.508,
0.762
],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [
{
"diameter": 0.0,
@ -133,6 +222,13 @@
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_presets": [],
"viewports": []
},
@ -391,14 +487,94 @@
"gencad": "",
"idf": "",
"netlist": "",
"plot": "sc64v2.gerbers/",
"pos_files": "sc64v2.gerbers/",
"specctra_dsn": "",
"step": "",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_export_filename": "",
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
},
{
"group_by": false,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
},
{
"group_by": false,
"label": "#",
"name": "${ITEM_NUMBER}",
"show": false
},
{
"group_by": false,
"label": "Notes",
"name": "Notes",
"show": true
},
{
"group_by": false,
"label": "Description",
"name": "Description",
"show": false
}
],
"filter_string": "",
"group_symbols": true,
"name": "",
"sort_asc": true,
"sort_field": "Reference"
},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
@ -412,6 +588,11 @@
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
@ -437,6 +618,7 @@
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
@ -444,7 +626,7 @@
"sheets": [
[
"e63e39d7-6ac0-4ffd-8aa3-1841a4541b55",
""
"Root"
]
],
"text_variables": {}

File diff suppressed because it is too large Load Diff

4669
hw/pcb/sc64v2_bom.html generated Normal file

File diff suppressed because one or more lines are too long

12
hw/shell/README.md Normal file
View File

@ -0,0 +1,12 @@
# SummerCart64 shell design files
This folder contains several different designs of the SummerCart64 shell and button
`./` folder contains original design made by [Mateusz Faderewski 'Polprzewodnikowy'](https://github.com/Polprzewodnikowy) in the Autodesk Fusion 360 and exported `.stl` files ready for 3D print.
`./injection mold` folder contains adapted design for injection molding process by [Mena 'Pheeeeenom'](https://github.com/Pheeeeenom).
`./button` folder contains designs for the button on the back of the SummerCart64. Designs are:
- `sc64_shell_button_b3fs-101x.stl` - for the Omron B3FS-101x button (by [Mason Stooksbury](https://github.com/MasonStooksbury))
- `sc64_shell_button_b3fs-105x.step` - for the Omron B3FS-105x button (by [Mena 'Pheeeeenom'](https://github.com/Pheeeeenom))
- `sc64_shell_button_b3fs-105x_with_end_stop.step` - for the Omron B3FS-105x button but with additional flange to prevent it from coming out of the shell (by [Mena 'Pheeeeenom'](https://github.com/Pheeeeenom))

Binary file not shown.

View File

@ -0,0 +1,600 @@
ISO-10303-21;
HEADER;
/* Generated by software containing ST-Developer
* from STEP Tools, Inc. (www.steptools.com)
*/
FILE_DESCRIPTION(
/* description */ (''),
/* implementation_level */ '2;1');
FILE_NAME(
/* name */ 'sc64_shell_button v3.step',
/* time_stamp */ '2024-01-03T20:51:50-06:00',
/* author */ (''),
/* organization */ (''),
/* preprocessor_version */ 'ST-DEVELOPER v20',
/* originating_system */ 'Autodesk Translation Framework v12.14.0.127',
/* authorisation */ '');
FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
ENDSEC;
DATA;
#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#13),#504);
#11=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#510,#12);
#12=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#14),#503);
#13=STYLED_ITEM('',(#522),#14);
#14=MANIFOLD_SOLID_BREP('ButtonCap',#299);
#15=CYLINDRICAL_SURFACE('',#320,3.);
#16=TOROIDAL_SURFACE('',#316,2.8,0.2);
#17=ELLIPSE('',#309,57.3219678278922,3.);
#18=ELLIPSE('',#311,57.3219678278922,3.);
#19=ELLIPSE('',#315,57.3219678278922,3.);
#20=ELLIPSE('',#322,57.3219678278922,3.);
#21=CIRCLE('',#307,3.);
#22=CIRCLE('',#313,3.);
#23=CIRCLE('',#317,2.8);
#24=CIRCLE('',#318,0.2);
#25=CIRCLE('',#319,3.);
#26=CIRCLE('',#321,3.);
#27=CIRCLE('',#323,3.);
#28=CIRCLE('',#324,3.);
#29=FACE_OUTER_BOUND('',#45,.T.);
#30=FACE_OUTER_BOUND('',#46,.T.);
#31=FACE_OUTER_BOUND('',#47,.T.);
#32=FACE_OUTER_BOUND('',#48,.T.);
#33=FACE_OUTER_BOUND('',#49,.T.);
#34=FACE_OUTER_BOUND('',#50,.T.);
#35=FACE_OUTER_BOUND('',#51,.T.);
#36=FACE_OUTER_BOUND('',#52,.T.);
#37=FACE_OUTER_BOUND('',#53,.T.);
#38=FACE_OUTER_BOUND('',#54,.T.);
#39=FACE_OUTER_BOUND('',#55,.T.);
#40=FACE_OUTER_BOUND('',#56,.T.);
#41=FACE_OUTER_BOUND('',#57,.T.);
#42=FACE_OUTER_BOUND('',#58,.T.);
#43=FACE_OUTER_BOUND('',#59,.T.);
#44=FACE_OUTER_BOUND('',#60,.T.);
#45=EDGE_LOOP('',(#187,#188,#189,#190));
#46=EDGE_LOOP('',(#191,#192,#193,#194,#195,#196,#197,#198));
#47=EDGE_LOOP('',(#199,#200,#201,#202));
#48=EDGE_LOOP('',(#203,#204,#205,#206,#207,#208,#209,#210));
#49=EDGE_LOOP('',(#211,#212,#213,#214));
#50=EDGE_LOOP('',(#215,#216,#217,#218,#219,#220));
#51=EDGE_LOOP('',(#221,#222,#223,#224));
#52=EDGE_LOOP('',(#225,#226,#227,#228));
#53=EDGE_LOOP('',(#229,#230,#231,#232));
#54=EDGE_LOOP('',(#233,#234,#235,#236));
#55=EDGE_LOOP('',(#237,#238,#239,#240));
#56=EDGE_LOOP('',(#241,#242,#243,#244,#245,#246,#247,#248,#249,#250,#251,
#252));
#57=EDGE_LOOP('',(#253));
#58=EDGE_LOOP('',(#254,#255,#256,#257));
#59=EDGE_LOOP('',(#258,#259,#260,#261));
#60=EDGE_LOOP('',(#262,#263,#264,#265,#266,#267,#268));
#61=LINE('',#420,#90);
#62=LINE('',#422,#91);
#63=LINE('',#424,#92);
#64=LINE('',#425,#93);
#65=LINE('',#429,#94);
#66=LINE('',#431,#95);
#67=LINE('',#432,#96);
#68=LINE('',#434,#97);
#69=LINE('',#436,#98);
#70=LINE('',#438,#99);
#71=LINE('',#439,#100);
#72=LINE('',#442,#101);
#73=LINE('',#443,#102);
#74=LINE('',#447,#103);
#75=LINE('',#449,#104);
#76=LINE('',#451,#105);
#77=LINE('',#453,#106);
#78=LINE('',#454,#107);
#79=LINE('',#455,#108);
#80=LINE('',#457,#109);
#81=LINE('',#460,#110);
#82=LINE('',#463,#111);
#83=LINE('',#466,#112);
#84=LINE('',#471,#113);
#85=LINE('',#474,#114);
#86=LINE('',#478,#115);
#87=LINE('',#488,#116);
#88=LINE('',#497,#117);
#89=LINE('',#498,#118);
#90=VECTOR('',#333,10.);
#91=VECTOR('',#334,10.);
#92=VECTOR('',#335,10.);
#93=VECTOR('',#336,10.);
#94=VECTOR('',#339,10.);
#95=VECTOR('',#340,10.);
#96=VECTOR('',#341,10.);
#97=VECTOR('',#342,10.);
#98=VECTOR('',#343,10.);
#99=VECTOR('',#344,10.);
#100=VECTOR('',#345,10.);
#101=VECTOR('',#348,10.);
#102=VECTOR('',#349,10.);
#103=VECTOR('',#352,10.);
#104=VECTOR('',#353,10.);
#105=VECTOR('',#354,10.);
#106=VECTOR('',#355,10.);
#107=VECTOR('',#356,10.);
#108=VECTOR('',#357,10.);
#109=VECTOR('',#360,10.);
#110=VECTOR('',#363,10.);
#111=VECTOR('',#366,10.);
#112=VECTOR('',#369,10.);
#113=VECTOR('',#376,10.);
#114=VECTOR('',#379,10.);
#115=VECTOR('',#384,10.);
#116=VECTOR('',#397,3.);
#117=VECTOR('',#410,10.);
#118=VECTOR('',#411,10.);
#119=VERTEX_POINT('',#418);
#120=VERTEX_POINT('',#419);
#121=VERTEX_POINT('',#421);
#122=VERTEX_POINT('',#423);
#123=VERTEX_POINT('',#427);
#124=VERTEX_POINT('',#428);
#125=VERTEX_POINT('',#430);
#126=VERTEX_POINT('',#433);
#127=VERTEX_POINT('',#435);
#128=VERTEX_POINT('',#437);
#129=VERTEX_POINT('',#441);
#130=VERTEX_POINT('',#445);
#131=VERTEX_POINT('',#446);
#132=VERTEX_POINT('',#448);
#133=VERTEX_POINT('',#450);
#134=VERTEX_POINT('',#452);
#135=VERTEX_POINT('',#459);
#136=VERTEX_POINT('',#461);
#137=VERTEX_POINT('',#465);
#138=VERTEX_POINT('',#469);
#139=VERTEX_POINT('',#473);
#140=VERTEX_POINT('',#477);
#141=VERTEX_POINT('',#481);
#142=VERTEX_POINT('',#483);
#143=VERTEX_POINT('',#487);
#144=VERTEX_POINT('',#489);
#145=VERTEX_POINT('',#491);
#146=EDGE_CURVE('',#119,#120,#61,.T.);
#147=EDGE_CURVE('',#121,#119,#62,.T.);
#148=EDGE_CURVE('',#122,#121,#63,.T.);
#149=EDGE_CURVE('',#120,#122,#64,.T.);
#150=EDGE_CURVE('',#123,#124,#65,.T.);
#151=EDGE_CURVE('',#125,#123,#66,.T.);
#152=EDGE_CURVE('',#125,#119,#67,.T.);
#153=EDGE_CURVE('',#126,#120,#68,.T.);
#154=EDGE_CURVE('',#127,#126,#69,.T.);
#155=EDGE_CURVE('',#128,#127,#70,.T.);
#156=EDGE_CURVE('',#124,#128,#71,.T.);
#157=EDGE_CURVE('',#129,#125,#72,.T.);
#158=EDGE_CURVE('',#129,#121,#73,.T.);
#159=EDGE_CURVE('',#130,#131,#74,.T.);
#160=EDGE_CURVE('',#132,#130,#75,.T.);
#161=EDGE_CURVE('',#133,#132,#76,.T.);
#162=EDGE_CURVE('',#134,#133,#77,.T.);
#163=EDGE_CURVE('',#134,#122,#78,.T.);
#164=EDGE_CURVE('',#131,#129,#79,.T.);
#165=EDGE_CURVE('',#126,#134,#80,.T.);
#166=EDGE_CURVE('',#123,#135,#81,.F.);
#167=EDGE_CURVE('',#136,#135,#21,.T.);
#168=EDGE_CURVE('',#136,#131,#82,.F.);
#169=EDGE_CURVE('',#124,#137,#83,.F.);
#170=EDGE_CURVE('',#135,#137,#17,.T.);
#171=EDGE_CURVE('',#138,#136,#18,.T.);
#172=EDGE_CURVE('',#138,#130,#84,.F.);
#173=EDGE_CURVE('',#139,#128,#85,.F.);
#174=EDGE_CURVE('',#137,#139,#22,.T.);
#175=EDGE_CURVE('',#140,#127,#86,.F.);
#176=EDGE_CURVE('',#139,#140,#19,.T.);
#177=EDGE_CURVE('',#141,#141,#23,.T.);
#178=EDGE_CURVE('',#141,#142,#24,.T.);
#179=EDGE_CURVE('',#142,#142,#25,.T.);
#180=EDGE_CURVE('',#142,#143,#87,.T.);
#181=EDGE_CURVE('',#143,#144,#26,.T.);
#182=EDGE_CURVE('',#144,#145,#20,.T.);
#183=EDGE_CURVE('',#145,#138,#27,.T.);
#184=EDGE_CURVE('',#140,#143,#28,.T.);
#185=EDGE_CURVE('',#132,#145,#88,.F.);
#186=EDGE_CURVE('',#133,#144,#89,.F.);
#187=ORIENTED_EDGE('',*,*,#146,.F.);
#188=ORIENTED_EDGE('',*,*,#147,.F.);
#189=ORIENTED_EDGE('',*,*,#148,.F.);
#190=ORIENTED_EDGE('',*,*,#149,.F.);
#191=ORIENTED_EDGE('',*,*,#150,.F.);
#192=ORIENTED_EDGE('',*,*,#151,.F.);
#193=ORIENTED_EDGE('',*,*,#152,.T.);
#194=ORIENTED_EDGE('',*,*,#146,.T.);
#195=ORIENTED_EDGE('',*,*,#153,.F.);
#196=ORIENTED_EDGE('',*,*,#154,.F.);
#197=ORIENTED_EDGE('',*,*,#155,.F.);
#198=ORIENTED_EDGE('',*,*,#156,.F.);
#199=ORIENTED_EDGE('',*,*,#157,.F.);
#200=ORIENTED_EDGE('',*,*,#158,.T.);
#201=ORIENTED_EDGE('',*,*,#147,.T.);
#202=ORIENTED_EDGE('',*,*,#152,.F.);
#203=ORIENTED_EDGE('',*,*,#159,.F.);
#204=ORIENTED_EDGE('',*,*,#160,.F.);
#205=ORIENTED_EDGE('',*,*,#161,.F.);
#206=ORIENTED_EDGE('',*,*,#162,.F.);
#207=ORIENTED_EDGE('',*,*,#163,.T.);
#208=ORIENTED_EDGE('',*,*,#148,.T.);
#209=ORIENTED_EDGE('',*,*,#158,.F.);
#210=ORIENTED_EDGE('',*,*,#164,.F.);
#211=ORIENTED_EDGE('',*,*,#165,.F.);
#212=ORIENTED_EDGE('',*,*,#153,.T.);
#213=ORIENTED_EDGE('',*,*,#149,.T.);
#214=ORIENTED_EDGE('',*,*,#163,.F.);
#215=ORIENTED_EDGE('',*,*,#164,.T.);
#216=ORIENTED_EDGE('',*,*,#157,.T.);
#217=ORIENTED_EDGE('',*,*,#151,.T.);
#218=ORIENTED_EDGE('',*,*,#166,.T.);
#219=ORIENTED_EDGE('',*,*,#167,.F.);
#220=ORIENTED_EDGE('',*,*,#168,.T.);
#221=ORIENTED_EDGE('',*,*,#150,.T.);
#222=ORIENTED_EDGE('',*,*,#169,.T.);
#223=ORIENTED_EDGE('',*,*,#170,.F.);
#224=ORIENTED_EDGE('',*,*,#166,.F.);
#225=ORIENTED_EDGE('',*,*,#159,.T.);
#226=ORIENTED_EDGE('',*,*,#168,.F.);
#227=ORIENTED_EDGE('',*,*,#171,.F.);
#228=ORIENTED_EDGE('',*,*,#172,.T.);
#229=ORIENTED_EDGE('',*,*,#156,.T.);
#230=ORIENTED_EDGE('',*,*,#173,.F.);
#231=ORIENTED_EDGE('',*,*,#174,.F.);
#232=ORIENTED_EDGE('',*,*,#169,.F.);
#233=ORIENTED_EDGE('',*,*,#155,.T.);
#234=ORIENTED_EDGE('',*,*,#175,.F.);
#235=ORIENTED_EDGE('',*,*,#176,.F.);
#236=ORIENTED_EDGE('',*,*,#173,.T.);
#237=ORIENTED_EDGE('',*,*,#177,.T.);
#238=ORIENTED_EDGE('',*,*,#178,.T.);
#239=ORIENTED_EDGE('',*,*,#179,.T.);
#240=ORIENTED_EDGE('',*,*,#178,.F.);
#241=ORIENTED_EDGE('',*,*,#179,.F.);
#242=ORIENTED_EDGE('',*,*,#180,.T.);
#243=ORIENTED_EDGE('',*,*,#181,.T.);
#244=ORIENTED_EDGE('',*,*,#182,.T.);
#245=ORIENTED_EDGE('',*,*,#183,.T.);
#246=ORIENTED_EDGE('',*,*,#171,.T.);
#247=ORIENTED_EDGE('',*,*,#167,.T.);
#248=ORIENTED_EDGE('',*,*,#170,.T.);
#249=ORIENTED_EDGE('',*,*,#174,.T.);
#250=ORIENTED_EDGE('',*,*,#176,.T.);
#251=ORIENTED_EDGE('',*,*,#184,.T.);
#252=ORIENTED_EDGE('',*,*,#180,.F.);
#253=ORIENTED_EDGE('',*,*,#177,.F.);
#254=ORIENTED_EDGE('',*,*,#161,.T.);
#255=ORIENTED_EDGE('',*,*,#185,.T.);
#256=ORIENTED_EDGE('',*,*,#182,.F.);
#257=ORIENTED_EDGE('',*,*,#186,.F.);
#258=ORIENTED_EDGE('',*,*,#160,.T.);
#259=ORIENTED_EDGE('',*,*,#172,.F.);
#260=ORIENTED_EDGE('',*,*,#183,.F.);
#261=ORIENTED_EDGE('',*,*,#185,.F.);
#262=ORIENTED_EDGE('',*,*,#162,.T.);
#263=ORIENTED_EDGE('',*,*,#186,.T.);
#264=ORIENTED_EDGE('',*,*,#181,.F.);
#265=ORIENTED_EDGE('',*,*,#184,.F.);
#266=ORIENTED_EDGE('',*,*,#175,.T.);
#267=ORIENTED_EDGE('',*,*,#154,.T.);
#268=ORIENTED_EDGE('',*,*,#165,.T.);
#269=PLANE('',#301);
#270=PLANE('',#302);
#271=PLANE('',#303);
#272=PLANE('',#304);
#273=PLANE('',#305);
#274=PLANE('',#306);
#275=PLANE('',#308);
#276=PLANE('',#310);
#277=PLANE('',#312);
#278=PLANE('',#314);
#279=PLANE('',#325);
#280=PLANE('',#326);
#281=PLANE('',#327);
#282=PLANE('',#328);
#283=ADVANCED_FACE('',(#29),#269,.F.);
#284=ADVANCED_FACE('',(#30),#270,.F.);
#285=ADVANCED_FACE('',(#31),#271,.F.);
#286=ADVANCED_FACE('',(#32),#272,.F.);
#287=ADVANCED_FACE('',(#33),#273,.F.);
#288=ADVANCED_FACE('',(#34),#274,.F.);
#289=ADVANCED_FACE('',(#35),#275,.F.);
#290=ADVANCED_FACE('',(#36),#276,.F.);
#291=ADVANCED_FACE('',(#37),#277,.F.);
#292=ADVANCED_FACE('',(#38),#278,.F.);
#293=ADVANCED_FACE('',(#39),#16,.T.);
#294=ADVANCED_FACE('',(#40),#15,.T.);
#295=ADVANCED_FACE('',(#41),#279,.T.);
#296=ADVANCED_FACE('',(#42),#280,.F.);
#297=ADVANCED_FACE('',(#43),#281,.F.);
#298=ADVANCED_FACE('',(#44),#282,.F.);
#299=CLOSED_SHELL('',(#283,#284,#285,#286,#287,#288,#289,#290,#291,#292,
#293,#294,#295,#296,#297,#298));
#300=AXIS2_PLACEMENT_3D('',#416,#329,#330);
#301=AXIS2_PLACEMENT_3D('',#417,#331,#332);
#302=AXIS2_PLACEMENT_3D('',#426,#337,#338);
#303=AXIS2_PLACEMENT_3D('',#440,#346,#347);
#304=AXIS2_PLACEMENT_3D('',#444,#350,#351);
#305=AXIS2_PLACEMENT_3D('',#456,#358,#359);
#306=AXIS2_PLACEMENT_3D('',#458,#361,#362);
#307=AXIS2_PLACEMENT_3D('',#462,#364,#365);
#308=AXIS2_PLACEMENT_3D('',#464,#367,#368);
#309=AXIS2_PLACEMENT_3D('',#467,#370,#371);
#310=AXIS2_PLACEMENT_3D('',#468,#372,#373);
#311=AXIS2_PLACEMENT_3D('',#470,#374,#375);
#312=AXIS2_PLACEMENT_3D('',#472,#377,#378);
#313=AXIS2_PLACEMENT_3D('',#475,#380,#381);
#314=AXIS2_PLACEMENT_3D('',#476,#382,#383);
#315=AXIS2_PLACEMENT_3D('',#479,#385,#386);
#316=AXIS2_PLACEMENT_3D('',#480,#387,#388);
#317=AXIS2_PLACEMENT_3D('',#482,#389,#390);
#318=AXIS2_PLACEMENT_3D('',#484,#391,#392);
#319=AXIS2_PLACEMENT_3D('',#485,#393,#394);
#320=AXIS2_PLACEMENT_3D('',#486,#395,#396);
#321=AXIS2_PLACEMENT_3D('',#490,#398,#399);
#322=AXIS2_PLACEMENT_3D('',#492,#400,#401);
#323=AXIS2_PLACEMENT_3D('',#493,#402,#403);
#324=AXIS2_PLACEMENT_3D('',#494,#404,#405);
#325=AXIS2_PLACEMENT_3D('',#495,#406,#407);
#326=AXIS2_PLACEMENT_3D('',#496,#408,#409);
#327=AXIS2_PLACEMENT_3D('',#499,#412,#413);
#328=AXIS2_PLACEMENT_3D('',#500,#414,#415);
#329=DIRECTION('axis',(0.,0.,1.));
#330=DIRECTION('refdir',(1.,0.,0.));
#331=DIRECTION('center_axis',(0.,0.,1.));
#332=DIRECTION('ref_axis',(1.,0.,0.));
#333=DIRECTION('',(-1.,0.,0.));
#334=DIRECTION('',(0.,1.,0.));
#335=DIRECTION('',(1.,0.,0.));
#336=DIRECTION('',(0.,-1.,0.));
#337=DIRECTION('center_axis',(0.,1.,0.));
#338=DIRECTION('ref_axis',(-1.,0.,0.));
#339=DIRECTION('',(-0.0523359562429438,0.,0.998629534754574));
#340=DIRECTION('',(-1.,0.,0.));
#341=DIRECTION('',(0.,0.,1.));
#342=DIRECTION('',(0.,0.,1.));
#343=DIRECTION('',(-1.,0.,0.));
#344=DIRECTION('',(-0.0523359562429438,0.,-0.998629534754574));
#345=DIRECTION('',(-1.,0.,0.));
#346=DIRECTION('center_axis',(1.,0.,0.));
#347=DIRECTION('ref_axis',(0.,1.,0.));
#348=DIRECTION('',(0.,1.,0.));
#349=DIRECTION('',(0.,0.,1.));
#350=DIRECTION('center_axis',(0.,-1.,0.));
#351=DIRECTION('ref_axis',(1.,0.,0.));
#352=DIRECTION('',(0.0523359562429438,0.,-0.998629534754574));
#353=DIRECTION('',(1.,0.,0.));
#354=DIRECTION('',(0.0523359562429438,0.,0.998629534754574));
#355=DIRECTION('',(1.,0.,0.));
#356=DIRECTION('',(0.,0.,1.));
#357=DIRECTION('',(1.,0.,0.));
#358=DIRECTION('center_axis',(-1.,0.,0.));
#359=DIRECTION('ref_axis',(0.,-1.,0.));
#360=DIRECTION('',(0.,-1.,0.));
#361=DIRECTION('center_axis',(0.,0.,1.));
#362=DIRECTION('ref_axis',(1.,0.,0.));
#363=DIRECTION('',(0.,-1.,0.));
#364=DIRECTION('center_axis',(0.,0.,1.));
#365=DIRECTION('ref_axis',(1.,0.,0.));
#366=DIRECTION('',(0.,-1.,0.));
#367=DIRECTION('center_axis',(0.998629534754574,0.,0.0523359562429438));
#368=DIRECTION('ref_axis',(0.,1.,0.));
#369=DIRECTION('',(0.,-1.,0.));
#370=DIRECTION('center_axis',(0.998629534754574,0.,0.0523359562429438));
#371=DIRECTION('ref_axis',(0.0523359562429438,0.,-0.998629534754574));
#372=DIRECTION('center_axis',(0.998629534754574,0.,0.0523359562429438));
#373=DIRECTION('ref_axis',(0.,1.,0.));
#374=DIRECTION('center_axis',(0.998629534754574,0.,0.0523359562429438));
#375=DIRECTION('ref_axis',(0.0523359562429438,0.,-0.998629534754574));
#376=DIRECTION('',(0.,-1.,0.));
#377=DIRECTION('center_axis',(0.,0.,1.));
#378=DIRECTION('ref_axis',(1.,0.,0.));
#379=DIRECTION('',(0.,1.,0.));
#380=DIRECTION('center_axis',(0.,0.,1.));
#381=DIRECTION('ref_axis',(1.,0.,0.));
#382=DIRECTION('center_axis',(-0.998629534754574,0.,0.0523359562429438));
#383=DIRECTION('ref_axis',(0.,-1.,0.));
#384=DIRECTION('',(0.,1.,0.));
#385=DIRECTION('center_axis',(-0.998629534754574,0.,0.0523359562429438));
#386=DIRECTION('ref_axis',(0.0523359562429438,0.,0.998629534754574));
#387=DIRECTION('center_axis',(0.,0.,1.));
#388=DIRECTION('ref_axis',(1.,0.,0.));
#389=DIRECTION('center_axis',(0.,0.,-1.));
#390=DIRECTION('ref_axis',(1.,0.,0.));
#391=DIRECTION('center_axis',(0.,-1.,0.));
#392=DIRECTION('ref_axis',(-1.,0.,0.));
#393=DIRECTION('center_axis',(0.,0.,1.));
#394=DIRECTION('ref_axis',(1.,0.,0.));
#395=DIRECTION('center_axis',(0.,0.,1.));
#396=DIRECTION('ref_axis',(1.,0.,0.));
#397=DIRECTION('',(0.,0.,-1.));
#398=DIRECTION('center_axis',(0.,0.,1.));
#399=DIRECTION('ref_axis',(1.,0.,0.));
#400=DIRECTION('center_axis',(-0.998629534754574,0.,0.0523359562429438));
#401=DIRECTION('ref_axis',(0.0523359562429438,0.,0.998629534754574));
#402=DIRECTION('center_axis',(0.,0.,1.));
#403=DIRECTION('ref_axis',(1.,0.,0.));
#404=DIRECTION('center_axis',(0.,0.,1.));
#405=DIRECTION('ref_axis',(1.,0.,0.));
#406=DIRECTION('center_axis',(0.,0.,1.));
#407=DIRECTION('ref_axis',(1.,0.,0.));
#408=DIRECTION('center_axis',(-0.998629534754574,0.,0.0523359562429438));
#409=DIRECTION('ref_axis',(0.,-1.,0.));
#410=DIRECTION('',(0.,1.,0.));
#411=DIRECTION('',(0.,1.,0.));
#412=DIRECTION('center_axis',(0.,0.,1.));
#413=DIRECTION('ref_axis',(1.,0.,0.));
#414=DIRECTION('center_axis',(0.,0.,1.));
#415=DIRECTION('ref_axis',(1.,0.,0.));
#416=CARTESIAN_POINT('',(0.,0.,0.));
#417=CARTESIAN_POINT('Origin',(-32.5,40.25,8.6));
#418=CARTESIAN_POINT('',(-31.25,41.5,8.6));
#419=CARTESIAN_POINT('',(-33.75,41.5,8.6));
#420=CARTESIAN_POINT('',(-33.75,41.5,8.6));
#421=CARTESIAN_POINT('',(-31.25,39.,8.6));
#422=CARTESIAN_POINT('',(-31.25,41.5,8.6));
#423=CARTESIAN_POINT('',(-33.75,39.,8.6));
#424=CARTESIAN_POINT('',(-31.25,39.,8.6));
#425=CARTESIAN_POINT('',(-33.75,39.,8.6));
#426=CARTESIAN_POINT('Origin',(-31.25,41.5,4.6));
#427=CARTESIAN_POINT('',(-31.3117572189413,41.5,4.6));
#428=CARTESIAN_POINT('',(-31.4165727775074,41.5,6.6));
#429=CARTESIAN_POINT('',(-31.3118701541713,41.5,4.60215493256167));
#430=CARTESIAN_POINT('',(-31.25,41.5,4.6));
#431=CARTESIAN_POINT('',(-31.875,41.5,4.6));
#432=CARTESIAN_POINT('',(-31.25,41.5,4.6));
#433=CARTESIAN_POINT('',(-33.75,41.5,4.6));
#434=CARTESIAN_POINT('',(-33.75,41.5,4.6));
#435=CARTESIAN_POINT('',(-33.6882427810587,41.5,4.6));
#436=CARTESIAN_POINT('',(-31.875,41.5,4.6));
#437=CARTESIAN_POINT('',(-33.5834272224926,41.5,6.6));
#438=CARTESIAN_POINT('',(-33.6847060304338,41.5,4.66748522210396));
#439=CARTESIAN_POINT('',(-31.875,41.5,6.6));
#440=CARTESIAN_POINT('Origin',(-31.25,39.,4.6));
#441=CARTESIAN_POINT('',(-31.25,39.,4.6));
#442=CARTESIAN_POINT('',(-31.25,39.625,4.6));
#443=CARTESIAN_POINT('',(-31.25,39.,4.6));
#444=CARTESIAN_POINT('Origin',(-33.75,39.,4.6));
#445=CARTESIAN_POINT('',(-31.4165727775074,39.,6.6));
#446=CARTESIAN_POINT('',(-31.3117572189413,39.,4.6));
#447=CARTESIAN_POINT('',(-31.3152939695662,39.,4.66748522210396));
#448=CARTESIAN_POINT('',(-33.5834272224926,39.,6.6));
#449=CARTESIAN_POINT('',(-33.125,39.,6.6));
#450=CARTESIAN_POINT('',(-33.6882427810587,39.,4.6));
#451=CARTESIAN_POINT('',(-33.6881298458287,39.,4.60215493256167));
#452=CARTESIAN_POINT('',(-33.75,39.,4.6));
#453=CARTESIAN_POINT('',(-33.125,39.,4.6));
#454=CARTESIAN_POINT('',(-33.75,39.,4.6));
#455=CARTESIAN_POINT('',(-33.125,39.,4.6));
#456=CARTESIAN_POINT('Origin',(-33.75,41.5,4.6));
#457=CARTESIAN_POINT('',(-33.75,40.875,4.6));
#458=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#459=CARTESIAN_POINT('',(-31.3117572189413,43.004646818244,4.6));
#460=CARTESIAN_POINT('',(-31.3117572189413,38.8190911978746,4.6));
#461=CARTESIAN_POINT('',(-31.3117572189413,37.495353181756,4.6));
#462=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#463=CARTESIAN_POINT('',(-31.3117572189413,38.8190911978746,4.6));
#464=CARTESIAN_POINT('Origin',(-31.312152245655,37.3881823957492,4.60753755871915));
#465=CARTESIAN_POINT('',(-31.4165727775074,43.0475320290502,6.6));
#466=CARTESIAN_POINT('',(-31.4165727775074,38.8190911978746,6.6));
#467=CARTESIAN_POINT('Origin',(-32.5,40.25,27.2730229235879));
#468=CARTESIAN_POINT('Origin',(-31.312152245655,37.3881823957492,4.60753755871915));
#469=CARTESIAN_POINT('',(-31.4165727775074,37.4524679709498,6.6));
#470=CARTESIAN_POINT('Origin',(-32.5,40.25,27.2730229235879));
#471=CARTESIAN_POINT('',(-31.4165727775074,38.8190911978746,6.6));
#472=CARTESIAN_POINT('Origin',(-32.5,40.25,6.6));
#473=CARTESIAN_POINT('',(-33.5834272224926,43.0475320290502,6.6));
#474=CARTESIAN_POINT('',(-33.5834272224926,41.6809088021254,6.6));
#475=CARTESIAN_POINT('Origin',(-32.5,40.25,6.6));
#476=CARTESIAN_POINT('Origin',(-33.687847754345,43.1118176042508,4.60753755871915));
#477=CARTESIAN_POINT('',(-33.6882427810587,43.004646818244,4.6));
#478=CARTESIAN_POINT('',(-33.6882427810587,41.6809088021254,4.6));
#479=CARTESIAN_POINT('Origin',(-32.5,40.25,27.2730229235879));
#480=CARTESIAN_POINT('Origin',(-32.5,40.25,9.9));
#481=CARTESIAN_POINT('',(-35.3,40.25,10.1));
#482=CARTESIAN_POINT('Origin',(-32.5,40.25,10.1));
#483=CARTESIAN_POINT('',(-35.5,40.25,9.9));
#484=CARTESIAN_POINT('Origin',(-35.3,40.25,9.9));
#485=CARTESIAN_POINT('Origin',(-32.5,40.25,9.9));
#486=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#487=CARTESIAN_POINT('',(-35.5,40.25,4.59999999999997));
#488=CARTESIAN_POINT('',(-35.5,40.25,4.6));
#489=CARTESIAN_POINT('',(-33.6882427810587,37.495353181756,4.6));
#490=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#491=CARTESIAN_POINT('',(-33.5834272224926,37.4524679709498,6.6));
#492=CARTESIAN_POINT('Origin',(-32.5,40.25,27.2730229235879));
#493=CARTESIAN_POINT('Origin',(-32.5,40.25,6.6));
#494=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#495=CARTESIAN_POINT('Origin',(-32.5,40.25,10.1));
#496=CARTESIAN_POINT('Origin',(-33.687847754345,43.1118176042508,4.60753755871915));
#497=CARTESIAN_POINT('',(-33.5834272224926,41.6809088021254,6.6));
#498=CARTESIAN_POINT('',(-33.6882427810587,41.6809088021254,4.6));
#499=CARTESIAN_POINT('Origin',(-32.5,40.25,6.6));
#500=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#501=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#505,
'DISTANCE_ACCURACY_VALUE',
'Maximum model space distance between geometric entities at asserted c
onnectivities');
#502=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#505,
'DISTANCE_ACCURACY_VALUE',
'Maximum model space distance between geometric entities at asserted c
onnectivities');
#503=(
GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#501))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#505,#506,#507))
REPRESENTATION_CONTEXT('','3D')
);
#504=(
GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#502))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#505,#506,#507))
REPRESENTATION_CONTEXT('','3D')
);
#505=(
LENGTH_UNIT()
NAMED_UNIT(*)
SI_UNIT(.MILLI.,.METRE.)
);
#506=(
NAMED_UNIT(*)
PLANE_ANGLE_UNIT()
SI_UNIT($,.RADIAN.)
);
#507=(
NAMED_UNIT(*)
SI_UNIT($,.STERADIAN.)
SOLID_ANGLE_UNIT()
);
#508=SHAPE_DEFINITION_REPRESENTATION(#509,#510);
#509=PRODUCT_DEFINITION_SHAPE('',$,#512);
#510=SHAPE_REPRESENTATION('',(#300),#503);
#511=PRODUCT_DEFINITION_CONTEXT('part definition',#516,'design');
#512=PRODUCT_DEFINITION('sc64_shell reworked','sc64_shell reworked v10',
#513,#511);
#513=PRODUCT_DEFINITION_FORMATION('',$,#518);
#514=PRODUCT_RELATED_PRODUCT_CATEGORY('sc64_shell reworked v10',
'sc64_shell reworked v10',(#518));
#515=APPLICATION_PROTOCOL_DEFINITION('international standard',
'automotive_design',2009,#516);
#516=APPLICATION_CONTEXT(
'Core Data for Automotive Mechanical Design Process');
#517=PRODUCT_CONTEXT('part definition',#516,'mechanical');
#518=PRODUCT('sc64_shell reworked','sc64_shell reworked v10',$,(#517));
#519=PRESENTATION_STYLE_ASSIGNMENT((#523));
#520=PRESENTATION_STYLE_ASSIGNMENT((#524));
#521=PRESENTATION_STYLE_ASSIGNMENT((#525));
#522=PRESENTATION_STYLE_ASSIGNMENT((#526));
#523=SURFACE_STYLE_USAGE(.BOTH.,#527);
#524=SURFACE_STYLE_USAGE(.BOTH.,#528);
#525=SURFACE_STYLE_USAGE(.BOTH.,#529);
#526=SURFACE_STYLE_USAGE(.BOTH.,#530);
#527=SURFACE_SIDE_STYLE('',(#531));
#528=SURFACE_SIDE_STYLE('',(#532));
#529=SURFACE_SIDE_STYLE('',(#533));
#530=SURFACE_SIDE_STYLE('',(#534));
#531=SURFACE_STYLE_FILL_AREA(#535);
#532=SURFACE_STYLE_FILL_AREA(#536);
#533=SURFACE_STYLE_FILL_AREA(#537);
#534=SURFACE_STYLE_FILL_AREA(#538);
#535=FILL_AREA_STYLE('Steel - Satin',(#539));
#536=FILL_AREA_STYLE('Plastic - Translucent Matte (Blue)',(#540));
#537=FILL_AREA_STYLE('Powder Coat - Rough (White)',(#541));
#538=FILL_AREA_STYLE('Plastic - Glossy (Black)',(#542));
#539=FILL_AREA_STYLE_COLOUR('Steel - Satin',#543);
#540=FILL_AREA_STYLE_COLOUR('Plastic - Translucent Matte (Blue)',#544);
#541=FILL_AREA_STYLE_COLOUR('Powder Coat - Rough (White)',#545);
#542=FILL_AREA_STYLE_COLOUR('Plastic - Glossy (Black)',#546);
#543=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157);
#544=COLOUR_RGB('Plastic - Translucent Matte (Blue)',0.188235294117647,
0.231372549019608,0.588235294117647);
#545=COLOUR_RGB('Powder Coat - Rough (White)',0.964705882352941,0.964705882352941,
0.952941176470588);
#546=COLOUR_RGB('Plastic - Glossy (Black)',0.0980392156862745,0.0980392156862745,
0.0980392156862745);
ENDSEC;
END-ISO-10303-21;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,17 @@
TOOLCHAIN = mips64-elf-
N64_BINDIR = $(N64_INST)/bin
TOOLCHAIN = $(N64_BINDIR)/mips64-elf-
CC = $(TOOLCHAIN)gcc
CXX = $(TOOLCHAIN)g++
OBJCOPY = $(TOOLCHAIN)objcopy
OBJDUMP = $(TOOLCHAIN)objdump
STRIP = $(TOOLCHAIN)strip
SIZE = $(TOOLCHAIN)size
N64_ELFCOMPRESS = $(N64_BINDIR)/n64elfcompress
N64_TOOL = $(N64_BINDIR)/n64tool
PYTHON = python3
FLAGS = -march=vr4300 -mtune=vr4300 $(USER_FLAGS)
FLAGS = -march=vr4300 -mtune=vr4300 -mfix4300 $(USER_FLAGS)
CFLAGS = -Os -Wall -ffunction-sections -fdata-sections -ffreestanding -MMD -MP
ASFLAGS = -Wa,-I$(N64_INST)/mips64-elf/lib
LDFLAGS = -lc -nostartfiles -Wl,--gc-sections
@ -19,18 +24,20 @@ BUILD_DIR = build
SRC_FILES = \
startup.S \
boot.c \
crc32.c \
cic.c \
display.c \
error.c \
exception.c \
exception.S \
font.c \
init.c \
interrupt.c \
interrupts.c \
interrupts.S \
io.c \
ipl2.S \
joybus.c \
main.c \
menu.c \
reboot.S \
sc64.c \
syscalls.c \
test.c \
@ -69,19 +76,20 @@ $(BUILD_DIR)/%.asset.o: $(BUILD_DIR)/%.asset $(ASSET_DIR)/assets.S
$(BUILD_DIR)/bootloader.elf: $(OBJS) N64.ld
$(CXX) $(FLAGS) $(LDFLAGS) -TN64.ld $(OBJS) -o $@
@$(OBJDUMP) -S $@ > $(BUILD_DIR)/bootloader.lst
$(BUILD_DIR)/bootloader.bin: $(BUILD_DIR)/bootloader.elf tools/finalize.py
@$(OBJCOPY) -O binary $< $@
@$(PYTHON) tools/finalize.py $@ > /dev/null
print_size: $(BUILD_DIR)/bootloader.elf
@echo 'Size of modules:'
@$(SIZE) -B -d -t --common $(OBJS)
@echo 'Size of bootloader:'
@$(SIZE) -B -d $<
@$(SIZE) -B -d $@
@$(OBJDUMP) -S $@ > $(BUILD_DIR)/bootloader.lst
all: $(BUILD_DIR)/bootloader.bin print_size
$(BUILD_DIR)/bootloader.bin: $(BUILD_DIR)/bootloader.elf
@cp $< $<.stripped
@$(STRIP) -s $<.stripped
@cp $<.stripped $<.compressed
@$(N64_ELFCOMPRESS) -c 2 -o $(dir $<) $<.compressed
@$(N64_TOOL) --title "SC64 bootloader" --output $@ --align 256 $<.compressed
all: $(BUILD_DIR)/bootloader.bin
clean:
@rm -rf ./$(BUILD_DIR)/*

Some files were not shown because too many files have changed in this diff Show More