mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2025-04-12 21:51:17 +02:00
Compare commits
134 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
88d654129a | ||
![]() |
b88c9a314b | ||
![]() |
e4c3f34fb0 | ||
![]() |
b520f9ace8 | ||
![]() |
d8c4f979cc | ||
![]() |
d63f5893da | ||
![]() |
d307e1a5b1 | ||
![]() |
65f8fa3cf7 | ||
![]() |
6c566bd530 | ||
![]() |
99060bec15 | ||
![]() |
63feaa0c2e | ||
![]() |
a59ad1d39b | ||
![]() |
30fb3d0ea6 | ||
![]() |
a3d4082384 | ||
![]() |
0739ca624c | ||
![]() |
bb1ce45dfe | ||
![]() |
9193e9c6f2 | ||
![]() |
3fbb6f3823 | ||
![]() |
f546e5d17d | ||
![]() |
8393963650 | ||
![]() |
20a9ec0087 | ||
![]() |
b3d9e98e68 | ||
![]() |
6698550dbd | ||
![]() |
18041e2547 | ||
![]() |
0538a28f9e | ||
![]() |
1ade3ade8e | ||
![]() |
80b4aa95cd | ||
![]() |
6eef811cd6 | ||
![]() |
e2c100ae7f | ||
![]() |
a6e86587ae | ||
![]() |
93ab101be4 | ||
![]() |
cc41652e6f | ||
![]() |
ed63eb3e8c | ||
![]() |
db4f16754f | ||
![]() |
74e20cb8cc | ||
![]() |
3146cc8c99 | ||
![]() |
4a50e33acd | ||
![]() |
d12bfaabf6 | ||
![]() |
04cecb1955 | ||
![]() |
a5284aa770 | ||
![]() |
bbcf041b5a | ||
![]() |
12e16b807a | ||
![]() |
92fb4a85df | ||
![]() |
1259687902 | ||
![]() |
d8976def97 | ||
![]() |
e9ee025e21 | ||
![]() |
912f356650 | ||
![]() |
631f140c48 | ||
![]() |
71cef2cd6c | ||
![]() |
1b71b4a333 | ||
![]() |
5e33e516a2 | ||
![]() |
5adc95b6e1 | ||
![]() |
acc3e588d8 | ||
![]() |
a571fe16f5 | ||
![]() |
903efe5353 | ||
![]() |
e4af127e55 | ||
![]() |
6bbfee44e7 | ||
![]() |
9843a79a86 | ||
![]() |
80c06f3e53 | ||
![]() |
554305290e | ||
![]() |
e6751c262d | ||
![]() |
92838da349 | ||
![]() |
a884d69308 | ||
![]() |
7bc4e6d180 | ||
![]() |
a0bd0ddd98 | ||
![]() |
b8632a305b | ||
![]() |
b89ca68cb4 | ||
![]() |
0f3eaa6d17 | ||
![]() |
5854b4ec0d | ||
![]() |
9599db8307 | ||
![]() |
cf19dc6151 | ||
![]() |
0e868b5ad5 | ||
![]() |
8a49e954ce | ||
![]() |
3b13d21e63 | ||
![]() |
4eaa0b3353 | ||
![]() |
64c3b69454 | ||
![]() |
83bcfd3065 | ||
![]() |
61bd3c62d8 | ||
![]() |
2846938c5f | ||
![]() |
0050688255 | ||
![]() |
03daabeae8 | ||
![]() |
e93cecfae3 | ||
![]() |
0150060f1e | ||
![]() |
42b10e85f1 | ||
![]() |
cff730cafc | ||
![]() |
f6b94aec97 | ||
![]() |
c156b72bee | ||
![]() |
f27f644a7e | ||
![]() |
5b880fc052 | ||
![]() |
a12641bf39 | ||
![]() |
01bef4060e | ||
![]() |
b4b3659458 | ||
![]() |
7a83fb3eae | ||
![]() |
66f71c2040 | ||
![]() |
95b78f3cd9 | ||
![]() |
421d0438f3 | ||
![]() |
be37025d42 | ||
![]() |
17c12f5957 | ||
![]() |
f7eb6a73b4 | ||
![]() |
b84213b3e4 | ||
![]() |
356f1f2f0f | ||
![]() |
42acb48004 | ||
![]() |
1f7be611d8 | ||
![]() |
13fc38fe73 | ||
![]() |
2639a93b6f | ||
![]() |
7ea74f19a5 | ||
![]() |
7f21902e21 | ||
![]() |
d7aadf48f9 | ||
![]() |
5ae3e32d63 | ||
![]() |
ef053f9c52 | ||
![]() |
3ed1ad4d73 | ||
![]() |
c14da52f46 | ||
![]() |
6c1446c9df | ||
![]() |
bf13434f40 | ||
![]() |
3f3f1e3b86 | ||
![]() |
ff27e35ae8 | ||
![]() |
e0198083ae | ||
![]() |
fe855c31ae | ||
![]() |
73716de8f6 | ||
![]() |
ebb2b3b77e | ||
![]() |
473f3b883b | ||
![]() |
bee41d1d04 | ||
![]() |
6eb89688ab | ||
![]() |
5c6f25500a | ||
![]() |
a28e118cba | ||
![]() |
129bb4b800 | ||
![]() |
e170abdcd3 | ||
![]() |
b68d4a4be0 | ||
![]() |
bfd501dd8a | ||
![]() |
664092036f | ||
![]() |
a4a52fd15a | ||
![]() |
716123fedf | ||
![]() |
b3a9d5ff63 | ||
![]() |
c4f6a0d555 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -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
1
.github/FUNDING.yml
vendored
@ -1,2 +1 @@
|
||||
github: polprzewodnikowy
|
||||
ko_fi: polprzewodnikowy
|
||||
|
27
.github/ISSUE_TEMPLATE/bug_report.md
vendored
27
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -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
58
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal 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
|
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -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
|
||||
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -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.
|
20
.github/PULL_REQUEST_TEMPLATE/default.md
vendored
20
.github/PULL_REQUEST_TEMPLATE/default.md
vendored
@ -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.
|
117
.github/workflows/build.yml
vendored
117
.github/workflows/build.yml
vendored
@ -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
103
README.md
@ -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
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
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
BIN
assets/sc64_pcb_front.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 429 KiB |
59
build.sh
59
build.sh
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
31
docs/02_n64_commands.md
Normal 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 |
|
@ -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 |
|
@ -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
773
docs/03_usb_interface.md
Normal 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 |
|
@ -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
23
docs/05_fw_and_sw_info.md
Normal 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
144
docs/06_build_guide.md
Normal 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
|
||||
|
||||
[](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.
|
@ -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.
|
@ -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)
|
||||
|
2
fw/project/lcmxo2/.gitignore
vendored
2
fw/project/lcmxo2/.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
.recovery
|
||||
*.dir/
|
||||
*.ccl
|
||||
*.dat
|
||||
*.dmp
|
||||
*.html
|
||||
*.ini
|
||||
@ -11,6 +12,7 @@
|
||||
*.tcl
|
||||
*.tpf
|
||||
*.trc
|
||||
*.txt
|
||||
*.xml
|
||||
impl*/
|
||||
|
||||
|
@ -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
|
||||
|
1
fw/project/lcmxo2/debug.sty
generated
1
fw/project/lcmxo2/debug.sty
generated
@ -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"/>
|
||||
|
@ -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"
|
||||
|
23
fw/project/lcmxo2/release.sty
generated
23
fw/project/lcmxo2/release.sty
generated
@ -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"/>
|
||||
|
@ -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>
|
||||
|
@ -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" ;
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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
|
||||
|
@ -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
31
fw/rtl/memory/dma_scb.sv
Normal 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
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
245
fw/rtl/n64/n64_cic.sv
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
67
fw/rtl/serv/serv_aligner.v
vendored
Normal 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
81
fw/rtl/serv/serv_alu.v
vendored
Normal 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
51
fw/rtl/serv/serv_bufreg.v
vendored
Normal 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
65
fw/rtl/serv/serv_bufreg2.v
vendored
Normal 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
234
fw/rtl/serv/serv_compdec.v
vendored
Normal 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
142
fw/rtl/serv/serv_csr.v
vendored
Normal 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
84
fw/rtl/serv/serv_ctrl.v
vendored
Normal 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
365
fw/rtl/serv/serv_decode.v
vendored
Normal 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
95
fw/rtl/serv/serv_immdec.v
vendored
Normal 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
69
fw/rtl/serv/serv_mem_if.v
vendored
Normal 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
149
fw/rtl/serv/serv_rf_if.v
vendored
Normal 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
45
fw/rtl/serv/serv_rf_ram.v
vendored
Normal 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
174
fw/rtl/serv/serv_rf_ram_if.v
vendored
Normal 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
216
fw/rtl/serv/serv_rf_top.v
vendored
Normal 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
224
fw/rtl/serv/serv_state.v
vendored
Normal 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
659
fw/rtl/serv/serv_top.v
vendored
Normal 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
|
@ -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
|
||||
|
@ -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
37
fw/rtl/usb/usb_scb.sv
Normal 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
|
@ -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)
|
||||
);
|
||||
|
@ -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 ;
|
||||
|
@ -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
1
fw/tests/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
35
fw/tests/Makefile
Normal file
35
fw/tests/Makefile
Normal 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
|
126
fw/tests/benches/memory_dma_tb.sv
Normal file
126
fw/tests/benches/memory_dma_tb.sv
Normal 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
|
119
fw/tests/benches/usb_ft1248_tb.sv
Normal file
119
fw/tests/benches/usb_ft1248_tb.sv
Normal 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
22
fw/tests/docker_run.sh
Executable 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
|
39
fw/tests/mocks/dma_controller_mock.sv
Normal file
39
fw/tests/mocks/dma_controller_mock.sv
Normal 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
|
145
fw/tests/mocks/fifo_bus_fifo_mock.sv
Normal file
145
fw/tests/mocks/fifo_bus_fifo_mock.sv
Normal 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
|
49
fw/tests/mocks/fifo_mock.sv
Normal file
49
fw/tests/mocks/fifo_mock.sv
Normal 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
|
70
fw/tests/mocks/memory_sdram_mock.sv
Normal file
70
fw/tests/mocks/memory_sdram_mock.sv
Normal 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
33
fw/tests/mocks/vendor/fifo_8kb.sv
vendored
Normal 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
2
fw/tests/traces/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.vcd
|
||||
*.gtkw
|
2
hw/pcb/.gitignore
vendored
2
hw/pcb/.gitignore
vendored
@ -1,5 +1,7 @@
|
||||
*.lck
|
||||
**/*-backups
|
||||
**/*-bak
|
||||
**/*.3dshapes
|
||||
**/*.csv
|
||||
**/*.gerbers
|
||||
**/*.kicad_prl
|
||||
|
289
hw/pcb/LICENSE
Normal file
289
hw/pcb/LICENSE
Normal 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
31
hw/pcb/ibom.config.ini
Normal 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
|
4414
hw/pcb/sc64_hw_v2.0a_bom.html
generated
4414
hw/pcb/sc64_hw_v2.0a_bom.html
generated
File diff suppressed because one or more lines are too long
95785
hw/pcb/sc64v2.kicad_pcb
95785
hw/pcb/sc64v2.kicad_pcb
File diff suppressed because it is too large
Load Diff
@ -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": {}
|
||||
|
52341
hw/pcb/sc64v2.kicad_sch
52341
hw/pcb/sc64v2.kicad_sch
File diff suppressed because it is too large
Load Diff
4669
hw/pcb/sc64v2_bom.html
generated
Normal file
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
12
hw/shell/README.md
Normal 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))
|
BIN
hw/shell/button/sc64_shell_button_b3fs-101x.stl
Normal file
BIN
hw/shell/button/sc64_shell_button_b3fs-101x.stl
Normal file
Binary file not shown.
600
hw/shell/button/sc64_shell_button_b3fs-105x.step
Normal file
600
hw/shell/button/sc64_shell_button_b3fs-105x.step
Normal 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;
|
1367
hw/shell/button/sc64_shell_button_b3fs-105x_with_end_stop.step
Normal file
1367
hw/shell/button/sc64_shell_button_b3fs-105x_with_end_stop.step
Normal file
File diff suppressed because it is too large
Load Diff
27534
hw/shell/injection mold/sc64_bottom.step
Normal file
27534
hw/shell/injection mold/sc64_bottom.step
Normal file
File diff suppressed because it is too large
Load Diff
41323
hw/shell/injection mold/sc64_shell.stp
Normal file
41323
hw/shell/injection mold/sc64_shell.stp
Normal file
File diff suppressed because it is too large
Load Diff
18846
hw/shell/injection mold/sc64_top.step
Normal file
18846
hw/shell/injection mold/sc64_top.step
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
Loading…
x
Reference in New Issue
Block a user