├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── check-style.yml │ └── unit-test.yml ├── .gitignore ├── .images └── tree_core_logo.svg ├── 3RD_PARTY.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── fpga ├── .gitignore └── README.md ├── report └── tc_l2.md ├── rtl ├── TreeCoreL1 │ └── tc_l1 │ │ ├── hello │ │ ├── Makefile │ │ ├── hello.cpp │ │ └── hello.v │ │ └── switch │ │ ├── Makefile │ │ ├── top.cpp │ │ └── top.v └── TreeCoreL2 │ ├── .scalafmt.conf │ ├── Makefile │ ├── build.sc │ ├── scripts │ ├── copy.sh │ ├── env.sh │ ├── install.sh │ ├── record.sh │ ├── setup.sh │ └── template.sh │ └── tc_l2 │ ├── Makefile │ └── src │ └── main │ ├── csrc │ ├── emu.h │ └── main.cpp │ └── scala │ ├── axi4 │ ├── AXI4Bridge.scala │ ├── Arbiter.scala │ └── Crossbar.scala │ ├── common │ ├── AXI4Config.scala │ ├── Helper.scala │ ├── InstConfig.scala │ ├── NumExten.scala │ └── Timer.scala │ ├── core │ ├── Processor.scala │ ├── StallControl.scala │ ├── TreeCoreL2.scala │ ├── ex │ │ ├── ACU.scala │ │ ├── ALU.scala │ │ ├── BEU.scala │ │ ├── CSRReg.scala │ │ ├── Divider.scala │ │ ├── EXU.scala │ │ ├── MDU.scala │ │ └── Multiplier.scala │ ├── id │ │ ├── IDU.scala │ │ ├── ISADecoder.scala │ │ ├── ImmExten.scala │ │ └── RegFile.scala │ ├── if │ │ ├── BPU.scala │ │ ├── BTB.scala │ │ ├── Cache.scala │ │ ├── GHR.scala │ │ ├── IFU.scala │ │ └── PHT.scala │ ├── ma │ │ ├── CLINT.scala │ │ ├── LSU.scala │ │ └── MAU.scala │ └── wb │ │ └── WBU.scala │ ├── port │ ├── AXI4IO.scala │ ├── BRANCHIO.scala │ ├── COREIO.scala │ ├── CSRIO.scala │ ├── DXCHGIO.scala │ ├── EX2MEMIO.scala │ ├── ID2EXIO.scala │ ├── IF2IDIO.scala │ ├── IFIO.scala │ ├── LSIO.scala │ ├── MDUIO.scala │ ├── MEM2WBIO.scala │ ├── NXTPCIO.scala │ └── WBDATAIO.scala │ ├── top │ ├── SimTop.scala │ ├── SoCTop.scala │ └── TopMain.scala │ └── utils │ ├── AddModulePrefix.scala │ ├── Debug.scala │ └── Difftest.scala ├── tests ├── .gitignore ├── README.md ├── compile_rtl.py ├── compliance_test.py └── run_all_isa_test.py └── tools ├── bin2mem.py ├── bin2mif.py └── env ├── hello_world_tb.gtkw ├── hello_world_tb.sh └── hello_world_tb.v /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /.github/workflows/check-style.yml: -------------------------------------------------------------------------------- 1 | name: check-style 2 | 3 | on: 4 | push: 5 | branches: [ main, tc-l2 ] 6 | 7 | jobs: 8 | check-style: 9 | name: Check Code Style 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Install dependencies 14 | run: | 15 | echo "fake action" -------------------------------------------------------------------------------- /.github/workflows/unit-test.yml: -------------------------------------------------------------------------------- 1 | name: unit-test 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | difftest-isa-test: 9 | name: Difftest ISA Test 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Install dependencies 14 | run: | 15 | cd rtl/TreeCoreL2 16 | chmod +x scripts/install.sh 17 | make install 18 | chmod +x scripts/setup.sh 19 | make setup 20 | make nemuBuild 21 | make dramsim3Build 22 | make riscvTestBuild 23 | make cpuTestBuild 24 | make CHIP_TARGET=tc_l2 RUN_PLATFORM=action unit-test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env/*.vcd 2 | env/*.vvp 3 | *.swp 4 | out 5 | build 6 | .bsp 7 | am 8 | NEMU 9 | difftest 10 | ysyxSoC 11 | DRAMsim3 12 | dramsim3.json 13 | dramsim3.txt 14 | dramsim3epoch.json 15 | *.vcd 16 | *.wave 17 | .mypy_cache 18 | .pytest_cache 19 | .metals 20 | .vscode 21 | dependency 22 | __pycache__ -------------------------------------------------------------------------------- /.images/tree_core_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 25 | 28 | 32 | 33 | 34 | 57 | 62 | 63 | 65 | 66 | 68 | image/svg+xml 69 | 71 | 72 | 73 | 74 | 75 | 80 | 90 | TC 102 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /3RD_PARTY.md: -------------------------------------------------------------------------------- 1 | # Open Source License Acknowledgements and Third-Party Copyrights 2 | 3 | TreeCore CPU utilizes third party software from various sources. Portions of this software are copyrighted by their respective owners as indicated in the copyright notices below. 4 | 5 | The following acknowledgements pertain to this software license. 6 | 7 | ## Main components used by TreeCore CPU 8 | These components are installed via [Makefile](./rtl/Makefile). You can check all the dependencies using the specific target in Makefile. 9 | 10 | ### verilator 11 | * maintainer: [verilator](https://github.com/verilator) 12 | * License: [LGPL-3.0](https://github.com/verilator/verilator/blob/master/LICENSE) 13 | * repo: https://github.com/verilator/verilator 14 | 15 | ### mill 16 | * maintainer: [com-lihaoyi](https://github.com/com-lihaoyi) 17 | * License: [MIT](https://github.com/com-lihaoyi/mill/blob/main/LICENSE) 18 | * repo: https://github.com/com-lihaoyi/mill 19 | 20 | ### riscv-test 21 | * maintainer: [NJU-ProjectN](https://github.com/NJU-ProjectN) 22 | * License: [custom](https://github.com/NJU-ProjectN/riscv-tests/blob/master/LICENSE) 23 | * repo: https://github.com/NJU-ProjectN/riscv-tests 24 | 25 | ### difftest 26 | * maintainer: [oscpu](https://gitee.com/oscpu) 27 | * License: [MulanPSL-2.0](https://gitee.com/oscpu/difftest/blob/master/LICENSE) 28 | * repo: https://gitee.com/oscpu/difftest 29 | 30 | ### NEMU 31 | * maintainer: [oscpu](https://gitee.com/oscpu) 32 | * License: [MulanPSL-2.0](https://gitee.com/oscpu/difftest/blob/master/LICENSE) 33 | * repo: https://gitee.com/oscpu/NEMU 34 | 35 | ### DRAMsim3 36 | * maintainer: [OpenXiangShan](https://github.com/OpenXiangShan) 37 | * License: [MIT](https://github.com/OpenXiangShan/DRAMsim3/blob/co-simulation/LICENSE) 38 | * repo: https://github.com/OpenXiangShan/DRAMsim3 39 | 40 | ### ysyxSoC 41 | * maintainer: [oscpu](https://github.com/OSCPU) 42 | * License: [custom](https://github.com/OSCPU/ysyxSoC/blob/master/LICENSE.Berkeley) 43 | * repo: https://github.com/OSCPU/ysyxSoC 44 | 45 | ## Libraries modified for TreeCore CPU 46 | These libraries derive from [NJU-ProjectN](https://github.com/NJU-ProjectN) and are modified specifically for TreeCore CPU. 47 | 48 | ### abstract-machine 49 | * maintainer: [maksyuki](https://github.com/maksyuki) 50 | * License: [GPL-3.0](https://github.com/maksyuki/ysyx-software-file/blob/master/LICENSE) 51 | * repo: https://github.com/maksyuki/ysyx-software-file/tree/master/abstract-machine 52 | 53 | ### am-kernels 54 | * maintainer: [maksyuki](https://github.com/maksyuki) 55 | * License: [GPL-3.0](https://github.com/maksyuki/ysyx-software-file/blob/master/LICENSE) 56 | * repo: https://github.com/maksyuki/ysyx-software-file/tree/master/am-kernels -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | maksyuki@126.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contribute 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Tree Core CPU 3 |

TreeCore CPU: A Series of RISCV Processors Written from Scratch

4 |

5 |

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | stars 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |

25 | 26 | 27 | ## Overview 28 | The TreeCore processors are the riscv cores developed under the [Open Source Chip Project by University (OSCPU)](https://github.com/OSCPU) project. OSCPU was initiated by ICT, CAS(**_Institute of computing Technology, Chinese Academy of Sciences_**), which aims to make students use all open-source toolchains to design chips by themselves. Students enroll in this project need to pass tests, submit final design report and prepare oral defense for the qualification of tape-out. It also can be called "One Life, One Chip" project in Chinese which has carried out three season: 29 | ### Season 1[**2021.8-2021.12**]: Five undergraduates design a tape-outed riscv processor in four months 30 | Season 1 was a first educational practice which aimed to design riscv processor by five undergraduates for tape-out in China. And its achievement was [NutShell](https://github.com/OSCPU/NutShell), [a Linux-Compatible RISC-V Processor Designed by Undergraduates](https://www.youtube.com/watch?v=8K97ahPecqE). Five students are all from UCAS(**_University of Chinese Academy of Sciences_**). 31 | 32 | ### Season 2[**2020.8-2021.x**]: Eleven undergraduates design their own tape-outed processors 33 | Unlike Season 1, Season 2 had eleven undergraduates from five universities to design processors, and it is the first attempt to promote this project to the other university. 34 | 35 | ### Season 3[**2021.7-2022.1**]: More students(One hundred students), More open source tools(NEMU, difftest, AM...) 36 | TreeCoreL1[[1]](#id_tcl1) and TreeCoreL2[[2]](#id_tcl2) are the achievement of this season. After about six months of development, TreeCoreL2 obtained the qualification of tape-out in second shuttle. You can visit the official website [ysyx.org](https://ysyx.org/) to get more information. 37 | > NOTE: The PCB card with TreeCoreL2 possible return in the second quarter of 2022, so on board debugging cannot release now. 38 | 39 | ### Season 4[**2022.2.20-2022.10.28, in progress**]: More open source IPs(SDRAM, VGA...), Smoother learning curve(bbs, tutorials, lecture, ...) 40 | TreeCoreL3[[3]](#id_tcl3) will be the expected achievement of this season. TreeCoreL3 is a 64-bits single-issue, five-stage pipeline riscv core with cache written in verilog. Different from the TreeCoreL2, the all softare runtimes to support TreeCoreL3 is implemented by myself. 41 | 42 | ### Season 5[**2022.8.28-2023.2.10, in progress**]: Provide living broadcast course and development flow forzen 43 | TreeCoreL4[[4]](#id_tcl4) will be the expected achievement of this season. TreeCoreL4 is a 64-bits two-issue, six-stage pipeline riscv core with cache written in chisel3. 44 | 45 | Now the TreeCore has two version: TreeCoreL1(**_TreeCore Learning 1_**) and TreeCoreL2(**_TreeCore Learning 2_**). The TreeCore project aims to help students to learn how to write riscv processors by themselves with **step-to-step materials**. Not like textbooks only exhibit all of concepts in one time, the learn process of TreeCore is incremental. That means TreeCore only provides a very simple model with necessary new knowledges you need to learn first, then add extra codes to perfect the whole design every time until it is finished. 46 | 47 | 48 | ## Story and Motivation 49 | I heard the word '**_riscv_**' first time in sophomore year(2016). At that time, my roommate participated in the pilot class of **_Computer Architecture_**, and their final assignment was to **design a simple riscv processor**. In fact, I only knew it was an open source RISC ISA launched by the UC, Berkeley. What is unexpected to me is that just after a few period of time, the riscv has been supported by many semiconductor giants and research institutions and **more and more people believe riscv will usher in a revolution that can change the old pattern in someday**. 50 | 51 | I've always thought the best way to learn is to practice myself. When searching online, I found the learning threshold of processor is high. In addition, in order to pursue high performance, some open-source riscv cores are very complex(such as using dynamics branch prediction, multi-core processing, out-of-order execution technology, etc), these are very difficult for beginners to learn. In meanwhile, I learned that "One Life, One Chip" project with many ailge hardware developement tools. So why not design and implement processors with these new tools from scratch? The result of that desire is this project. 52 | 53 | I hope it can become a ABC project like Arduino to make more processor enthusiasts and computer related specialized students enter into the computer architecture field more easily. 54 | 55 | ## Feature 56 | IMG!!!!!!!!!!!!!!!! to intro three type processor and timeline. 57 | 58 | **intro** the plan with the such as the target every type core need to meet. and timeline 59 | 60 | ## Usage 61 | This section introduces how to set up development environment and runs unit test for your own riscv processor. Project directory is: 62 | ```bash 63 | env -> 64 | | hello_world_tb.gtkw # gtkwave wave config 65 | | hello_world_tb.sh # compile script 66 | | hello_world_tb.v # hello world verilog module 67 | fpga -> 68 | | bare_metal/ # bare metal verilog module for fpga 69 | report -> 70 | | tc_l2.md # treecore l2 wiki 71 | rtl -> 72 | | TreeCoreL1 73 | | TreeCoreL2 74 | tests -> 75 | | compile_rtl.py # bare metal module compile script 76 | | compliance_test.py # isa compliance test 77 | | run_all_isa_test.py # run all isa test 78 | tools -> 79 | | bin2mem.py # convert bin file to mem file 80 | | bin2mif.py # convert bin file to mif file 81 | ``` 82 | 83 | ## TreeCoreL1 84 | * 64-bits FSM 85 | * written by verilog 86 | 87 | In fact, TreeCoreL1 is not a processor, it is a bundle of some independent verilator programs and common chisel modules writing for learning. 88 | 89 | ## TreeCoreL2 90 |

91 | 92 |

93 | TreeCoreL2 data flow graph 94 |

95 |

96 | 97 | * 64-bits single-issue, five-stage pipeline riscv core 98 | * written by chisel3 99 | * support RISCV integer(I) instruction set 100 | * supports machine mode privilege levels 101 | * supports AXI4 inst and mem acess 102 | * supports dynamics branch prediction 103 | * can boot rt-thread 104 | * develop under all open-source toolchain 105 | asdafafaadsfsafa 106 | IMG!!!!!!!!!!!!!!! 107 | 108 | 109 | ### Develop Schedule 110 | Now, the develop schedule of TreeCore is recorded by the **Tencent Document**. You can click below link to view it: 111 | 112 | 1. TreeCoreL1&2(**frozen**): [link](https://docs.qq.com/sheet/DY3lORW5Pa3pLRFpT?newPad=1&newPadType=clone&tab=BB08J2) 113 | 114 | ### Memory Map 115 | To compatible with ysyx3 SoC test, TreeCoreL2 have below memory map range: 116 | 117 | | Range | Description | 118 | | ------------------------- | --------------------------------------------------- | 119 | | 0x0000_0000 - 0x01ff_ffff | reserve | 120 | | 0x0200_0000 - 0x0200_ffff | clint | 121 | | 0x0201_0000 - 0x0fff_ffff | reserve | 122 | | 0x1000_0000 - 0x1000_0fff | uart16550 | 123 | | 0x1000_1000 - 0x1000_1fff | spi controller | 124 | | 0x1000_2000 - 0x2fff_ffff | reserve | 125 | | 0x3000_0000 - 0x3fff_ffff | spi flash xip mode | 126 | | 0x4000_0000 - 0x7fff_ffff | chiplink | 127 | | 0x8000_0000 - 0x8xxx_xxxx | mem | 128 | 129 | #### Configuration 130 | 131 | ### Enviroment Setup 132 | > NOTE: All of the components and tools are installed under linux operation system. To gurantee the compatibility and stability, I **STRONGLY** recommend using `ubuntu 20.04 LTS`. `ubuntu 18.04` and `ubuntu 16.04` is not supported official. 133 | 134 | If you're new to TreeCore project, we suggest you start with the install section. Remeber you **ONLY** need to install the below libraries once. Now all of operations(config, compile, test) have been automated by Makefile. You can visit [unit-test.yml](.github/workflows/unit-test.yml) to get more information. 135 | > NOTE: In order to download and configure all libraries successful, you **NEED** to be able to visit github.com and gitee.com. 136 | 137 | First, you need to install verilator, mill, difftest, abstract-machine and other dependency libraries: 138 | ```bash 139 | $ git clone https://github.com/microdynamics-cpu/tree-core-cpu.git 140 | $ cd tree-core-cpu/rtl 141 | $ chmod +x scripts/install.sh 142 | $ make install 143 | ``` 144 | Then, download and configuare all components from the github and gitee: 145 | ```bash 146 | $ chmod +x scripts/setup.sh 147 | $ make setup 148 | ``` 149 | After that, you need to add the `NEMU_HOME` and `NOOP_HOME` environment variables to your shell environment config file: 150 | ```bash 151 | $ echo export NEMU_HOME=$(pwd)/dependency/NEMU >> ~/.bashrc # according to shell type your system uses 152 | $ echo export NOOP_HOME=$(pwd)/dependency >> ~/.bashrc 153 | $ source ~/.bashrc 154 | ``` 155 | 156 | Running the ISA test don't need 8G memory, so you can reconfigure the `memory size` to reduce the simulation memory usage. Achieving that, you need to type `make menuconfig` as follow: 157 | 158 | ```bash 159 | $ cd dependency/NEMU 160 | $ make menuconfig 161 | ``` 162 | > NOTE: if you encounter `Your display is too small to run Menuconfig!` error, you need to resize the terminal to match need as the console output: `It must be at least 19 lines by 80 columns`. 163 | 164 |

165 | 166 |

167 | The main configuration menu 168 |

169 |

170 | 171 | Usually, 256MB memory address space is enough for simulation. You need to switch into `[Memory - Configuration]` menu and change `[Memory size]` value into `0x10000000` manually as follow picture shows. It can adjust difftest's simulation memory size from 8G to 256MB. 172 | 173 | > NOTE: In fact, the `Memory size` has been modified to `0x10000000` in `make setup` phase. Now, you only need to confirm it once more time. 174 |

175 | 176 |

177 | The memory address size menu 178 |

179 |

180 | 181 | Last, remember to type `Save` button in bottom menu to save the `.config` file. Then, type `Exit` to exit the menuconfig. 182 | 183 | ### Compile runtime libraries 184 | If you already run above commands correctly, you can compile runtime libraries as follow: 185 | 186 | ```bash 187 | $ cd ../../ 188 | $ make nemuBuild 189 | $ make dramsim3Build 190 | ``` 191 | 192 | ### Compile testcases 193 | Two type of ISA testcases set are used: `riscv test` and `cpu test`. 194 | ```bash 195 | $ make riscvTestBuild 196 | $ make cpuTestBuild 197 | $ make amTestBuild 198 | ``` 199 | > NOTE: you need enough memory to compile the application binaries. Generally speaking, you need at least 4GB of memory. 200 | 201 | ### Recursive test 202 | After you modify the processor design, you need to run recursive unit test to gurantee the modification is correct. 203 | 204 | ```bash 205 | $ make CHIP_TARGET=tc_l2 unit-test 206 | ``` 207 | 208 | The unit tests display the progress, testcase name, PASS or FAIL and ipc value. 209 |

210 | 211 |

212 | TreeCoreL2's unit test result 213 |

214 |

215 | 216 | Running unit test need to download `mill` from github.com. If you cannot access the github correctly, you need to type below commands to configure `mill` manually: 217 | 218 | ```bash 219 | $ # download '0.9.9-assembly' from https://github.com/com-lihaoyi/mill/releases/download/0.9.9/0.9.9-assembly manually. 220 | $ cp 0.9.9-assembly ~/.cache/mill/download 221 | $ mv ~/.cache/mill/download/0.9.9-assembly ~/.cache/mill/download/0.9.9 # change name 222 | $ chmod +x ~/.cache/mill/download/0.9.9 223 | ``` 224 | 225 | ### Software test 226 | Software test, also called application test, can provide integrated test for interrupt. You need to recompile the amtest with specific `AM_TARGET` when you want to change the software target. 227 | ```bash 228 | # the 'AM_TARGET' option value(default h): 229 | # h => "hello" 230 | # H => "display this help message" 231 | # i => "interrupt/yield test" 232 | # d => "scan devices" 233 | # m => "multiprocessor test" 234 | # t => "real-time clock test" 235 | # k => "readkey test" 236 | # v => "display test" 237 | # a => "audio test" 238 | # p => "x86 virtual memory test" 239 | $ make amTestBuild AM_TARGET=i 240 | $ make amTest 241 | ``` 242 | 243 | ### Benchmark test 244 | First, you need to compile the benchmark programs. 245 | ```bash 246 | $ make coremarkTestBuild 247 | $ make dhrystoneTestBuild 248 | $ make microbenchTestBuild 249 | ``` 250 | ```bash 251 | $ make coremarkTest 252 | $ make dhrystoneTest 253 | $ make microbenchTest 254 | ``` 255 | 256 | ### SoC test 257 | SoC test is based on ysyxSoC project. SoC test provides more accurate simulation environment for processor design. 258 | 259 | ```bash 260 | $ make CHIP_TARGET=tc_l2 socBuild 261 | # SOC_APP_TYPE: flash, loader 262 | # SOC_APP_NAME: hello, memtest, rtthread 263 | $ make CHIP_TARGET=tc_l2 SOC_APP_TYPE=flash SOC_APP_NAME=hello socTest 264 | ``` 265 | ### Add and Customize new project 266 | ```bash 267 | # First modify the `CHIP_TARGET` in Makefile to your custom name which create folder. 268 | $ make template 269 | ``` 270 | 271 | ## TreeCoreL3(_under development_) 272 | 273 | 274 | ## TreeCoreL4(_under development_) 275 | * 64-bits five-stage pipeline riscv core 276 | 277 | ## Plan 278 | 279 | ## Update 280 | 281 | ## License 282 | TreeCore CPU's codes are release under the [GPL-3.0 License](./LICENSE) and compliance with other open source agreements. You can find all 3rd party libraries licenses in [3RD_PARTY.md](./3RD_PARTY.md). 283 | 284 | ## Acknowledgement 285 | 1. [oscpu-framework](https://github.com/OSCPU/oscpu-framework) 286 | 2. [NutShell](https://github.com/OSCPU/NutShell) 287 | 288 | ## Reference 289 | 290 | -------------------------------------------------------------------------------- /fpga/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.area 3 | *.db 4 | *.bit 5 | *.o 6 | *.vcd -------------------------------------------------------------------------------- /fpga/README.md: -------------------------------------------------------------------------------- 1 | ## test 2 | -------------------------------------------------------------------------------- /report/tc_l2.md: -------------------------------------------------------------------------------- 1 | # 一生一芯第三期项目报告 2 | 3 | ## 个人介绍 4 | 5 | 我是缪宇驰,学号是20210324。西北工业大学航天学院精确制导与控制研究所在读研究生,将于2022年6月毕业。2018年本科毕业于西北工业大学航天学院探测制导与控制技术专业。现主要研究方向为微小卫星空间科学探测,星载计算机设计,小天体表面空间机器人运动规划和仿真。目前参与国家自然科学基金一项,发表国内论文一篇。曾获得研究生一等奖学金等。擅长FPGA板级电路设计开发和调试。热爱开源软硬件运动,业余时间从事开源工具类软件开发,[个人github地址](https://github.com/maksyuki)。 6 | 7 | 以前没有实际设计过处理器核,参加一生一芯三期算是我第一次完整实现一个处理器。 8 | 9 | ## 项目概述 10 | 11 | - 项目地址: [tree-core-cpu](https://github.com/microdynamics-cpu/tree-core-cpu) 12 | - 开发语言:chisel 13 | - 许可证:GPL-3.0 14 | 15 | TreeCoreL2是一个支持RV64I的单发射5级流水线的开源处理器核。支持axi4总线取指和访存,支持动态分支预测(BTB, PHT, GHR),支持机器特权模式下的异常中断处理。能够在difftest和soc仿真环境下启动rt-thread。 16 | 17 | ## 微架构设计 18 |

19 | 20 |

21 | TreeCoreL2 总体数据流图 22 |

23 |

24 | 25 | TreeCoreL2的微架构设计采用经典的5级流水线结构,取指和访存的请求通过crossbar进行汇总并转换成自定义的axi-like总线**data exchange(dxchg)**,最后通过转换桥将dxchg协议转换成axi4协议并进行仲裁。下面将着重介绍**取指**、**执行**、**访存**、**crossbar&axi4转换桥**和**流水线控制**五部分的具体实现。 26 | 27 | ### 取指 28 | 取指单元主要功能是计算出下一个周期的pc并向axi总线发送读请求。pc通过多路选择器按照优先级从高到低依次选取`mtvec`、`mepc`、`jump target`、 `branch predict target`和`pc + 4`的值。BPU采用基于全局历史的两级预测器。相关参数如下: 29 | 1. Global History Reister(GHR): bit width = 5 30 | 2. Pattern History Table(PHT): size = 32 31 | 3. Branch Target Buffer(BTB): line size = 64(pc) + 64(target) + 1(jump) size = 32 32 | 33 | GHR每次从EXU得到分支是否taken的信息用于更新GHR移位寄存器的值,之后输出更新后值到PHT中并与当前pc求异或(**_gshare_**)。其结果作为PHT检索对应entry的地址,PHT每次从EXU得到分支执行后信息用于更新自己。BTB的每个Line记录一个1位的jump,64位的pc和64位的tgt值。1位的jump表示当前记录的指令是否是一个无条件跳转指令。虽然BTB中留有jump的标志,但是目前并不对无条件跳转指令进行预测。因为有些jump指令的target可能是不固定的,比如函数调用中的`ret`指令,会使得BTB以上一次保存的target进行预测,进而跳转到错误的地址。 34 | 35 |

36 | 37 |

38 | 取指单元主体部分 39 |

40 |

41 | 42 | 由于目前TreeCore2的取指和访存没有使用cache,处理器核需要大量时钟周期来等待axi的响应,所以采用动态分支预测技术后对ipc的提升较小。 43 |

44 | 45 |

46 | 使用分支预测对性能的一点改进 47 |

48 |

49 | 50 | ### 执行 51 | 执行单元主要用于执行算术逻辑计算、计算分支指令的跳转地址。另外还设计了一个乘除法单元(MDU)和加速计算单元(ACU)用于对矩阵乘除法进行加速,但是由于个人进度的影响,没能按期调通cache,故没有将MDU,ACU集成到提交的版本中。最后执行单元中还实现了CSR寄存器,用于对环境调用异常和中断进行处理。其中`EXU.scala`中的83~92行代码为跳转控制逻辑的核心代码: 52 | 53 | ```scala 54 | io.nxtPC.trap := valid && (timeIntrEn || ecallEn) 55 | io.nxtPC.mtvec := csrReg.io.csrState.mtvec 56 | io.nxtPC.mret := valid && (isa === instMRET) 57 | io.nxtPC.mepc := csrReg.io.csrState.mepc 58 | // (pred, fact)--->(NT, T) or (T, NT) 59 | protected val predNTfactT = branch && !predTaken 60 | protected val predTfactNT = !branch && predTaken 61 | io.nxtPC.branch := valid && (predNTfactT || predTfactNT) 62 | io.nxtPC.tgt := Mux(valid && predNTfactT, tgt, Mux(valid && predTfactNT, pc + 4.U, 0.U(XLen.W))) 63 | io.stall := valid && (io.nxtPC.branch || timeIntrEn || ecallEn || (isa === instMRET)) 64 | ``` 65 | 66 | ### 访存 67 | 访存单元集成了LSU和CLINT,其中LSU负责生成访存所需的读写控制信号(size, wmask等)。CLINT则读入生成的控制信号,若访存的地址处于`0x0200_0000 - 0x0200_ffff`之间,则处理访存的信号,否则将控制信号透传出去。 68 |

69 | 70 |

71 | 72 | ### Crossbar&Axi4转换桥 73 | crossbar负责将取值和访存的请求进行合并,统一成一个自定义的axi-like总线**data exchange(dxchg)**,dxchg其实和axi-lite很接近。不过考虑之后扩展的需要,故自定义了一个。axi4转换桥将crossbar的dxchg总线接口转换成标准axi4总线,axi4采用单主机模式,主要通过crossbar中状态机的不同状态来区分一次axi请求是取值还是访存: 74 | 75 |

76 | 77 |

78 | axi总线访存实现 79 |

80 |

81 | 82 | 状态机有两个状态`eumInst`和`eumMem`,初始化后处于`eumInst`,当IFU发送取值请求并等到axi的响应后,表示一次取值请求完成,同时状态会转移到`eumMem`。状态切换到`eumMem`是因为对于一条指令来说,其只可能是访存指令,在MAU中发起读写axi请求;或是非访存指令,不发起请求。由于TreeCoreL2的微架构实现中不存在处理连续两个访存请求的情况,所以状态机在一次访存后一定会切换到取值状态。 83 | 84 | 85 | 86 | ### 流水线控制 87 | TreeCoreL2通过旁路实现RAW数据冒险,另外TreeCoreL2的流水线每一级都有一个valid信号,当置`false.B`时,流水线会被stall。使流水线暂停的信号有: 88 | 1. axi4的读写请求,只有当取指或者访存完成后才会重启流水线 89 | 2. 无条件跳转指令和条件跳转指令预测错误时,会暂停idu和ifu的流水线 90 | 3. 环境调用异常`ecall`、定时器中断触发或者中断处理程序返回执行`mret`时,会暂停idu和ifu的流水线 91 | 92 | 93 | ## 项目结构和参考 94 | TreeCore的代码仓库结构借鉴了[riscv-sodor](https://github.com/ucb-bar/riscv-sodor)和[oscpu-framework](https://github.com/OSCPU/oscpu-framework)组织代码的方式并使用make作为项目构建工具,同时Makefile里面添加了模板参数,可以支持多个不同处理器的独立开发,能够直接使用`make [target]`下载、配置相关依赖软件、生成、修改面向不同平台(difftest和soc)的verilog文件,执行回归测试等。 95 | 96 |

97 | 98 |

99 | 使用make自定义函数实现回归测试target 100 |

101 |

102 | 103 | 1. 在编码过程中使用到的chisel类型和object: 104 | - `ListLookup`: 用于IDU中进行指令解码 105 | - `MuxLookup`:用于实现多路复用器 106 | - `Counter`:用于在CLINT中生成低速时钟驱动mtime自增 107 | - `PopCount`:在AXIBridge中计算发送给axi总线的size 108 | - `Decoupled`:用于实现axi总线的输入输出接口 109 | 110 | 2. 另外TreeCore的实现和测试依赖于众多项目,其中包括: 111 | - [chisel3](https://github.com/chipsalliance/chisel3) 112 | - [verilator](https://github.com/verilator/verilator) 113 | - [NEMU](https://gitee.com/oscpu/NEMU) 114 | - [DRAMsim3](https://github.com/OpenXiangShan/DRAMsim3) 115 | - [difftest](https://gitee.com/oscpu/difftest) 116 | - [Abstract Machine](https://github.com/NJU-ProjectN/abstract-machine) 117 | - [ysyxSoC](https://github.com/OSCPU/ysyxSoC) 118 | - [riscv-tests](https://github.com/NJU-ProjectN/riscv-tests) 119 | 3. 立即数扩展模块部分参考了[果壳处理器](https://github.com/OSCPU/NutShell)的实现方式 120 | 4. 流水线结构和各功能单元安排部分参考了[蜂鸟E203](https://github.com/riscv-mcu/e203_hbirdv2) 121 | 122 | ## 总结 123 | 124 | ### 心得感想 125 | 首先,要衷心地感谢一生一芯三期项目的所有老师,助教同学们一直以来的辛苦付出。去年自己有幸赶到上科大参加了RISCV中国峰会,香山处理器的系列报告让我大饱眼福。当听说新一期一生一芯项目准备面向全国高校学生开放后,作为一名研三临近毕业的学生,深感这次机会的来之不易,便毫不犹豫地报了名。在实际编码调试过程中让我重新学习了很多知识,比如内存地址对齐问题。我记得我第一次听说“地址对齐”这个名词还是13年我大一学c语言的时候,当时老师在讲解union类型时引出了这个概念。但是当时对这个概念没有深入学习下去,这导致我在刚开始调试axi仲裁的时候一直没搞对地址的掩码计算,花了很长时间。另外参加一生一芯三期对于我来说也是个不小的挑战,因为它要求独立开发,要在很短的时间内学习很多新知识,使用很多新工具,而这些是我以前做过的课程实验所没有的。在具体开发过程中,由于本人跨专业的原因,体系结构相关知识比较薄弱,所以很多内容都要从零开始学起。另外我还要兼顾科研任务,毕设实验和找工作等多项事情,时间很紧张,有时很长时间没法调试出一个bug也会让我感到沮丧和迷茫。但是相比于参加之前,自己也确实收获了实实在在的成长。通过参加一生一芯三期,我完整地实现了一个处理器核,虽然还不太完美。学习了chisel,verilator,difftest等众多开源处理器开发工具及其背后的敏捷开发思想,也加深了对软硬件之间工作原理的认知。当时的[进度表](https://docs.qq.com/sheet/DY3lORW5Pa3pLRFpT?newPad=1&newPadType=clone&tab=BB08J2)也记录下了自己开发调试过程中的点点滴滴。那种不停google->查书->编码->调试后bug被解决的喜悦让我终生难忘。 126 | 127 |

128 | 129 |

130 | TreeCoreL2开发进度表 131 |

132 |

133 | 134 | ### 文档资料整理 135 | 另外,在自己观看学习视频,编写、调试代码的过程中,为了方便自己复习、消化相关知识,我将自己平时曾踩过的坑以及qq群各位同学的问题记录了下来,并配以相关解答,总结成了一个FAQ文档。目前该文档有近3.7万字,202张图片,共126页。之后有时间将继续对文档中的相关内容进行补充,修改和更新。 136 | 137 |

138 | 139 |

140 | 总结的常见问题文档 141 |

142 |

143 | 144 | ### 一点开发过程中的想法: 波形与回归测试联合调试工具的设计 145 | difftest进行差分测试可以快速定位到出错的指令,却无法像波形那样直观地展现多周期完整的信号变化。考虑设计一个工具,当difftest对比到出错的指令时能够触发事件,而这个事件传递到波形组件后可以直接定位到对应时钟周期并显示临近的波形,以方便调试。后期的话考虑直接对波形进行解析,就像嵌入式领域的逻辑分析仪一样,能够直接将诸如操作数,stall等信息标注到波形上。 146 | 147 | ## 计划 148 | 目前开发的**TreeCoreL2**是TreeCore系列处理器核的第二个版本,目前基本达到设计目标,后续将会继续优化代码。而第三个版本(**TreeCoreL3**)和第四个版本(**TreeCoreL4**)将会追求更高的性能,也是规划中的参加一生一芯第四期和第五期的处理器。其中**TreeCoreL3**将在前代核的基础上,支持RV64IMAC指令,cache和mmu,并提高流水线级数,使其能够启动rt-thread,xv6和linux。**TreeCoreL4** 则会在**TreeCoreL3**的基础上实现浮点运算和多发射技术,进一步提高处理器性能。 149 | 150 | 对于TreeCoreL2来说: 151 | - 继续改进当前TreeCoreL2的微架构设计,能够使用更多chisel的特性来简化代码实现 152 | - 将处理器核移植到安路科技的fpga上 153 | 154 | 155 | -------------------------------------------------------------------------------- /rtl/TreeCoreL1/tc_l1/hello/Makefile: -------------------------------------------------------------------------------- 1 | comp: 2 | verilator -Wall --cc --exe --build hello.cpp hello.v -o emu -Mdir build 3 | 4 | run: 5 | ./build/emu 6 | 7 | .PHONY: 8 | comp run -------------------------------------------------------------------------------- /rtl/TreeCoreL1/tc_l1/hello/hello.cpp: -------------------------------------------------------------------------------- 1 | #include "Vhello.h" 2 | #include "verilated.h" 3 | 4 | int main(int argc, char **argv, char **env) 5 | { 6 | VerilatedContext *contextp = new VerilatedContext; 7 | contextp->commandArgs(argc, argv); 8 | Vhello *top = new Vhello{contextp}; 9 | while (!contextp->gotFinish()) 10 | { 11 | top->eval(); 12 | } 13 | delete top; 14 | delete contextp; 15 | return 0; 16 | } -------------------------------------------------------------------------------- /rtl/TreeCoreL1/tc_l1/hello/hello.v: -------------------------------------------------------------------------------- 1 | module hello; 2 | initial begin 3 | $display("Hello World"); 4 | $finish; 5 | end 6 | endmodule 7 | -------------------------------------------------------------------------------- /rtl/TreeCoreL1/tc_l1/switch/Makefile: -------------------------------------------------------------------------------- 1 | comp: 2 | verilator -Wall --cc --exe --build top.cpp top.v -o emu -Mdir build 3 | 4 | run: 5 | ./build/emu 6 | 7 | .PHONY: 8 | comp run -------------------------------------------------------------------------------- /rtl/TreeCoreL1/tc_l1/switch/top.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "Vtop.h" 6 | #include "verilated.h" 7 | 8 | int main(int argc, char **argv, char **env) 9 | { 10 | VerilatedContext *contextp = new VerilatedContext; 11 | contextp->commandArgs(argc, argv); 12 | Vtop *top = new Vtop{contextp}; 13 | while (!contextp->gotFinish()) 14 | { 15 | int a = rand() & 1; 16 | int b = rand() & 1; 17 | top->a = a; 18 | top->b = b; 19 | top->eval(); 20 | printf("a = %d, b = %d, f = %d\n", a, b, top->f); 21 | assert(top->f == a ^ b); 22 | } 23 | delete top; 24 | delete contextp; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /rtl/TreeCoreL1/tc_l1/switch/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input a, 3 | input b, 4 | output f 5 | ); 6 | assign f = a ^ b; 7 | endmodule 8 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = 2.6.4 2 | 3 | maxColumn = 300 4 | align = most 5 | continuationIndent.defnSite = 2 6 | assumeStandardLibraryStripMargin = true 7 | docstrings = ScalaDoc 8 | lineEndings = preserve 9 | includeCurlyBraceInSelectChains = false 10 | danglingParentheses.preset = true 11 | 12 | align.tokens.add = [ 13 | { 14 | code = ":" 15 | }, 16 | { 17 | code = "->" 18 | }, 19 | { 20 | code = "<>" 21 | }, 22 | { 23 | code = ":=" 24 | }, 25 | { 26 | code = "=" 27 | } 28 | ] 29 | 30 | newlines.alwaysBeforeCurlyBraceLambdaParams = false 31 | newlines.alwaysBeforeMultilineDef = false 32 | newlines.implicitParamListModifierForce = [before] 33 | 34 | verticalMultiline.atDefnSite = true 35 | 36 | optIn.annotationNewlines = true 37 | 38 | rewrite.rules = [SortImports, PreferCurlyFors, AvoidInfix] 39 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/bin/bash 2 | 3 | # be carefully, this path will be used in clean(rm -rf)!!! 4 | # github action or native 5 | RUN_PLATFORM ?= native 6 | # need to set the $(CHIP_TARGET) with tc_lx(2, 3, 4...) 7 | CHIP_TARGET ?= tc_l2 8 | ROOT_PATH := $(shell pwd)/dependency 9 | SOURCE_PATH := $(ROOT_PATH)/../tc_l2 10 | BUILD_DIR := $(SOURCE_PATH)/build 11 | MILL_OUT_DIR := $(ROOT_PATH)/../out 12 | 13 | AM_FOLDER_PATH := $(ROOT_PATH)/am 14 | AM_KERNEL_PATH := $(AM_FOLDER_PATH)/am-kernels 15 | VERSION_ID := riscv64-mycpu 16 | 17 | SIMPLETEST_HOME := $(AM_FOLDER_PATH)/simple-tests 18 | RISCVTEST_HOME := $(AM_FOLDER_PATH)/riscv-tests 19 | FCEMUX_HOME := $(AM_FOLDER_PATH)/fceux-am 20 | CPUTEST_HOME := $(AM_KERNEL_PATH)/tests/cpu-tests 21 | AMTEST_HOME := $(AM_KERNEL_PATH)/tests/am-tests 22 | COREMARK_HOME := $(AM_KERNEL_PATH)/benchmarks/coremark 23 | DHRYSTONE_HOME := $(AM_KERNEL_PATH)/benchmarks/dhrystone 24 | MICROBENCH_HOME := $(AM_KERNEL_PATH)/benchmarks/microbench 25 | DIFFTEST_HOME := $(ROOT_PATH)/difftest 26 | DRAMSIM3_HOME := $(ROOT_PATH)/DRAMsim3 27 | YSYXSOC_HOME := $(ROOT_PATH)/ysyxSoC/ysyx 28 | 29 | ###### soc var ###### 30 | SOC_CSRC_HOME += $(SOURCE_PATH)/src/main/csrc 31 | SOC_CSRC_LIB_HOME += $(ROOT_PATH)/ysyxSoC/ysyx/peripheral/spiFlash 32 | SOC_CXXFILES += $(shell find $(SOC_CSRC_HOME) -name "*.cpp") 33 | SOC_CXXFILES += $(shell find $(SOC_CSRC_LIB_HOME) -name "*.cpp") 34 | 35 | SOC_VSRC_HOME += $(BUILD_DIR)/soc 36 | SOC_COMPILE_HOME := $(SOC_VSRC_HOME)/emu-compile 37 | SOC_VSRC_TOP := ysyxSoCFull 38 | SOC_VSRC_LIB_HOME += $(ROOT_PATH)/ysyxSoC/ysyx/peripheral/ 39 | SOC_VXXFILES += $(shell find $(SOC_VSRC_HOME) -name "*.v") 40 | SOC_VXXFILES += $(shell find $(SOC_VSRC_LIB_HOME) -name "*.v") 41 | 42 | SOC_VSRC_INCLPATH += -I$(SOC_VSRC_HOME) 43 | SOC_VSRC_INCLPATH += -I$(ROOT_PATH)/ysyxSoC/ysyx/peripheral/uart16550/rtl 44 | SOC_VSRC_INCLPATH += -I$(ROOT_PATH)/ysyxSoC/ysyx/peripheral/spi/rtl 45 | SOC_CSRC_INCLPATH += -I$(SOC_CSRC_HOME) 46 | SOC_CSRC_INCLPATH += -I$(SOC_CSRC_LIB_HOME) 47 | 48 | # if want to ouput vcd wave, replace '-DDUMP_WAVE_FST' to '-DDUMP_WAVE_VCD', 49 | # replace '--trace-fst' to '--trace' 50 | SOC_CXXFLAGS += -std=c++11 -static -Wall $(SOC_CSRC_INCLPATH) -DDUMP_WAVE_FST 51 | SOC_FLAGS += --cc --exe --top-module $(SOC_VSRC_TOP) 52 | SOC_FLAGS += --x-assign unique -O3 -CFLAGS "$(SOC_CXXFLAGS)" 53 | SOC_FLAGS += --trace-fst --assert --stats-vars --output-split 30000 --output-split-cfuncs 30000 54 | SOC_FLAGS += --timescale "1ns/1ns" -Wno-fatal 55 | SOC_FLAGS += -o $(BUILD_DIR)/soc/emu 56 | SOC_FLAGS += -Mdir $(BUILD_DIR)/soc/emu-compile 57 | SOC_FLAGS += $(SOC_VSRC_INCLPATH) $(SOC_CXXFILES) $(SOC_VXXFILES) 58 | 59 | CCACHE := $(if $(shell which ccache),ccache,) 60 | ifneq ($(CCACHE),) 61 | export OBJCACHE = ccache 62 | endif 63 | 64 | 65 | export AM_HOME := $(AM_FOLDER_PATH)/abstract-machine 66 | export NEMU_HOME := $(ROOT_PATH)/NEMU 67 | export NOOP_HOME := $(ROOT_PATH) 68 | export DRAMSIM3_HOME := $(DRAMSIM3_HOME) 69 | 70 | define getRecursiveTestRes 71 | @printf "[%2d/%d]" $$(echo $$(cat $(1)/build/log/allcasenum-log.txt) + 1 | bc) $(2) 72 | @echo $$(echo $$(cat $(1)/build/log/allcasenum-log.txt) + 1 | bc) > $(1)/build/log/allcasenum-log.txt 73 | -@$(BUILD_DIR)/emu -i $< &> $(1)/build/log/$@-log.txt 74 | 75 | @printf "[%25s] " $@ 76 | @if (grep 'HIT GOOD TRAP' $(1)/build/log/$@-log.txt > /dev/null) then \ 77 | echo -e "\033[1;32mPASS! ipc =$$(grep 'IPC' $(1)/build/log/$@-log.txt | cut -d = -f4)\033[0m" \ 78 | $$(echo $$(echo $$(cat $(1)/build/log/passcasenum-log.txt) + 1 | bc) > $(1)/build/log/passcasenum-log.txt); \ 79 | else \ 80 | echo -e "\033[1;31mFAIL!\033[0m"; \ 81 | fi 82 | endef 83 | 84 | ###### dev env target ###### 85 | install: 86 | @./scripts/install.sh -g -c 87 | 88 | setup: 89 | @./scripts/setup.sh -a 90 | 91 | ###### project template target ###### 92 | template: 93 | @./scripts/template.sh -t $(CHIP_TARGET) 94 | 95 | ###### chisel target ###### 96 | millTest: 97 | mill -i $(CHIP_TARGET).test 98 | 99 | chiselBuild: 100 | mkdir -p $(BUILD_DIR) 101 | mill -i $(CHIP_TARGET).runMain top.TopMain -td $(BUILD_DIR) 102 | 103 | chiselHelp: 104 | mill -i $(CHIP_TARGET).runMain top.TopMain --help 105 | 106 | millCompile: 107 | mill -i $(CHIP_TARGET).compile 108 | 109 | millBsp: 110 | mill -i mill.bsp.BSP/install 111 | 112 | format: 113 | mill -i $(CHIP_TARGET).reformat 114 | 115 | checkformat: 116 | mill -i $(CHIP_TARGET).checkFormat 117 | 118 | ###### NEMU target ###### 119 | nemuBuild: 120 | $(MAKE) -C $(NEMU_HOME) 121 | 122 | ###### DRAMsim3 target ###### 123 | dramsim3Build: 124 | mkdir -p $(DRAMSIM3_HOME)/build 125 | cd $(DRAMSIM3_HOME)/build && cmake -D COSIM=1 .. 126 | $(MAKE) -C $(DRAMSIM3_HOME)/build 127 | 128 | ###### difftest target ###### 129 | # if want to use the RamHelper, need to remove the 'WITH_DRAMSIM3=1' 130 | # becuase the framework, now the 'memAXI_0_[r|w]_bits_data' need to be replaced 131 | # by 'memAXI_0_w_bits_data[3:0]' in Makefile 132 | difftestBuild: 133 | @sed -i 's/io_memAXI_0_\([a-z]*\)_bits_data,/io_memAXI_0_\1_bits_data[3:0],/g' $(BUILD_DIR)/SimTop.v 134 | @sed -i 's/io_memAXI_0_w_bits_data =/io_memAXI_0_w_bits_data[0] =/g' $(BUILD_DIR)/SimTop.v 135 | @sed -i 's/ io_memAXI_0_r_bits_data;/ io_memAXI_0_r_bits_data[0];/g' $(BUILD_DIR)/SimTop.v 136 | $(MAKE) -C $(DIFFTEST_HOME) WITH_DRAMSIM3=1 EMU_TRACE=1 DESIGN_DIR=$(SOURCE_PATH) 137 | 138 | changeTargetToSimTop: 139 | @sed -i 's/SoCEna\([ ]*\)=\([ ]*\)true/SoCEna\1=\2false/g' $(SOURCE_PATH)/src/main/scala/common/InstConfig.scala 140 | 141 | changeTargetToSoCTop: 142 | @sed -i 's/SoCEna\([ ]*\)=\([ ]*\)false/SoCEna\1=\2true/g' $(SOURCE_PATH)/src/main/scala/common/InstConfig.scala 143 | 144 | simBuild: changeTargetToSimTop chiselBuild difftestBuild 145 | 146 | simpleTestBuild: 147 | $(MAKE) -C $(SIMPLETEST_HOME) ARCH=$(VERSION_ID) 148 | 149 | ###### riscv-tests target ###### 150 | riscvTestBuild: 151 | $(MAKE) -C $(RISCVTEST_HOME) ARCH=$(VERSION_ID) 152 | 153 | ###### (am)cpu-tests target ###### 154 | cpuTestBuild: 155 | $(MAKE) -C $(CPUTEST_HOME) ARCH=$(VERSION_ID) 156 | 157 | ###### (am)am-tests target ###### 158 | # now only test the rtl-time and interrupt 159 | AM_TARGET ?=h 160 | amTestBuild: 161 | $(MAKE) -C $(AMTEST_HOME) ARCH=$(VERSION_ID) mainargs=$(AM_TARGET) 162 | 163 | ###### (am)coremark target ###### 164 | coremarkTestBuild: 165 | $(MAKE) -C $(COREMARK_HOME) ARCH=$(VERSION_ID) 166 | 167 | ###### (am)dhrystone target ###### 168 | dhrystoneTestBuild: 169 | $(MAKE) -C $(DHRYSTONE_HOME) ARCH=$(VERSION_ID) 170 | 171 | 172 | ###### (am)microbench target ###### 173 | microbenchTestBuild: 174 | $(MAKE) -C $(MICROBENCH_HOME) ARCH=$(VERSION_ID) mainargs=test 175 | 176 | 177 | ###### (am)fcemux target ###### 178 | fecmuxTestBuild: 179 | $(MAKE) -C $(FCEMUX_HOME) ARCH=$(VERSION_ID) mainargs=mario 180 | 181 | ###### demo test target ###### 182 | demoTest: 183 | $(BUILD_DIR)/emu -i $(RISCVTEST_HOME)/build/addi-$(VERSION_ID).bin 184 | 185 | 186 | ###### simple test recursive test target ###### 187 | simpleTestbinFile = $(foreach dir, $(SIMPLETEST_HOME)/build, $(wildcard $(dir)/*.bin)) 188 | simpleTestCaseName = $(foreach file, $(simpleTestbinFile), $(patsubst %-$(VERSION_ID), simpletest-%, $(basename $(notdir $(file))))) 189 | simpleTestLogFile = $(foreach file, $(simpleTestCaseName), $(patsubst %, %-log.txt, $(file))) 190 | $(shell if [[ -d $(SIMPLETEST_HOME) ]]; then mkdir -p $(SIMPLETEST_HOME)/build/log 1>/dev/null 2>&1; fi) 191 | 192 | simpleRecursiveTest: $(simpleTestLogFile) $(simpleTestCaseName) 193 | @printf "[\033[0;33m%s\033[0m]\n" all-done 194 | @echo -e "[\033[0;33mAll: $$(cat $(SIMPLETEST_HOME)/build/log/allcasenum-log.txt) \033[0;32mPASS: $$(cat $(SIMPLETEST_HOME)/build/log/passcasenum-log.txt) \033[0;31mFAIL: $$(echo $$(echo $$(cat $(SIMPLETEST_HOME)/build/log/allcasenum-log.txt) - $$(cat $(SIMPLETEST_HOME)/build/log/passcasenum-log.txt) | bc))\033[0m]"; 195 | 196 | $(simpleTestLogFile): 197 | $(shell touch $(SIMPLETEST_HOME)/build/log/$@) 198 | $(shell touch $(SIMPLETEST_HOME)/build/log/allcasenum-log.txt) 199 | $(shell touch $(SIMPLETEST_HOME)/build/log/passcasenum-log.txt) 200 | $(shell echo 0 > $(SIMPLETEST_HOME)/build/log/allcasenum-log.txt) 201 | $(shell echo 0 > $(SIMPLETEST_HOME)/build/log/passcasenum-log.txt) 202 | 203 | $(simpleTestCaseName): simpletest-%: $(SIMPLETEST_HOME)/build/%-$(VERSION_ID).bin 204 | @$(call getRecursiveTestRes, $(SIMPLETEST_HOME)) 205 | 206 | 207 | ###### riscv test recursive test target ###### 208 | riscvNum = 50 209 | riscvTestbinFile = $(foreach dir, $(RISCVTEST_HOME)/build, $(wildcard $(dir)/*.bin)) 210 | riscvTestCaseName = $(foreach file, $(riscvTestbinFile), $(patsubst %-$(VERSION_ID), riscvtest-%, $(basename $(notdir $(file))))) 211 | riscvTestLogFile = $(foreach file, $(riscvTestCaseName), $(patsubst %, %-log.txt, $(file))) 212 | $(shell if [[ -d $(RISCVTEST_HOME) ]]; then mkdir -p $(RISCVTEST_HOME)/build/log 1>/dev/null 2>&1; fi) 213 | 214 | riscvRecursiveTest: $(riscvTestLogFile) $(riscvTestCaseName) 215 | @printf "[\033[0;33mall-done\033[0m]\n" 216 | @echo -e "[\033[0;33mAll: $$(cat $(RISCVTEST_HOME)/build/log/allcasenum-log.txt) \033[0;32mPASS: $$(cat $(RISCVTEST_HOME)/build/log/passcasenum-log.txt) \033[0;31mFAIL: $$(echo $$(echo $$(cat $(RISCVTEST_HOME)/build/log/allcasenum-log.txt) - $$(cat $(RISCVTEST_HOME)/build/log/passcasenum-log.txt) | bc))\033[0m]"; 217 | 218 | $(riscvTestLogFile): 219 | $(shell touch $(RISCVTEST_HOME)/build/log/$@) 220 | $(shell touch $(RISCVTEST_HOME)/build/log/allcasenum-log.txt) 221 | $(shell touch $(RISCVTEST_HOME)/build/log/passcasenum-log.txt) 222 | $(shell echo 0 > $(RISCVTEST_HOME)/build/log/allcasenum-log.txt) 223 | $(shell echo 0 > $(RISCVTEST_HOME)/build/log/passcasenum-log.txt) 224 | 225 | $(riscvTestCaseName): riscvtest-%: $(RISCVTEST_HOME)/build/%-$(VERSION_ID).bin 226 | $(call getRecursiveTestRes, $(RISCVTEST_HOME), $(riscvNum)) 227 | 228 | 229 | ###### cpu test recursive test target ###### 230 | cpuTestbinFile = $(foreach dir, $(CPUTEST_HOME)/build, $(wildcard $(dir)/*.bin)) 231 | cpuTestCaseName = $(foreach file, $(cpuTestbinFile), $(patsubst %-$(VERSION_ID), cputest-%, $(basename $(notdir $(file))))) 232 | cpuTestLogFile = $(foreach file, $(cpuTestCaseName), $(patsubst %, %-log.txt, $(file))) 233 | $(shell if [[ -d $(CPUTEST_HOME) ]]; then mkdir -p $(CPUTEST_HOME)/build/log 1>/dev/null 2>&1; fi) 234 | 235 | cpuRecursiveTest: $(cpuTestLogFile) $(cpuTestCaseName) 236 | @printf "[\033[0;33mall-done\033[0m]\n" 237 | @echo -e "[\033[0;33mAll: $$(cat $(CPUTEST_HOME)/build/log/allcasenum-log.txt) \033[0;32mPASS: $$(cat $(CPUTEST_HOME)/build/log/passcasenum-log.txt) \033[0;31mFAIL: $$(echo $$(echo $$(cat $(CPUTEST_HOME)/build/log/allcasenum-log.txt) - $$(cat $(CPUTEST_HOME)/build/log/passcasenum-log.txt) | bc))\033[0m]"; 238 | 239 | $(cpuTestLogFile): 240 | $(shell touch $(CPUTEST_HOME)/build/log/$@) 241 | $(shell touch $(CPUTEST_HOME)/build/log/allcasenum-log.txt) 242 | $(shell touch $(CPUTEST_HOME)/build/log/passcasenum-log.txt) 243 | $(shell echo 0 > $(CPUTEST_HOME)/build/log/allcasenum-log.txt) 244 | $(shell echo 0 > $(CPUTEST_HOME)/build/log/passcasenum-log.txt) 245 | 246 | $(cpuTestCaseName): cputest-%: $(CPUTEST_HOME)/build/%-$(VERSION_ID).bin 247 | $(call getRecursiveTestRes, $(CPUTEST_HOME), 33) 248 | 249 | postTest: 250 | # ifeq dont's need to indent 251 | # ref to: https://stackoverflow.com/questions/55133855/how-to-compare-two-string-variables-in-makefile 252 | @echo -e "\033[0;33mstart post test check...\033[0m"; 253 | ifeq ($(RUN_PLATFORM), action) 254 | @if [ "$$(echo $$(echo $$(cat $(CPUTEST_HOME)/build/log/allcasenum-log.txt) - $$(cat $(CPUTEST_HOME)/build/log/passcasenum-log.txt) | bc))" = "0" ]; then\ 255 | echo -e "\033[0;32maction check pass!\033[0m";\ 256 | else \ 257 | echo -e "\033[0;31maction check fail!\033[0m";\ 258 | exit 1; \ 259 | fi 260 | endif 261 | @echo -e "\033[0;32mpost check done!\033[0m"; 262 | 263 | unit-test: simBuild riscvRecursiveTest cpuRecursiveTest postTest 264 | 265 | ###### benchmark(application) rule test target ###### 266 | # BUG: some error 267 | amTest: 268 | $(BUILD_DIR)/emu -i $(AMTEST_HOME)/build/amtest-$(VERSION_ID).bin 269 | 270 | coremarkTest: 271 | $(BUILD_DIR)/emu -i $(COREMARK_HOME)/build/coremark-$(VERSION_ID).bin 272 | 273 | dhrystoneTest: 274 | $(BUILD_DIR)/emu -i $(DHRYSTONE_HOME)/build/dhrystone-$(VERSION_ID).bin 275 | 276 | microbenchTest: 277 | $(BUILD_DIR)/emu -i $(MICROBENCH_HOME)/build/microbench-$(VERSION_ID).bin 278 | ###### soc name rule test target ###### 279 | socTopModify: 280 | @mkdir -p $(BUILD_DIR)/soc 281 | @cp $(BUILD_DIR)/SoCTop.v $(BUILD_DIR)/soc/ysyx_210324.v 282 | @sed -i 's/module ysyx_210324_SoCTop/module ysyx_210324/g' $(BUILD_DIR)/soc/ysyx_210324.v 283 | @sed -i 's/io_\([a-z]*\)_\([a-z]*\)_[bits]*_*\([a-z]*\)/io_\1_\2\3/g' $(BUILD_DIR)/soc/ysyx_210324.v 284 | 285 | # FIMXE: need a better solution, not just copy to dir everytime 286 | socNameCheck: socTopModify 287 | @cp $(YSYXSOC_HOME)/soc/cpu-check.py $(BUILD_DIR)/soc 288 | @cd $(BUILD_DIR)/soc && echo 324 | python3 cpu-check.py 289 | 290 | socLintCheck: socNameCheck 291 | @cp $(BUILD_DIR)/soc/ysyx_210324.v $(YSYXSOC_HOME)/lint/ 292 | @sed -i 's/ID = \([0-9]*\)/ID = 210324/g' $(YSYXSOC_HOME)/lint/Makefile 293 | @echo -e "\033[1;32mstart lint check....\033[0m" 294 | $(MAKE) -C $(YSYXSOC_HOME)/lint/ lint 295 | @echo -e "\033[1;32mlint check done\033[0m" 296 | @echo -e "\033[1;32mstart lint-unused check....\033[0m" 297 | $(MAKE) -C $(YSYXSOC_HOME)/lint/ lint-unused 298 | @echo -e "\033[1;32mlint-unused check done\033[0m" 299 | 300 | socPrevBuild: changeTargetToSoCTop chiselBuild socNameCheck 301 | # FIXME: if only need to moidfy core, comment below two lines 302 | # need to remove 'TestHarness' module from the ysyxSoCFull.v, 303 | # because it is the test top module 304 | @cp $(YSYXSOC_HOME)/soc/ysyxSoCFull.v $(BUILD_DIR)/soc 305 | @sed -i s/ysyx_000000/ysyx_210324/g $(BUILD_DIR)/soc/ysyxSoCFull.v 306 | @sed -i '/module TestHarness/,/endmodule/d' $(BUILD_DIR)/soc/ysyxSoCFull.v 307 | verilator $(SOC_FLAGS) 308 | 309 | socBuild: socPrevBuild 310 | $(MAKE) VM_PARALLEL_BUILDS=1 OPT_FAST="-O3" -C $(SOC_COMPILE_HOME) -f V$(SOC_VSRC_TOP).mk -j1 311 | 312 | # flash, loader 313 | SOC_APP_TYPE ?= flash 314 | # hello, memtest, rtthread 315 | SOC_APP_NAME ?= hello 316 | SOC_TARGET := $(SOC_APP_NAME)-$(SOC_APP_TYPE) 317 | socTest: 318 | # TODO: check if the bin exist! 319 | $(SOC_VSRC_HOME)/emu -i $(YSYXSOC_HOME)/program/bin/$(SOC_APP_TYPE)/$(SOC_TARGET).bin 320 | 321 | socSubmit: 322 | @cp $(BUILD_DIR)/soc/ysyx_210324.v ../../oscpu-submit/projects/soc/vsrc/ 323 | 324 | ###### clean target ###### 325 | cleanBuild: 326 | rm -rf $(BUILD_DIR) 327 | 328 | cleanMillOut: 329 | rm -rf $(MILL_OUT_DIR) 330 | 331 | cleanDepRepo: 332 | rm -rf $(AM_FOLDER_PATH) $(NEMU_HOME) $(DIFFTEST_HOME) 333 | 334 | cleanAll: cleanBuild cleanMillOut cleanDepRepo 335 | 336 | 337 | .PHONY: install setup \ 338 | template \ 339 | millTest chiselBuild chiselHelp millCompile millBsp format checkformat \ 340 | nemuBuild dramsim3Build difftestBuild changeTargetToSimTop changeTargetToSoCTop simBuild \ 341 | simpleTestBuild riscvTestBuild cpuTestBuild amTestBuild coremarkTestBuild \ 342 | dhrystoneTestBuild microbenchTestBuild fecmuxTestBuild demoTest \ 343 | simpleRecursiveTest riscvRecursiveTest cpuRecursiveTest postTest unit-test \ 344 | amTest coremarkTest dhrystoneTest microbenchTest \ 345 | socTopModify socNameCheck socLintCheck socPrevBuild socBuild socSubmit socTest\ 346 | cleanBuild cleanMillOut cleanDepRepo cleanAll 347 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/build.sc: -------------------------------------------------------------------------------- 1 | import mill._ 2 | import mill.scalalib._ 3 | import mill.scalalib.scalafmt.ScalafmtModule 4 | import mill.scalalib.TestModule.Utest 5 | import mill.bsp._ 6 | 7 | object tc_l2 extends ScalaModule with ScalafmtModule { m => 8 | override def scalaVersion = "2.12.13" 9 | override def scalacOptions = Seq( 10 | "-Xsource:2.11", 11 | "-language:reflectiveCalls", 12 | "-deprecation", 13 | "-feature", 14 | "-Xcheckinit", 15 | // Enables autoclonetype2 in 3.4.x (on by default in 3.5.0) 16 | // "-P:chiselplugin:useBundlePlugin" 17 | ) 18 | override def ivyDeps = Agg( 19 | ivy"edu.berkeley.cs::chisel3:3.5.0", 20 | ) 21 | override def scalacPluginIvyDeps = Agg( 22 | ivy"edu.berkeley.cs:::chisel3-plugin:3.5.0", 23 | ivy"org.scalamacros:::paradise:2.1.1" 24 | ) 25 | object test extends Tests with Utest { 26 | override def ivyDeps = m.ivyDeps() ++ Agg( 27 | ivy"com.lihaoyi::utest:0.7.10", 28 | ivy"edu.berkeley.cs::chiseltest:0.3.3", 29 | ) 30 | } 31 | 32 | override def moduleDeps = super.moduleDeps ++ Seq(difftest) 33 | } 34 | 35 | object difftest extends ScalaModule { 36 | override def scalaVersion = "2.12.13" 37 | override def millSourcePath = os.pwd / "dependency" / "difftest" 38 | override def ivyDeps = Agg( 39 | ivy"edu.berkeley.cs::chisel3:3.5.0" 40 | ) 41 | } -------------------------------------------------------------------------------- /rtl/TreeCoreL2/scripts/copy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # cp -r `ls | grep -v copy.sh | xargs` ../../../oscpu-dev-record/cpu 4 | cp -r src ../../../oscpu-dev-record/cpu 5 | # cp -r test ../../../oscpu-dev-record/cpu 6 | cp -r am/simple-tests ../../../ysyx-software-file 7 | # am-kernels 8 | cp -r am/am-kernels/benchmarks ../../../ysyx-software-file/am-kernels 9 | cp -r am/am-kernels/kernels ../../../ysyx-software-file/am-kernels 10 | cp -r am/am-kernels/LICENSE ../../../ysyx-software-file/am-kernels 11 | cp -r am/am-kernels/README ../../../ysyx-software-file/am-kernels 12 | cp -r am/am-kernels/tests ../../../ysyx-software-file/am-kernels 13 | # abstract-machine 14 | cp -r am/abstract-machine/am ../../../ysyx-software-file/abstract-machine 15 | cp -r am/abstract-machine/klib ../../../ysyx-software-file/abstract-machine 16 | cp -r am/abstract-machine/LICENSE ../../../ysyx-software-file/abstract-machine 17 | cp -r am/abstract-machine/README ../../../ysyx-software-file/abstract-machine 18 | cp -r am/abstract-machine/Makefile ../../../ysyx-software-file/abstract-machine 19 | cp -r am/abstract-machine/scripts ../../../ysyx-software-file/abstract-machine 20 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/scripts/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export AM_HOME=$(pwd)/../dependency/am/abstract-machine 4 | export NEMU_HOME=$(pwd)/../dependency/NEMU 5 | export NOOP_HOME=$(pwd)/../dependency 6 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | help() { 4 | echo "Usage:" 5 | echo "install.sh [-g] [-c]" 6 | echo "Description:" 7 | echo "-g: Install gtkwave." 8 | echo "-c: Install mill for Chisel env." 9 | exit 0 10 | } 11 | 12 | while getopts 'hgc' OPT; do 13 | case $OPT in 14 | h) help;; 15 | g) GTKWAVE="true";; 16 | c) CHISEL="true";; 17 | ?) help;; 18 | esac 19 | done 20 | 21 | if !(cat /etc/*release | grep 'Ubuntu 20.04'); then 22 | echo "Your Linux branch does not meet the requirements, please use Ubuntu 20.04." 23 | exit 1 24 | fi 25 | 26 | UPDATED="false" 27 | install_package() { 28 | for package in $* 29 | do 30 | dpkg -s "$package" >/dev/null 2>&1 && { 31 | echo "$package has been installed." 32 | } || { 33 | if [[ $UPDATED == "false" ]]; then 34 | UPDATED="true" 35 | sudo apt-get update 36 | fi 37 | sudo apt-get --yes install $package 38 | } 39 | done 40 | } 41 | 42 | install_verilator() { 43 | ubt20_64_package_list=("git" "perl" "python3" "make" "autoconf" "g++" "flex" "bison" "ccache" 44 | "libgoogle-perftools-dev" "numactl" "perl-doc" "libfl2" "libfl-dev" "zlibc" "zlib1g" "zlib1g-dev") 45 | for package in ${ubt20_64_package_list[@]} ; do 46 | install_package $package 47 | done 48 | 49 | which verilator >/dev/null 2>&1 && { 50 | echo "verilator has been installed." 51 | } || { 52 | mkdir -p dependency 53 | git clone https://github.com/verilator/verilator ./dependency/verilator # run first time 54 | 55 | # every time you need to build: 56 | # unsetenv VERILATOR_ROOT # For csh; ignore error if on bash 57 | unset VERILATOR_ROOT # for bash 58 | cd dependency/verilator 59 | git pull # make sure git repository is up-to-date 60 | # git tag # see what versions exist 61 | #git checkout master # use development branch (e.g. recent bug fixes) 62 | #git checkout stable # use most recent stable release 63 | git checkout v4.210 # switch to specified release version 64 | 65 | autoconf # create ./configure script 66 | ./configure # configure and create Makefile 67 | make -j `nproc` # build Verilator itself (if error, try just 'make') 68 | sudo make install 69 | } 70 | } 71 | 72 | install_mill() { 73 | install_package curl 74 | install_package default-jre 75 | 76 | which mill >/dev/null 2>&1 && { 77 | echo "mill has been installed." 78 | } || { 79 | sudo sh -c "curl -L https://github.com/com-lihaoyi/mill/releases/download/0.9.9/0.9.9 > /usr/local/bin/mill && chmod +x /usr/local/bin/mill" 80 | } 81 | } 82 | 83 | install_verilator 84 | 85 | # install for difftest 86 | install_package libsqlite3-dev 87 | # install for NEMU 88 | install_package libreadline-dev libsdl2-dev bison libncurses5-dev 89 | # install cmake for DRAMsim3 90 | install_package cmake 91 | # isntall riscv toolchain 92 | install_package g++-riscv64-linux-gnu 93 | install_package binutils-riscv64-linux-gnu 94 | 95 | [[ $GTKWAVE == "true" ]] && install_package gtkwave libcanberra-gtk-module 96 | [[ $CHISEL == "true" ]] && install_mill 97 | 98 | echo "############# verilator and mill install finish!!! #############" 99 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/scripts/record.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # to print the color in terminal 4 | INFO="\033[0;33m" 5 | ERROR="\033[0;31m" 6 | RIGHT="\033[0;32m" 7 | END="\033[0m" 8 | 9 | 10 | ROOT_PATH=$(dirname $(readlink -f "$0"))/../dependency 11 | AM_FOLDER_PATH=${ROOT_PATH}"/am" 12 | ABSTRACT_MACHINE_FOLDER_PATH=${AM_FOLDER_PATH}"/abstract-machine" 13 | SIMPLE_TESTS_FOLDER_PATH=${AM_FOLDER_PATH}"/simple-tests" 14 | RISCV_TESTS_FOLDER_PATH=${AM_FOLDER_PATH}"/riscv-tests" 15 | AM_KERNELS_FOLDER_PATH=${AM_FOLDER_PATH}"/am-kernels" 16 | 17 | DIFFTEST_FOLDER_PATH=${ROOT_PATH}"/difftest" 18 | NEMU_FOLDER_PATH=${ROOT_PATH}"/NEMU" 19 | DRAMSIM3_FOLDER_PATH=${ROOT_PATH}"/DRAMsim3" 20 | YSYXSOC_PATH=${ROOT_PATH}"/ysyxSoC" 21 | YSYX_SOFTWARE_FILE_PATH=${ROOT_PATH}"/ysyx-software-file" 22 | 23 | #NOTE: am-kernel, simple-test need to dowload from the 'ysyx-software-file' repo 24 | configYsyxSoftwareFile() { 25 | cd ${ROOT_PATH} 26 | if [[ -d ${YSYX_SOFTWARE_FILE_PATH} ]]; then 27 | echo -e "${RIGHT}ysyx-software-file exist!${END}" 28 | else 29 | echo -e "${INFO}[no download]: git clone...${END}" 30 | git clone -b ysyx3 --depth 1 https://github.com/maksyuki/ysyx-software-file.git 31 | fi 32 | } 33 | 34 | # download the am repo from the github 35 | ###### abstract-machine ###### 36 | configAbstractMachine() { 37 | configYsyxSoftwareFile 38 | 39 | mkdir -p ${AM_FOLDER_PATH} 40 | cd ${AM_FOLDER_PATH} 41 | if [[ -d ${ABSTRACT_MACHINE_FOLDER_PATH} ]]; then 42 | echo -e "${RIGHT}abstract-machine exist!${END}" 43 | # if git fsck --full != 0; then 44 | # echo "[download error]: remove the dir and git clone" 45 | # rm -rf abstract-machine 46 | # git clone https://github.com/NJU-ProjectN/abstract-machine.git 47 | # fi 48 | else 49 | echo -e "${INFO}[no exist] copy...${END}" 50 | cp -rf ${YSYX_SOFTWARE_FILE_PATH}/abstract-machine ./ 51 | # echo -e "${INFO}[no download]: git clone...${END}" 52 | # git clone https://github.com/NJU-ProjectN/abstract-machine.git 53 | fi 54 | 55 | cd ${ABSTRACT_MACHINE_FOLDER_PATH} 56 | # git checkout ysyx2021 57 | 58 | if [[ -z $AM_HOME ]]; then 59 | echo -e "${INFO}AM_HOME is empty, set AM_HOME...${END}" 60 | export AM_HOME=${ABSTRACT_MACHINE_FOLDER_PATH} 61 | 62 | elif [[ $AM_HOME != ${ABSTRACT_MACHINE_FOLDER_PATH} ]]; then 63 | echo -e "${ERROR}AM_HOME is set error, error value: $AM_HOME${END}" 64 | export AM_HOME=${ABSTRACT_MACHINE_FOLDER_PATH} 65 | 66 | else 67 | echo -e "${RIGHT}AM_HOME exist and is a right value${END}" 68 | fi 69 | echo -e "${RIGHT}AM_HOME: $AM_HOME${END}" 70 | 71 | cd ${ROOT_PATH} 72 | } 73 | 74 | ###### simple-tests, riscv-tests ###### 75 | configTestSuites() { 76 | mkdir -p ${AM_FOLDER_PATH} 77 | cd ${AM_FOLDER_PATH} 78 | if [[ -d ${RISCV_TESTS_FOLDER_PATH} ]]; then 79 | echo -e "${RIGHT}riscv-tests exist!${END}" 80 | else 81 | echo -e "${INFO}[no download]: git clone...${END}" 82 | git clone https://github.com/NJU-ProjectN/riscv-tests.git 83 | fi 84 | 85 | cd ${ROOT_PATH} 86 | 87 | configYsyxSoftwareFile 88 | mkdir -p ${AM_FOLDER_PATH} 89 | cd ${AM_FOLDER_PATH} 90 | 91 | if [[ -d ${SIMPLE_TESTS_FOLDER_PATH} ]]; then 92 | echo -e "${RIGHT}simple-tests exist!${END}" 93 | else 94 | echo -e "${INFO}[no exist] copy...${END}" 95 | cp -rf ${YSYX_SOFTWARE_FILE_PATH}/simple-tests ./ 96 | fi 97 | 98 | cd ${ROOT_PATH} 99 | } 100 | 101 | ###### am-kernels ###### 102 | configAMKernels() { 103 | configYsyxSoftwareFile 104 | 105 | mkdir -p ${AM_FOLDER_PATH} 106 | cd ${AM_FOLDER_PATH} 107 | 108 | if [[ -d ${AM_KERNELS_FOLDER_PATH} ]]; then 109 | echo -e "${RIGHT}am-kernels exist!${END}" 110 | else 111 | echo -e "${INFO}[no exist]: copy...${END}" 112 | cp -rf ${YSYX_SOFTWARE_FILE_PATH}/am-kernels ./ 113 | fi 114 | 115 | cd ${ROOT_PATH} 116 | } 117 | 118 | # download the specific commit id difftest and NEMU 119 | # the commit id is same as the https://github.com/OSCPU/oscpu-framework.git 120 | ###### difftest ###### 121 | configDiffTest() { 122 | cd ${ROOT_PATH} 123 | 124 | if [[ -d ${DIFFTEST_FOLDER_PATH} ]]; then 125 | echo -e "${RIGHT}difftest exist!${END}" 126 | else 127 | echo -e "${INFO}[no download]: git clone...${END}" 128 | git clone https://gitee.com/oscpu/difftest.git 129 | fi 130 | 131 | cd ${DIFFTEST_FOLDER_PATH} 132 | git checkout 56d947b 133 | # change the ram size from 8G to 256MB 134 | sed -i 's/^\/\/\s\+\(#define\s\+EMU_RAM_SIZE\s\+(256\)/\1/' src/test/csrc/common/ram.h 135 | sed -i 's/^#define\s\+EMU_RAM_SIZE\s\+(8/\/\/ &/' src/test/csrc/common/ram.h 136 | 137 | cd ${ROOT_PATH} 138 | } 139 | 140 | ###### NEMU ###### 141 | configNemu() { 142 | cd ${ROOT_PATH} 143 | 144 | if [[ -d ${NEMU_FOLDER_PATH} ]]; then 145 | echo -e "${RIGHT}NEMU exist!${END}" 146 | else 147 | echo -e "${INFO}[no download]: git clone...${END}" 148 | git clone https://gitee.com/oscpu/NEMU.git 149 | fi 150 | 151 | cd ${NEMU_FOLDER_PATH} 152 | git checkout e402575 153 | 154 | if [[ -z $NEMU_HOME ]]; then 155 | echo -e "${INFO}NEMU_HOME is empty, set NEMU_HOME...${END}" 156 | export NEMU_HOME=${NEMU_FOLDER_PATH} 157 | export NOOP_HOME=${ROOT_PATH} 158 | 159 | elif [[ $NEMU_HOME != ${NEMU_FOLDER_PATH} ]]; then 160 | echo -e "${ERROR}NEMU_HOME is set error, error value: $NEMU_HOME${END}" 161 | export NEMU_HOME=${NEMU_FOLDER_PATH} 162 | export NOOP_HOME=${ROOT_PATH} 163 | else 164 | echo -e "${RIGHT}NEMU_HOME exist and is a right value${END}" 165 | fi 166 | 167 | echo -e "${RIGHT}NEMU_HOME: $NEMU_HOME${END}" 168 | echo -e "${RIGHT}NOOP_HOME: $NOOP_HOME${END}" 169 | 170 | make defconfig riscv64-xs-ref_defconfig 171 | # change the sim memory from 8G to 256MB 172 | # need to enter 'make menuconfig' and 173 | # modify [Memory Configuration]->[Memory size] to '0x10000000' manually 174 | sed -i 's/^\(CONFIG_MSIZE=0x\)\(.*\)/\110000000/' .config 175 | # NOTE: you need to set the 'NEMU_HOME' and 'NOOP_HOME' in sh config file! 176 | # because the compliation only reads sh env vars 177 | 178 | cd ${ROOT_PATH} 179 | } 180 | 181 | # the commit id is same as the https://github.com/OSCPU/oscpu-framework.git 182 | ###### dramsim3 ###### 183 | configDramSim3() { 184 | cd ${ROOT_PATH} 185 | 186 | if [[ -d ${DRAMSIM3_FOLDER_PATH} ]]; then 187 | echo -e "${RIGHT}dramsim3 exist!${END}" 188 | else 189 | echo -e "${INFO}[no download]: git clone...${END}" 190 | git clone https://github.com/OpenXiangShan/DRAMsim3.git 191 | fi 192 | 193 | cd ${DRAMSIM3_FOLDER_PATH} 194 | git checkout 5723f6b1cc157ac2d7b4154b50fd1799c9cf54aa 195 | 196 | cd ${ROOT_PATH} 197 | } 198 | 199 | ###### YsyxSoC ###### 200 | configYsyxSoC() { 201 | cd ${ROOT_PATH} 202 | 203 | if [[ -d ${YSYXSOC_PATH} ]]; then 204 | echo -e "${RIGHT}ysyxSoC exist!${END}" 205 | else 206 | echo -e "${INFO}[no download]: git clone...${END}" 207 | git clone --depth 1 https://github.com/OSCPU/ysyxSoC.git 208 | fi 209 | 210 | cd ${ROOT_PATH} 211 | } 212 | 213 | helpInfo() { 214 | echo -e "${INFO}Usage: setup.sh [-a][-n][-d][-i][-m][-r][-k][-y][-s repo][-h]${END}" 215 | echo -e "Description - set up the build env of the treecore riscv processor" 216 | echo -e "" 217 | echo -e "${RIGHT} -a: download and config all the repos${END}" 218 | echo -e "${RIGHT} -n: download and config nemu${END}" 219 | echo -e "${RIGHT} -d: download and config difftest${END}" 220 | echo -e "${RIGHT} -i: download and config dramsim3${END}" 221 | echo -e "${RIGHT} -m: download and config abstract-machine${END}" 222 | echo -e "${RIGHT} -r: download and config simple-tests, riscv-tests${END}" 223 | echo -e "${RIGHT} -k: download and config am-kernels${END}" 224 | echo -e "${RIGHT} -y: download and config ysyx-soc${END}" 225 | echo -e "${RIGHT} -s: download and config specific repo${END}" 226 | echo -e "sample: ./setup.sh -s [repo](default: nemu) ${INFO}[repo]: [nemu, diffttest, dramsim3, am, testsuites, am-kernels, ysyx-soc]${END}" 227 | echo -e "${RIGHT} -h: help information${END}" 228 | 229 | } 230 | 231 | configSpecRepo() { 232 | if [[ -n $1 && $1 == "all" ]]; then 233 | configAbstractMachine 234 | configTestSuites 235 | configAMKernels 236 | configDiffTest 237 | configNemu 238 | configDramSim3 239 | configYsyxSoC 240 | elif [[ -n $1 && $1 == "nemu" ]]; then 241 | configNemu 242 | elif [[ -n $1 && $1 == "difftest" ]]; then 243 | configDiffTest 244 | elif [[ -n $1 && $1 == "dramsim3" ]]; then 245 | configDramSim3 246 | elif [[ -n $1 && $1 == "am" ]]; then 247 | configAbstractMachine 248 | elif [[ -n $1 && $1 == "testsuites" ]]; then 249 | configTestSuites 250 | elif [[ -n $1 && $1 == "am-kernels" ]]; then 251 | configAMKernels 252 | elif [[ -n $1 && $1 == "ysyx-soc" ]]; then 253 | configYsyxSoC 254 | else 255 | echo -e "${ERROR}the params [$1] is not found.${END} opt value: [nemu, diffttest, dramsim3, am, testsuites, am-kernels, ysyx-soc]" 256 | fi 257 | } 258 | 259 | mkdir -p ${ROOT_PATH} 260 | # Check parameters 261 | while getopts 'andimrkys:h' OPT; do 262 | case $OPT in 263 | a) configSpecRepo "all";; 264 | n) configNemu;; 265 | d) configDiffTest;; 266 | i) configDramSim3;; 267 | m) configAbstractMachine;; 268 | r) configTestSuites;; 269 | k) configAMKernels;; 270 | y) configYsyxSoC;; 271 | s) configSpecRepo $OPTARG;; 272 | h) helpInfo;; 273 | ?) 274 | echo -e "${ERROR}invalid parameters!!!${END}" 275 | helpInfo 276 | ;; 277 | esac 278 | done 279 | 280 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/scripts/template.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # to print the color in terminal 4 | INFO="\033[0;33m" 5 | ERROR="\033[0;31m" 6 | RIGHT="\033[0;32m" 7 | END="\033[0m" 8 | 9 | # if not have content, create, otherwise check 10 | configContent() { 11 | cd $1 12 | # pwd 13 | echo -e "${INFO}check Makefile...${END}" 14 | if [[ -f "Makefile" ]]; then 15 | echo -e "${RIGHT}Makefile exist!${END}" 16 | else 17 | echo -e "${INFO}no exist${END}" 18 | echo "start config Makefile..." 19 | echo "sim-verilog:" > Makefile 20 | echo -e "${RIGHT}config[SUCCESSFUL]${END}" 21 | fi 22 | 23 | echo -e "${INFO}check source dir...${END}" 24 | if [[ -d "src" ]]; then 25 | echo -e "${RIGHT}src exist!${END}" 26 | else 27 | echo -e "${INFO}no exist${END}" 28 | echo "start generate dir..." 29 | mkdir -p src/main/csrc 30 | mkdir -p src/main/scala/axi4 31 | mkdir -p src/main/scala/common 32 | mkdir -p src/main/scala/core 33 | mkdir -p src/main/scala/port 34 | mkdir -p src/main/scala/top 35 | mkdir -p src/main/scala/utils 36 | echo -e "${RIGHT}generate src dir[SUCCESSFUL]${END}" 37 | fi 38 | 39 | echo -e "${INFO}check difftest file...${END}" 40 | if [[ -f "src/main/scala/utils/Difftest.scala" ]]; then 41 | echo -e "${RIGHT}Difftest.scala exist!${END}" 42 | else 43 | echo -e "${INFO}no exist${END}" 44 | echo "start generate Difftest.scala..." 45 | cp ../dependency/difftest/src/main/scala/Difftest.scala src/main/scala/utils/Difftest.scala 46 | echo -e "${RIGHT}generate Difftest.scala[SUCCESSFUL]${END}" 47 | fi 48 | 49 | echo -e "${INFO}check module prefix file...${END}" 50 | if [[ -f "src/main/scala/utils/AddModulePrefix.scala" ]]; then 51 | echo -e "${RIGHT}AddModulePrefix.scala exist!${END}" 52 | else 53 | echo -e "${INFO}no exist${END}" 54 | echo "start generate AddModulePrefix.scala..." 55 | cp ../tc_l2/src/main/scala/utils/AddModulePrefix.scala src/main/scala/utils/AddModulePrefix.scala 56 | echo -e "${RIGHT}generate AddModulePrefix.scala[SUCCESSFUL]${END}" 57 | fi 58 | } 59 | 60 | configTemplate() { 61 | if [[ -d $1 ]]; then 62 | echo -e "${RIGHT}$1 exist!${END}" 63 | else 64 | mkdir $1 65 | echo -e "${INFO}[no exist]: config project...${END}" 66 | fi 67 | 68 | configContent $1 69 | } 70 | 71 | configTarget() { 72 | # HACK: need to make one check statement 73 | # now dont receive 'tc_l2' as parameter 74 | if [[ -n $1 && $1 == "tc_l3" ]]; then 75 | configTemplate $1 76 | elif [[ -n $1 && $1 == "tc_l4" ]]; then 77 | configTemplate $1 78 | else 79 | configTemplate "tc_l1" # include other error parameters condition 80 | fi 81 | } 82 | 83 | helpInfo() { 84 | echo -e "${INFO}Usage: setup.sh [-t target][-h]${END}" 85 | echo -e "Description - set up the template dir env of the treecore riscv processor" 86 | echo -e "" 87 | echo -e "${RIGHT} -t: config specific target directory structure${END}" 88 | echo -e "sample: ./setup.sh -t [target](default: tc_l1) ${INFO}[target]: [tc_l1, tc_l2, tc_l3, ...]${END}" 89 | echo -e "${RIGHT} -h: help information${END}" 90 | } 91 | 92 | while getopts 't:h' OPT; do 93 | case $OPT in 94 | t) configTarget $OPTARG;; 95 | h) helpInfo;; 96 | ?) 97 | echo -e "${ERROR}invalid parameters!!!${END}" 98 | helpInfo 99 | ;; 100 | esac 101 | done -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/Makefile: -------------------------------------------------------------------------------- 1 | sim-verilog: 2 | @echo "this is sim-verilog target called by the difftest Makefile" 3 | @echo "do nothing, because now the SimTop.v is not generated by this Makefile" -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/csrc/emu.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef DUMP_WAVE_VCD 5 | #include 6 | #elif DUMP_WAVE_FST 7 | #include 8 | #endif 9 | #include 10 | #include 11 | 12 | extern "C" 13 | { 14 | void flash_init(const char *img); 15 | } 16 | 17 | class Emulator 18 | { 19 | public: 20 | Emulator(int argc, char *argv[]) 21 | { 22 | parseArgs(argc, argv); 23 | 24 | if (args.image == nullptr) 25 | { 26 | printf("Image file unspecified. Use -i to provide the image of flash"); 27 | exit(1); 28 | } 29 | printf("Initializing flash with \"%s\" ...\n", args.image); 30 | flash_init(args.image); 31 | 32 | printf("Initializing and resetting DUT ...\n"); 33 | dutPtr = new VysyxSoCFull; 34 | dutPtr->reset = 1; 35 | for (int i = 0; i < 10; i++) 36 | { 37 | dutPtr->clock = 0; 38 | dutPtr->eval(); 39 | dutPtr->clock = 1; 40 | dutPtr->eval(); 41 | } 42 | dutPtr->clock = 0; 43 | dutPtr->reset = 0; 44 | dutPtr->eval(); 45 | 46 | if (args.dumpWave) 47 | { 48 | #ifdef DUMP_WAVE_VCD 49 | wavePtr = new VerilatedVcdC; 50 | #elif DUMP_WAVE_FST 51 | wavePtr = new VerilatedFstC; 52 | #endif 53 | Verilated::traceEverOn(true); 54 | printf("`dump-wave` enabled, waves will be written to \"soc.wave\".\n"); 55 | dutPtr->trace(wavePtr, 1); 56 | wavePtr->open("soc.wave"); 57 | wavePtr->dump(0); 58 | } 59 | } 60 | ~Emulator() 61 | { 62 | if (args.dumpWave) 63 | { 64 | wavePtr->close(); 65 | delete wavePtr; 66 | } 67 | } 68 | 69 | void step() 70 | { 71 | dutPtr->clock = 1; 72 | dutPtr->eval(); 73 | cycle++; 74 | if (args.dumpWave && args.dumpBegin <= cycle && cycle <= args.dumpEnd) 75 | { 76 | wavePtr->dump((vluint64_t)cycle); 77 | } 78 | dutPtr->clock = 0; 79 | dutPtr->eval(); 80 | } 81 | 82 | unsigned long long get_cycle() 83 | { 84 | return cycle; 85 | } 86 | 87 | private: 88 | void parseArgs(int argc, char *argv[]) 89 | { 90 | int long_index; 91 | const struct option long_options[] = { 92 | {"dump-wave", 0, NULL, 0}, 93 | {"log-begin", 1, NULL, 'b'}, 94 | {"log-end", 1, NULL, 'e'}, 95 | {"image", 1, NULL, 'i'}, 96 | {"help", 0, NULL, 'h'}, 97 | {0, 0, NULL, 0}}; 98 | 99 | int o; 100 | while ((o = getopt_long(argc, const_cast(argv), 101 | "-hi:b:e:", long_options, &long_index)) != -1) 102 | { 103 | switch (o) 104 | { 105 | case 0: 106 | switch (long_index) 107 | { 108 | case 0: 109 | args.dumpWave = true; 110 | continue; 111 | } 112 | // fall through 113 | default: 114 | print_help(argv[0]); 115 | exit(0); 116 | case 'i': 117 | args.image = optarg; 118 | break; 119 | case 'b': 120 | args.dumpBegin = atoll(optarg); 121 | break; 122 | case 'e': 123 | args.dumpEnd = atoll(optarg); 124 | break; 125 | } 126 | } 127 | 128 | Verilated::commandArgs(argc, argv); 129 | } 130 | 131 | static inline void print_help(const char *file) 132 | { 133 | printf("Usage: %s [OPTION...]\n", file); 134 | printf("\n"); 135 | printf(" -i, --image=FILE run with this image file\n"); 136 | printf(" --dump-wave dump vcd(fst) format waveform when log is enabled.\n"); 137 | printf(" recommand use fst format, becuase fst format wave\n"); 138 | printf(" file is much smaller than vcd format. You need to\n"); 139 | printf(" change compiler option in Makefile to switch format.\n"); 140 | printf(" -b, --log-begin=NUM display log from NUM th cycle\n"); 141 | printf(" -e, --log-end=NUM stop display log at NUM th cycle\n"); 142 | printf(" -h, --help print program help info\n"); 143 | printf("\n"); 144 | } 145 | 146 | unsigned long long cycle = 0; 147 | 148 | struct Args 149 | { 150 | bool dumpWave = false; 151 | unsigned long dumpBegin = 0; 152 | unsigned long dumpEnd = -1; 153 | const char *image = nullptr; 154 | } args; 155 | 156 | VysyxSoCFull *dutPtr = nullptr; 157 | 158 | #ifdef DUMP_WAVE_VCD 159 | VerilatedVcdC *wavePtr = nullptr; 160 | #elif DUMP_WAVE_FST 161 | VerilatedFstC *wavePtr = nullptr; 162 | #endif 163 | 164 | }; 165 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/csrc/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | namespace chrono = std::chrono; 5 | 6 | #include "verilated.h" //Defines common routines 7 | #include "VysyxSoCFull.h" 8 | 9 | #include 10 | 11 | static int signal_received = 0; 12 | 13 | void sig_handler(int signo) 14 | { 15 | if (signal_received != 0) 16 | { 17 | puts("SIGINT received, forcely shutting down.\n"); 18 | exit(0); 19 | } 20 | puts("SIGINT received, gracefully shutting down... Type Ctrl+C again to stop forcely.\n"); 21 | signal_received = signo; 22 | } 23 | 24 | static Emulator *emu = nullptr; 25 | chrono::system_clock::time_point sim_start_time; 26 | void release() 27 | { 28 | if (emu != nullptr) 29 | { 30 | auto elapsed = chrono::duration_cast(chrono::system_clock::now() - sim_start_time); 31 | printf("Simulated %llu cycles in %lds\n", 32 | emu->get_cycle(), 33 | elapsed.count()); 34 | delete emu; 35 | } 36 | } 37 | 38 | int main(int argc, char *argv[]) 39 | { 40 | printf("Emu compiled at %s, %s\n", __DATE__, __TIME__); 41 | 42 | if (signal(SIGINT, sig_handler) == SIG_ERR) 43 | { 44 | printf("can't catch SIGINT\n"); 45 | } 46 | atexit(release); 47 | 48 | emu = new Emulator(argc, argv); 49 | printf("Start simulating ...\n"); 50 | sim_start_time = chrono::system_clock::now(); 51 | while (!Verilated::gotFinish() && signal_received == 0) 52 | { 53 | emu->step(); 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/axi4/AXI4Bridge.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class AXI4Bridge extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val socEn = Input(Bool()) 9 | val runEn = Output(Bool()) 10 | val dxchg = Flipped(new DXCHGIO) 11 | val axi = if (SoCEna) new SOCAXI4IO else new AXI4IO 12 | }) 13 | 14 | protected val arbiter = Module(new Arbiter) 15 | arbiter.io.runEn <> io.runEn 16 | arbiter.io.dxchg <> io.dxchg 17 | arbiter.io.axirdata := io.axi.r.bits.data 18 | arbiter.io.awHdShk := io.axi.aw.fire 19 | arbiter.io.wHdShk := io.axi.w.fire 20 | arbiter.io.bHdShk := io.axi.b.fire 21 | arbiter.io.arHdShk := io.axi.ar.fire 22 | arbiter.io.rHdShk := io.axi.r.fire 23 | 24 | protected val wMask = arbiter.io.dxchg.wmask 25 | protected val socARSize = arbiter.io.dxchg.rsize 26 | protected val socAWSize = MuxLookup( 27 | PopCount(wMask), 28 | 0.U, 29 | Array( 30 | 8.U -> 3.U, 31 | 4.U -> 2.U, 32 | 2.U -> 1.U, 33 | 1.U -> 0.U 34 | ) 35 | ) 36 | 37 | protected val arSize = Mux(io.socEn, socARSize, DiffRWSize) 38 | protected val awSize = Mux(io.socEn, socAWSize, DiffRWSize) 39 | protected val addrMask = Mux(io.socEn, SoCAddrMask, DifftestAddrMask) // difftest mask(align) important!!! 40 | 41 | when(arbiter.io.state === Arbiter.eumAR) { 42 | io.axi.ar.valid := true.B 43 | io.axi.ar.bits.size := arSize 44 | io.axi.ar.bits.addr := arbiter.io.dxchg.raddr & addrMask 45 | io.axi.r.ready := false.B 46 | io.axi.aw.valid := false.B 47 | io.axi.aw.bits.size := 0.U 48 | io.axi.aw.bits.addr := 0.U 49 | io.axi.w.valid := false.B 50 | io.axi.w.bits.strb := 0.U 51 | io.axi.w.bits.data := 0.U 52 | io.axi.b.ready := false.B 53 | 54 | }.elsewhen(arbiter.io.state === Arbiter.eumR) { 55 | io.axi.ar.valid := false.B 56 | io.axi.ar.bits.size := arSize 57 | io.axi.ar.bits.addr := arbiter.io.dxchg.raddr & addrMask 58 | io.axi.r.ready := true.B 59 | io.axi.aw.valid := false.B 60 | io.axi.aw.bits.size := 0.U 61 | io.axi.aw.bits.addr := 0.U 62 | io.axi.w.valid := false.B 63 | io.axi.w.bits.strb := 0.U 64 | io.axi.w.bits.data := 0.U 65 | io.axi.b.ready := false.B 66 | 67 | }.elsewhen(arbiter.io.state === Arbiter.eumAW) { 68 | io.axi.ar.valid := false.B 69 | io.axi.ar.bits.size := 0.U 70 | io.axi.ar.bits.addr := 0.U 71 | io.axi.r.ready := false.B 72 | io.axi.aw.valid := true.B 73 | io.axi.aw.bits.size := awSize 74 | io.axi.aw.bits.addr := arbiter.io.dxchg.waddr & addrMask 75 | io.axi.w.valid := false.B 76 | io.axi.w.bits.strb := 0.U 77 | io.axi.w.bits.data := 0.U 78 | io.axi.b.ready := false.B 79 | 80 | }.elsewhen(arbiter.io.state === Arbiter.eumW) { 81 | io.axi.ar.valid := false.B 82 | io.axi.ar.bits.size := 0.U 83 | io.axi.ar.bits.addr := 0.U 84 | io.axi.r.ready := false.B 85 | io.axi.aw.valid := false.B 86 | io.axi.aw.bits.size := awSize 87 | io.axi.aw.bits.addr := arbiter.io.dxchg.waddr & addrMask 88 | io.axi.w.valid := true.B 89 | io.axi.w.bits.strb := wMask 90 | io.axi.w.bits.data := arbiter.io.dxchg.wdata 91 | io.axi.b.ready := false.B 92 | 93 | }.elsewhen(arbiter.io.state === Arbiter.eumB) { 94 | io.axi.ar.valid := false.B 95 | io.axi.ar.bits.size := 0.U 96 | io.axi.ar.bits.addr := 0.U 97 | io.axi.r.ready := false.B 98 | io.axi.aw.valid := false.B 99 | io.axi.aw.bits.size := 0.U 100 | io.axi.aw.bits.addr := 0.U 101 | io.axi.w.valid := false.B 102 | io.axi.w.bits.strb := 0.U 103 | io.axi.w.bits.data := 0.U 104 | io.axi.b.ready := true.B 105 | 106 | }.otherwise { 107 | io.axi.ar.valid := false.B 108 | io.axi.ar.bits.size := 0.U 109 | io.axi.ar.bits.addr := 0.U 110 | io.axi.r.ready := false.B 111 | io.axi.aw.valid := false.B 112 | io.axi.aw.bits.size := 0.U 113 | io.axi.aw.bits.addr := 0.U 114 | io.axi.w.valid := false.B 115 | io.axi.w.bits.strb := 0.U 116 | io.axi.w.bits.data := 0.U 117 | io.axi.b.ready := false.B 118 | 119 | } 120 | 121 | if (!SoCEna) { 122 | val sim = io.axi.asInstanceOf[AXI4IO] 123 | sim.ar.bits.prot := 0.U 124 | sim.ar.bits.id := 0.U 125 | sim.ar.bits.len := 0.U 126 | sim.ar.bits.burst := 1.U 127 | sim.ar.bits.lock := 0.U 128 | sim.ar.bits.cache := 0.U 129 | sim.ar.bits.qos := 0.U 130 | sim.ar.bits.user := DontCare 131 | sim.aw.bits.prot := 0.U 132 | sim.aw.bits.id := 0.U 133 | sim.aw.bits.len := 0.U 134 | sim.aw.bits.burst := 1.U 135 | sim.aw.bits.lock := false.B 136 | sim.aw.bits.cache := 0.U 137 | sim.aw.bits.qos := 0.U 138 | sim.aw.bits.user := DontCare 139 | sim.w.bits.last := 1.U 140 | 141 | } else { 142 | io.axi.ar.bits.id := 0.U 143 | io.axi.ar.bits.len := 0.U 144 | io.axi.ar.bits.burst := 1.U 145 | io.axi.aw.bits.id := 0.U 146 | io.axi.aw.bits.len := 0.U 147 | io.axi.aw.bits.burst := 1.U 148 | io.axi.w.bits.last := 1.U 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/axi4/Arbiter.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | object Arbiter { 7 | // FSM var for read/write 8 | val eumIDLE :: eumStandby :: eumIDLE2 :: eumAW :: eumW :: eumB :: eumAR :: eumR :: Nil = Enum(8) 9 | } 10 | 11 | class Arbiter extends Module with InstConfig { 12 | val io = IO(new Bundle { 13 | val awHdShk = Input(Bool()) 14 | val wHdShk = Input(Bool()) 15 | val bHdShk = Input(Bool()) 16 | val arHdShk = Input(Bool()) 17 | val rHdShk = Input(Bool()) 18 | val axirdata = Input(UInt(XLen.W)) 19 | val dxchg = Flipped(new DXCHGIO) 20 | val state = Output(UInt(3.W)) 21 | val runEn = Output(Bool()) 22 | }) 23 | 24 | // arbitrate mem and inst req 25 | protected val runEn = RegInit(false.B) 26 | io.runEn := Mux(reset.asBool(), false.B, runEn) 27 | 28 | protected val valid = RegInit(false.B) 29 | protected val ren = RegInit(false.B) 30 | protected val raddr = RegInit(0.U(XLen.W)) 31 | protected val rdata = RegInit(0.U(XLen.W)) 32 | protected val rsize = RegInit(0.U(LDSize.W)) 33 | protected val wen = RegInit(false.B) 34 | protected val waddr = RegInit(0.U(XLen.W)) 35 | protected val wdata = RegInit(0.U(XLen.W)) 36 | protected val wmask = RegInit(0.U(MaskLen.W)) 37 | protected val stateReg = RegInit(Arbiter.eumIDLE) 38 | io.state := stateReg 39 | io.dxchg.rdata := rdata 40 | 41 | switch(stateReg) { 42 | is(Arbiter.eumIDLE) { 43 | valid := false.B 44 | ren := io.dxchg.ren 45 | raddr := io.dxchg.raddr 46 | rdata := io.dxchg.rdata 47 | rsize := io.dxchg.rsize 48 | wen := io.dxchg.wen 49 | waddr := io.dxchg.waddr 50 | wdata := io.dxchg.wdata 51 | wmask := io.dxchg.wmask 52 | stateReg := Arbiter.eumStandby 53 | } 54 | is(Arbiter.eumStandby) { 55 | when(valid) { 56 | runEn := true.B 57 | stateReg := Arbiter.eumIDLE2 58 | 59 | }.elsewhen(wen) { 60 | stateReg := Arbiter.eumAW 61 | 62 | }.elsewhen(ren) { 63 | stateReg := Arbiter.eumAR 64 | 65 | }.otherwise { 66 | valid := true.B 67 | stateReg := Arbiter.eumStandby 68 | } 69 | } 70 | is(Arbiter.eumIDLE2) { 71 | runEn := false.B 72 | stateReg := Arbiter.eumIDLE 73 | } 74 | is(Arbiter.eumAR) { 75 | when(io.arHdShk) { 76 | stateReg := Arbiter.eumR 77 | } 78 | } 79 | is(Arbiter.eumR) { 80 | when(io.rHdShk) { 81 | valid := true.B 82 | stateReg := Arbiter.eumStandby 83 | rdata := io.axirdata 84 | } 85 | } 86 | is(Arbiter.eumAW) { 87 | when(io.awHdShk) { 88 | stateReg := Arbiter.eumW 89 | } 90 | } 91 | is(Arbiter.eumW) { 92 | when(io.wHdShk) { 93 | stateReg := Arbiter.eumB 94 | } 95 | } 96 | is(Arbiter.eumB) { 97 | when(io.bHdShk) { 98 | valid := true.B 99 | stateReg := Arbiter.eumStandby 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/axi4/Crossbar.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class Crossbar extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val socEn = Input(Bool()) 9 | val runEn = Input(Bool()) 10 | val dxchg = new DXCHGIO 11 | val core = new COREIO 12 | }) 13 | 14 | protected val globalEn = RegInit(false.B) 15 | protected val inst = RegInit(0.U(InstLen.W)) 16 | protected val rdInst = Mux(io.core.fetch.addr(2).asBool(), io.dxchg.rdata(63, 32), io.dxchg.rdata(31, 0)) 17 | 18 | io.core.globalEn := Mux(io.runEn, globalEn, false.B) 19 | io.core.fetch.data := inst 20 | io.core.ld.data := io.dxchg.rdata 21 | 22 | // FSM for inst or mem data xform 23 | protected val eumInst :: eumMem :: Nil = Enum(2) 24 | protected val stateReg = RegInit(eumInst) 25 | 26 | switch(stateReg) { 27 | is(eumInst) { 28 | when(io.runEn) { 29 | globalEn := true.B 30 | stateReg := eumMem 31 | inst := rdInst 32 | } 33 | } 34 | is(eumMem) { 35 | when(io.runEn) { 36 | globalEn := false.B 37 | stateReg := eumInst 38 | inst := NOPInst 39 | } 40 | } 41 | } 42 | 43 | // because the difftest's logic addr is 0x000000 44 | protected val instSize = Mux(io.socEn, InstSoCRSize, InstDiffRSize) 45 | protected val baseAddr = Mux(io.socEn, SoCStartBaseAddr, DiffStartBaseAddr) 46 | protected val instAddr = io.core.fetch.addr - baseAddr 47 | protected val ldAddr = io.core.ld.addr - baseAddr 48 | protected val sdAddr = io.core.sd.addr - baseAddr 49 | protected val maEn = io.core.ld.en || io.core.sd.en 50 | 51 | // prepare the data exchange io signals 52 | io.dxchg.ren := ((stateReg === eumInst) || (stateReg === eumMem && maEn)) 53 | io.dxchg.raddr := Mux(stateReg === eumInst, instAddr, ldAddr) 54 | io.dxchg.rsize := Mux(stateReg === eumMem && io.core.ld.en, io.core.ld.size, instSize) 55 | io.dxchg.wen := stateReg === eumMem && io.core.sd.en 56 | io.dxchg.waddr := sdAddr 57 | io.dxchg.wdata := io.core.sd.data 58 | io.dxchg.wmask := io.core.sd.mask 59 | } 60 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/common/AXI4Config.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | trait AXI4Config extends IOConfig { 7 | val AxiProtLen = 3 8 | val AxiIdLen = 4 9 | val AxiUserLen = 1 10 | val AxiSizeLen = 3 // NOTE: or 2? 11 | val AxiLen = 8 12 | val AxiStrb = 8 13 | val AxiBurstLen = 2 14 | val AxiCacheLen = 4 15 | val AxiQosLen = 4 16 | val AxiRegionLen = 4 17 | val AxiRespLen = 2 18 | } 19 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/common/Helper.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | object LookupTree { 7 | def apply[T <: Data](key: UInt, mapping: Iterable[(UInt, T)]): T = 8 | Mux1H(mapping.map(p => (p._1 === key, p._2))) 9 | } 10 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/common/InstConfig.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | trait IOConfig { 7 | val XLen = 64 8 | val InstLen = 32 9 | val RegfileLen = 5 10 | val RegfileNum = 1 << RegfileLen 11 | val ISALen = 6 12 | // mem 13 | val MaskLen = 8 14 | val LDSize = 3 15 | // branch prediction 16 | val GHRLen = 5 17 | val PHTSize = 1 << GHRLen 18 | val BTBIdxLen = 5 19 | val BTBPcLen = XLen - BTBIdxLen 20 | val BTBTgtLen = XLen 21 | val BTBSize = 1 << BTBIdxLen 22 | } 23 | 24 | trait InstConfig extends IOConfig { 25 | val SoCEna = false 26 | val CacheEna = false 27 | 28 | val FlashStartAddr = "h0000000030000000".U(XLen.W) 29 | val SimStartAddr = "h0000000080000000".U(XLen.W) 30 | val DiffStartBaseAddr = "h0000000080000000".U(XLen.W) 31 | val SoCStartBaseAddr = "h0000000000000000".U(XLen.W) 32 | val DifftestAddrMask = "hfffffffffffffff8".U(XLen.W) 33 | val SoCAddrMask = "hffffffffffffffff".U(XLen.W) 34 | val InstSoCRSize = 2.U 35 | val InstDiffRSize = 3.U 36 | val DiffRWSize = 3.U 37 | 38 | val NOPInst = 0x13.U 39 | // inst type 40 | // nop is equal to [addi x0, x0, 0], so the oper is same as 'addi' inst 41 | val InstTypeLen = 3 42 | val nopInstType = 2.U(InstTypeLen.W) 43 | val rInstType = 1.U(InstTypeLen.W) 44 | val iInstType = 2.U(InstTypeLen.W) 45 | val sInstType = 3.U(InstTypeLen.W) 46 | val bInstType = 4.U(InstTypeLen.W) 47 | val uInstType = 5.U(InstTypeLen.W) 48 | val jInstType = 6.U(InstTypeLen.W) 49 | val wtRegTrue = true.B 50 | val wtRegFalse = false.B 51 | // inst 52 | val InstValLen = 6 53 | val instADDI = 0.U(InstValLen.W) 54 | val instADDIW = 1.U(InstValLen.W) 55 | val instSLTI = 2.U(InstValLen.W) 56 | val instSLTIU = 3.U(InstValLen.W) 57 | val instANDI = 4.U(InstValLen.W) 58 | val instORI = 5.U(InstValLen.W) 59 | val instXORI = 6.U(InstValLen.W) 60 | val instSLLI = 7.U(InstValLen.W) 61 | val instSLLIW = 8.U(InstValLen.W) 62 | val instSRLI = 9.U(InstValLen.W) 63 | val instSRLIW = 10.U(InstValLen.W) 64 | val instSRAI = 11.U(InstValLen.W) 65 | val instSRAIW = 12.U(InstValLen.W) 66 | val instLUI = 13.U(InstValLen.W) 67 | val instAUIPC = 14.U(InstValLen.W) 68 | val instADD = 15.U(InstValLen.W) 69 | val instADDW = 16.U(InstValLen.W) 70 | val instSLT = 17.U(InstValLen.W) 71 | val instSLTU = 18.U(InstValLen.W) 72 | val instAND = 19.U(InstValLen.W) 73 | val instOR = 20.U(InstValLen.W) 74 | val instXOR = 21.U(InstValLen.W) 75 | val instSLL = 22.U(InstValLen.W) 76 | val instSLLW = 23.U(InstValLen.W) 77 | val instSRL = 24.U(InstValLen.W) 78 | val instSRLW = 25.U(InstValLen.W) 79 | val instSUB = 26.U(InstValLen.W) 80 | val instSUBW = 27.U(InstValLen.W) 81 | val instSRA = 28.U(InstValLen.W) 82 | val instSRAW = 29.U(InstValLen.W) 83 | val instNOP = 30.U(InstValLen.W) 84 | val instJAL = 31.U(InstValLen.W) 85 | val instJALR = 32.U(InstValLen.W) 86 | val instBEQ = 33.U(InstValLen.W) 87 | val instBNE = 34.U(InstValLen.W) 88 | val instBLT = 35.U(InstValLen.W) 89 | val instBLTU = 36.U(InstValLen.W) 90 | val instBGE = 37.U(InstValLen.W) 91 | val instBGEU = 38.U(InstValLen.W) 92 | val instLB = 39.U(InstValLen.W) 93 | val instLBU = 40.U(InstValLen.W) 94 | val instLH = 41.U(InstValLen.W) 95 | val instLHU = 42.U(InstValLen.W) 96 | val instLW = 43.U(InstValLen.W) 97 | val instLWU = 44.U(InstValLen.W) 98 | val instLD = 45.U(InstValLen.W) 99 | val instSB = 46.U(InstValLen.W) 100 | val instSH = 47.U(InstValLen.W) 101 | val instSW = 48.U(InstValLen.W) 102 | val instSD = 49.U(InstValLen.W) 103 | val instCSRRW = 50.U(InstValLen.W) 104 | val instCSRRS = 51.U(InstValLen.W) 105 | val instCSRRC = 52.U(InstValLen.W) 106 | val instCSRRWI = 53.U(InstValLen.W) 107 | val instCSRRSI = 54.U(InstValLen.W) 108 | val instCSRRCI = 55.U(InstValLen.W) 109 | val instECALL = 56.U(InstValLen.W) 110 | val instMRET = 57.U(InstValLen.W) 111 | val instFENCE = 58.U(InstValLen.W) 112 | val instFENCE_I = 59.U(InstValLen.W) 113 | val instCUST = 60.U(InstValLen.W) 114 | 115 | // cache 116 | val NWay = 4 117 | val NBank = 4 118 | val NSet = 32 119 | val CacheLineSize = XLen * NBank 120 | val ICacheSize = NWay * NSet * CacheLineSize 121 | val DCacheSize = NWay * NSet * CacheLineSize 122 | 123 | // clint 124 | val ClintBaseAddr = 0x02000000.U(XLen.W) 125 | val ClintBoundAddr = 0x0200bfff.U(XLen.W) 126 | val MSipOffset = 0x0.U(XLen.W) 127 | val MTimeOffset = 0xbff8.U(XLen.W) 128 | val MTimeCmpOffset = 0x4000.U(XLen.W) 129 | // csr addr 130 | val CSRAddrLen = 12 131 | val mhartidAddr = 0xf14.U(CSRAddrLen.W) 132 | val mstatusAddr = 0x300.U(CSRAddrLen.W) 133 | val mieAddr = 0x304.U(CSRAddrLen.W) 134 | val mtvecAddr = 0x305.U(CSRAddrLen.W) 135 | val mscratchAddr = 0x340.U(CSRAddrLen.W) 136 | val mepcAddr = 0x341.U(CSRAddrLen.W) 137 | val mcauseAddr = 0x342.U(CSRAddrLen.W) 138 | val mipAddr = 0x344.U(CSRAddrLen.W) 139 | val mcycleAddr = 0xb00.U(CSRAddrLen.W) 140 | val medelegAddr = 0x302.U(CSRAddrLen.W) 141 | val timeCause = "h8000_0000_0000_0007".U(XLen.W) 142 | val ecallCause = "h0000_0000_0000_000b".U(XLen.W) 143 | 144 | // special inst 145 | val customInst = "h0000007b".U(InstLen.W) 146 | val haltInst = "h0000006b".U(InstLen.W) 147 | } 148 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/common/NumExten.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | // be careful to call this func, need to set the right msb val!!! 7 | // to minify the wire unused pin and bits in verilator 8 | object SignExt { 9 | def apply(a: UInt, len: Int) = { 10 | val aLen = a.getWidth 11 | val signBit = a(aLen - 1) 12 | if (aLen >= len) a(len - 1, 0) else Cat(Fill(len - aLen, signBit), a) 13 | } 14 | } 15 | 16 | object ZeroExt { 17 | def apply(a: UInt, len: Int) = { 18 | val aLen = a.getWidth 19 | if (aLen >= len) a(len - 1, 0) else Cat(0.U((len - aLen).W), a) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/common/Timer.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | // generate low speed clock 7 | class Timer(div: Int = 5) extends Module { 8 | val io = IO(new Bundle { 9 | val tick = Output(Bool()) 10 | }) 11 | 12 | require(div > 0) 13 | require(div < 15) 14 | protected val clockCnt = RegInit(1.U(4.W)) 15 | protected val tickTrigger = clockCnt === div.U 16 | 17 | when(tickTrigger) { 18 | clockCnt := 1.U 19 | }.otherwise { 20 | clockCnt := clockCnt + 1.U 21 | } 22 | 23 | io.tick := tickTrigger 24 | } 25 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/Processor.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | import difftest._ 7 | 8 | class Processor extends Module { 9 | val io = IO(new Bundle { 10 | val runEn = Input(Bool()) 11 | val socEn = Input(Bool()) 12 | val dxchg = new DXCHGIO 13 | }) 14 | 15 | protected val cpu = Module(new TreeCoreL2) 16 | protected val crossbar = Module(new Crossbar) 17 | 18 | cpu.io.socEn := io.socEn 19 | crossbar.io.runEn := io.runEn 20 | crossbar.io.socEn := io.socEn 21 | 22 | cpu.io.globalEn <> crossbar.io.core.globalEn 23 | cpu.io.fetch <> crossbar.io.core.fetch 24 | cpu.io.ld <> crossbar.io.core.ld 25 | cpu.io.sd <> crossbar.io.core.sd 26 | crossbar.io.dxchg <> io.dxchg 27 | } 28 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/StallControl.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class StallControl extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val globalEn = Input(Bool()) 9 | val stall = Input(Bool()) 10 | val st1 = Output(Bool()) 11 | val st2 = Output(Bool()) 12 | val st3 = Output(Bool()) 13 | }) 14 | 15 | protected val (tickCnt, cntWrap) = Counter(io.globalEn && io.stall, 3) 16 | protected val cyc1 = io.stall && (tickCnt === 0.U) 17 | protected val cyc2 = io.stall && (tickCnt === 1.U) 18 | protected val cyc3 = io.stall && (tickCnt === 2.U) 19 | 20 | io.st1 := cyc1 21 | io.st2 := cyc2 22 | io.st3 := cyc3 23 | } 24 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/TreeCoreL2.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import difftest._ 6 | 7 | class TreeCoreL2 extends Module with InstConfig { 8 | val io = IO(new Bundle { 9 | val globalEn = Input(Bool()) 10 | val socEn = Input(Bool()) 11 | val fetch = new IFIO 12 | val ld = new LDIO 13 | val sd = new SDIO 14 | }) 15 | 16 | protected val ifu = Module(new IFU) 17 | protected val idu = Module(new IDU) 18 | protected val exu = Module(new EXU) 19 | protected val mau = Module(new MAU) 20 | protected val wbu = Module(new WBU) 21 | 22 | // 1. switch base addr 23 | // 2. switch difftest access 24 | ifu.io.socEn := io.socEn 25 | wbu.io.socEn := io.socEn 26 | 27 | // datapath 28 | ifu.io.if2id <> idu.io.if2id 29 | idu.io.id2ex <> exu.io.id2ex 30 | exu.io.ex2mem <> mau.io.ex2mem 31 | mau.io.mem2wb <> wbu.io.mem2wb 32 | // stall signal 33 | exu.io.stall <> idu.io.stall 34 | exu.io.stall <> ifu.io.stall 35 | // branch prediction 36 | ifu.io.branchInfo <> exu.io.branchInfo 37 | // bypass 38 | idu.io.wbdata <> wbu.io.wbdata 39 | exu.io.bypassMem <> mau.io.bypassMem 40 | exu.io.bypassWb <> wbu.io.wbdata 41 | // misc 42 | idu.io.gpr <> wbu.io.gpr 43 | exu.io.nxtPC <> ifu.io.nxtPC 44 | exu.io.mtip <> mau.io.mtip 45 | 46 | // stall control 47 | protected val stallCtrl = Module(new StallControl) 48 | stallCtrl.io.globalEn := io.globalEn 49 | stallCtrl.io.stall := exu.io.stall 50 | 51 | ifu.io.stall := stallCtrl.io.st1 52 | idu.io.stall := stallCtrl.io.st1 53 | ifu.io.globalEn := io.globalEn 54 | idu.io.globalEn := io.globalEn 55 | exu.io.globalEn := Mux(stallCtrl.io.st1 || stallCtrl.io.st2, false.B, io.globalEn) 56 | mau.io.globalEn := Mux(stallCtrl.io.st1 || stallCtrl.io.st2, false.B, io.globalEn) 57 | wbu.io.globalEn := Mux(stallCtrl.io.st1 || stallCtrl.io.st2, false.B, io.globalEn) 58 | idu.io.wbdata := Mux(stallCtrl.io.st1 || stallCtrl.io.st2, 0.U.asTypeOf(new WBDATAIO), wbu.io.wbdata) 59 | ifu.io.nxtPC := Mux(stallCtrl.io.st1, exu.io.nxtPC, 0.U.asTypeOf(new NXTPCIO)) 60 | 61 | // special judge 62 | protected val lsStall = RegEnable(stallCtrl.io.st1, false.B, io.globalEn) || RegEnable(stallCtrl.io.st2, false.B, io.globalEn) 63 | protected val ldDataReg = RegInit(0.U(XLen.W)) 64 | 65 | when(io.globalEn) { 66 | when(stallCtrl.io.st1) { 67 | ldDataReg := io.ld.data 68 | }.elsewhen(stallCtrl.io.st3) { 69 | ldDataReg := 0.U 70 | } 71 | } 72 | 73 | // communicate with extern io 74 | io.fetch <> ifu.io.fetch 75 | io.ld.en := mau.io.ld.en && ~lsStall 76 | io.ld.addr := mau.io.ld.addr 77 | mau.io.ld.data := Mux(lsStall, ldDataReg, io.ld.data) 78 | io.ld.size := mau.io.ld.size 79 | io.sd.en := mau.io.sd.en && ~lsStall 80 | io.sd.addr := mau.io.sd.addr 81 | io.sd.data := mau.io.sd.data 82 | io.sd.mask := mau.io.sd.mask 83 | } 84 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ex/ACU.scala: -------------------------------------------------------------------------------- 1 | // package treecorel2 2 | 3 | // import chisel3._ 4 | // import chisel3.util._ 5 | 6 | // import treecorel2.ConstVal 7 | 8 | // class AGU extends Module { 9 | // val io = IO(new Bundle { 10 | // val isa = Input(new ISAIO) 11 | // val src1 = Input(UInt(ConstVal.AddrLen.W)) 12 | // val src2 = Input(UInt(ConstVal.AddrLen.W)) 13 | // val valid = Output(Bool()) 14 | // val busy = Output(Bool()) 15 | // val res = Output(UInt(ConstVal.AddrLen.W)) 16 | // }) 17 | 18 | // // cordic or gcd 19 | // // https://zhuanlan.zhihu.com/p/304477416 20 | // // https://zhuanlan.zhihu.com/p/365058686 21 | // protected val val1Reg = RegInit(0.U(64.W)) 22 | // protected val val2Reg = RegInit(0.U(64.W)) 23 | // protected val busyReg = RegInit(false.B) 24 | // protected val gcdVis = false.B 25 | 26 | // when(gcdVis && !busyReg) { 27 | // val1Reg := io.src1 28 | // val2Reg := io.src2 29 | // busyReg := true.B 30 | // }.elsewhen(busyReg) { 31 | // when(val1Reg > val2Reg) { 32 | // val1Reg := val1Reg - val2Reg 33 | // }.otherwise { 34 | // val2Reg := val2Reg - val1Reg 35 | // } 36 | // } 37 | 38 | // when(val2Reg === 0.U(64.W)) { busyReg := false.B } 39 | // io.valid := (val2Reg === 0.U(64.W) && busyReg) 40 | // io.busy := busyReg 41 | // io.res := val1Reg 42 | // } 43 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ex/ALU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class ALU extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val isa = Input(UInt(InstValLen.W)) 9 | val src1 = Input(UInt(XLen.W)) 10 | val src2 = Input(UInt(XLen.W)) 11 | val imm = Input(UInt(XLen.W)) 12 | val res = Output(UInt(XLen.W)) 13 | }) 14 | 15 | io.res := MuxLookup( 16 | io.isa, 17 | 0.U(XLen.W), 18 | Seq( 19 | instADDI -> (io.src1 + io.imm), 20 | instADD -> (io.src1 + io.src2), 21 | instLUI -> (io.imm), 22 | instSUB -> (io.src1 - io.src2), 23 | instADDIW -> SignExt((io.src1 + io.imm)(31, 0), 64), 24 | instADDW -> SignExt((io.src1 + io.src2)(31, 0), 64), 25 | instSUBW -> SignExt((io.src1 - io.src2)(31, 0), 64), 26 | instANDI -> (io.src1 & io.imm), 27 | instAND -> (io.src1 & io.src2), 28 | instORI -> (io.src1 | io.imm), 29 | instOR -> (io.src1 | io.src2), 30 | instXORI -> (io.src1 ^ io.imm), 31 | instXOR -> (io.src1 ^ io.src2), 32 | instSLT -> Mux(io.src1.asSInt < io.src2.asSInt, 1.U(XLen.W), 0.U(XLen.W)), 33 | instSLTI -> Mux(io.src1.asSInt < io.imm.asSInt, 1.U(XLen.W), 0.U(XLen.W)), 34 | instSLTU -> Mux(io.src1.asUInt < io.src2.asUInt, 1.U(XLen.W), 0.U(XLen.W)), 35 | instSLTIU -> Mux(io.src1.asUInt < io.imm.asUInt, 1.U(XLen.W), 0.U(XLen.W)), 36 | instSLL -> (io.src1 << io.src2(5, 0))(63, 0), 37 | instSRL -> (io.src1 >> io.src2(5, 0)), 38 | instSRA -> (io.src1.asSInt >> io.src2(5, 0)).asUInt, 39 | instSLLI -> (io.src1 << io.imm(5, 0))(63, 0), 40 | instSRLI -> (io.src1 >> io.imm(5, 0)), 41 | instSRAI -> (io.src1.asSInt >> io.imm(5, 0)).asUInt, 42 | instSLLW -> SignExt((io.src1 << io.src2(4, 0))(31, 0), 64), 43 | instSRLW -> SignExt((io.src1(31, 0) >> io.src2(4, 0)), 64), 44 | instSRAW -> SignExt((io.src1(31, 0).asSInt >> io.src2(4, 0)).asUInt, 64), 45 | instSLLIW -> SignExt((io.src1 << io.imm(4, 0))(31, 0), 64), 46 | instSRLIW -> SignExt((io.src1(31, 0) >> io.imm(4, 0)), 64), 47 | instSRAIW -> SignExt((io.src1(31, 0).asSInt >> io.imm(4, 0)).asUInt, 64) 48 | ) 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ex/BEU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class BEU extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val isa = Input(UInt(InstValLen.W)) 9 | val imm = Input(UInt(XLen.W)) 10 | val src1 = Input(UInt(XLen.W)) 11 | val src2 = Input(UInt(XLen.W)) 12 | val pc = Input(UInt(XLen.W)) 13 | val branIdx = Input(UInt(GHRLen.W)) 14 | val branchInfo = new BRANCHIO 15 | val branch = Output(Bool()) 16 | val tgt = Output(UInt(XLen.W)) 17 | }) 18 | 19 | protected val b = MuxLookup( 20 | io.isa, 21 | false.B, 22 | Seq( 23 | instBEQ -> (io.src1 === io.src2), 24 | instBNE -> (io.src1 =/= io.src2), 25 | instBGEU -> (io.src1 >= io.src2), 26 | instBLTU -> (io.src1 < io.src2), 27 | instBGE -> (io.src1.asSInt >= io.src2.asSInt), 28 | instBLT -> (io.src1.asSInt < io.src2.asSInt) 29 | ) 30 | ) 31 | 32 | protected val bInst = MuxLookup( 33 | io.isa, 34 | false.B, 35 | Seq( 36 | instBEQ -> true.B, 37 | instBNE -> true.B, 38 | instBGEU -> true.B, 39 | instBLTU -> true.B, 40 | instBGE -> true.B, 41 | instBLT -> true.B 42 | ) 43 | ) 44 | 45 | protected val jal = io.isa === instJAL 46 | protected val jalr = io.isa === instJALR 47 | io.branch := b | jal | jalr 48 | 49 | io.tgt := MuxLookup( 50 | io.isa, 51 | (io.pc + io.imm), // NOTE: branch target 52 | Seq( 53 | instJAL -> (io.pc + io.imm), 54 | instJALR -> (io.src1 + io.imm) 55 | ) 56 | ) 57 | 58 | io.branchInfo.branch := bInst 59 | io.branchInfo.jump := jal || jalr 60 | io.branchInfo.taken := io.branch 61 | io.branchInfo.idx := io.branIdx 62 | io.branchInfo.pc := io.pc 63 | io.branchInfo.tgt := io.tgt 64 | } 65 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ex/CSRReg.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import difftest._ 6 | 7 | class CSRReg extends Module with InstConfig { 8 | val io = IO(new Bundle { 9 | val globalEn = Input(Bool()) 10 | val pc = Input(UInt(XLen.W)) 11 | val inst = Input(UInt(XLen.W)) 12 | val src = Input(UInt(XLen.W)) 13 | val data = Output(UInt(XLen.W)) 14 | val mtip = Input(Bool()) 15 | val timeIntrEn = Output(Bool()) 16 | val ecallEn = Output(Bool()) 17 | val csrState = Flipped(new DiffCSRStateIO) 18 | }) 19 | 20 | protected val mcycle = RegInit(0.U(XLen.W)) 21 | protected val mstatus = RegInit(0.U(XLen.W)) 22 | protected val mtvec = RegInit(0.U(XLen.W)) 23 | protected val mcause = RegInit(0.U(XLen.W)) 24 | protected val mepc = RegInit(0.U(XLen.W)) 25 | protected val mie = RegInit(0.U(XLen.W)) 26 | protected val mip = RegInit(0.U(XLen.W)) 27 | protected val mscratch = RegInit(0.U(XLen.W)) 28 | protected val medeleg = RegInit(0.U(XLen.W)) 29 | protected val mhartid = RegInit(0.U(XLen.W)) 30 | 31 | protected val csrVis = MuxLookup( 32 | io.inst, 33 | false.B, 34 | Seq( 35 | instCSRRW -> true.B, 36 | instCSRRWI -> true.B, 37 | instCSRRS -> true.B, 38 | instCSRRSI -> true.B, 39 | instCSRRC -> true.B, 40 | instCSRRCI -> true.B 41 | ) 42 | ) 43 | 44 | protected val zimm = ZeroExt(io.inst(19, 15), XLen) 45 | protected val addr = io.inst(31, 20) 46 | protected val mretVis = io.inst === instMRET 47 | protected val ecallVis = io.inst === instECALL 48 | protected val mhartidVis = addr === mhartidAddr 49 | protected val mstatusVis = addr === mstatusAddr 50 | protected val mieVis = addr === mieAddr 51 | protected val mtvecVis = addr === mtvecAddr 52 | protected val mscratchVis = addr === mscratchAddr 53 | protected val mepcVis = addr === mepcAddr 54 | protected val mcauseVis = addr === mcauseAddr 55 | protected val mipVis = addr === mipAddr 56 | protected val mcycleVis = addr === mcycleAddr 57 | protected val medelegVis = addr === medelegAddr 58 | 59 | protected val rdVal = MuxLookup( 60 | addr, 61 | 0.U(XLen.W), 62 | Seq( 63 | mhartidAddr -> Mux(csrVis, mhartid, 0.U), 64 | mstatusAddr -> Mux(csrVis, mstatus, 0.U), 65 | mieAddr -> Mux(csrVis, mie, 0.U), 66 | mtvecAddr -> Mux(csrVis, mtvec, 0.U), 67 | mscratchAddr -> Mux(csrVis, mscratch, 0.U), 68 | mepcAddr -> Mux(csrVis, mepc, 0.U), 69 | mcauseAddr -> Mux(csrVis, mcause, 0.U), 70 | mipAddr -> Mux(csrVis, mip, 0.U), 71 | mcycleAddr -> Mux(csrVis, mcycle, 0.U), 72 | medelegAddr -> Mux(csrVis, medeleg, 0.U) 73 | ) 74 | ) 75 | 76 | protected val MIE = mstatus(3) 77 | protected val MPIE = mstatus(7) 78 | protected val MPP = mstatus(12, 11) 79 | protected val MTIE = mie(7) 80 | protected val MTIP = mip(7) 81 | protected val TIV = MIE && (MTIE && MTIP) 82 | protected val TIVR = RegEnable(TIV, false.B, io.globalEn) 83 | protected val timeIntrEn = TIV && ~TIVR 84 | protected val ecallEn = ecallVis 85 | io.timeIntrEn := timeIntrEn 86 | io.ecallEn := ecallEn 87 | 88 | protected val wData = MuxLookup( 89 | io.inst, 90 | 0.U(XLen.W), 91 | Seq( 92 | instCSRRC -> (rdVal & ~io.src), 93 | instCSRRCI -> (rdVal & ~zimm), 94 | instCSRRS -> (rdVal | io.src), 95 | instCSRRSI -> (rdVal | zimm), 96 | instCSRRW -> (io.src), 97 | instCSRRWI -> (zimm) 98 | ) 99 | ) 100 | 101 | protected val sdBits = wData(16, 15) === 3.U || wData(14, 13) === 3.U 102 | protected val nop3 = 0.U(3.W) 103 | protected val trapStatus = Cat(mstatus(63, 13), 3.U(2.W), nop3, MIE, nop3, 0.U(1.W), nop3) 104 | protected val mretStatus = Cat(mstatus(63, 13), 0.U(2.W), nop3, 1.U(1.W), nop3, MPIE, nop3) 105 | 106 | when(csrVis && mcycleVis) { 107 | mcycle := wData 108 | }.otherwise { 109 | mcycle := mcycle + 1.U 110 | } 111 | 112 | when(io.globalEn) { 113 | when(timeIntrEn || ecallEn) { 114 | mstatus := trapStatus 115 | }.elsewhen(mretVis) { 116 | mstatus := mretStatus 117 | }.elsewhen(csrVis && mstatusVis) { 118 | mstatus := Cat(sdBits.asUInt, wData(62, 0)) 119 | } 120 | 121 | when(csrVis && mtvecVis) { mtvec := wData } 122 | when(csrVis && mieVis) { mie := wData } 123 | when(csrVis && mipVis) { 124 | mip := wData 125 | }.otherwise { 126 | mip := Mux(io.mtip, "h0000_0000_0000_0080".U, 0.U) 127 | } 128 | 129 | when(timeIntrEn) { 130 | mcause := timeCause 131 | }.elsewhen(ecallEn) { 132 | mcause := ecallCause 133 | }.elsewhen(csrVis && mcauseVis) { 134 | mcause := wData 135 | } 136 | 137 | when(timeIntrEn || ecallEn) { 138 | mepc := io.pc 139 | }.elsewhen(csrVis && mepcVis) { 140 | mepc := wData 141 | } 142 | 143 | when(csrVis && mscratchVis) { mscratch := wData } 144 | when(csrVis && medelegVis) { medeleg := wData } 145 | when(csrVis && mhartidVis) { mhartid := wData } 146 | } 147 | 148 | io.data := rdVal 149 | 150 | io.csrState.clock := clock 151 | io.csrState.coreid := 0.U 152 | io.csrState.mstatus := mstatus 153 | io.csrState.mcause := mcause 154 | io.csrState.mepc := mepc 155 | io.csrState.sstatus := mstatus & "h8000_0003_000d_e122".U 156 | io.csrState.scause := 0.U 157 | io.csrState.sepc := 0.U 158 | io.csrState.satp := 0.U 159 | io.csrState.mip := 0.U 160 | io.csrState.mie := mie 161 | io.csrState.mscratch := mscratch 162 | io.csrState.sscratch := 0.U 163 | io.csrState.mideleg := 0.U 164 | io.csrState.medeleg := medeleg 165 | io.csrState.mtval := 0.U 166 | io.csrState.stval := 0.U 167 | io.csrState.mtvec := mtvec 168 | io.csrState.stvec := 0.U 169 | io.csrState.priviledgeMode := 3.U 170 | } 171 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ex/Divider.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class Divider(val len: Int) extends Module { 7 | val io = IO(new Bundle { 8 | val en = Input(Bool()) 9 | val flush = Input(Bool()) 10 | val divZero = Output(Bool()) 11 | val done = Output(Bool()) 12 | val divident = Input(UInt(len.W)) 13 | val divisor = Input(UInt(len.W)) 14 | val quo = Output(UInt(len.W)) 15 | val rem = Output(UInt(len.W)) 16 | }) 17 | 18 | io.divZero := false.B 19 | io.done := false.B 20 | io.quo := 0.U 21 | io.rem := 0.U 22 | } 23 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ex/EXU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class EXU extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val globalEn = Input(Bool()) 9 | val mtip = Input(Bool()) 10 | val stall = Output(Bool()) 11 | val id2ex = Flipped(new ID2EXIO) 12 | val bypassMem = Flipped(new WBDATAIO) 13 | val bypassWb = Flipped(new WBDATAIO) 14 | val ex2mem = new EX2MEMIO 15 | val nxtPC = new NXTPCIO 16 | val branchInfo = new BRANCHIO 17 | }) 18 | 19 | protected val exReg = RegEnable(io.id2ex, WireInit(0.U.asTypeOf(new ID2EXIO())), io.globalEn) 20 | protected val valid = exReg.valid 21 | protected val inst = exReg.inst 22 | protected val pc = exReg.pc 23 | protected val branIdx = exReg.branIdx 24 | protected val predTaken = exReg.predTaken 25 | protected val isa = exReg.isa 26 | protected val imm = exReg.imm 27 | protected val wen = exReg.wen 28 | protected val rs1 = exReg.inst(19, 15) 29 | protected val rs2 = exReg.inst(24, 20) 30 | protected val wdest = exReg.wdest 31 | 32 | // handle bypass signal 33 | protected val bypassMemSrc1En = io.bypassMem.wen && (rs1 === io.bypassMem.wdest) && (rs1 =/= 0.U) 34 | protected val bypassMemSrc2En = io.bypassMem.wen && (rs2 === io.bypassMem.wdest) && (rs2 =/= 0.U) 35 | protected val bypassWbSrc1En = io.bypassWb.wen && (rs1 === io.bypassWb.wdest) && (rs1 =/= 0.U) 36 | protected val bypassWbSrc2En = io.bypassWb.wen && (rs2 === io.bypassWb.wdest) && (rs2 =/= 0.U) 37 | protected val src1 = Mux(bypassMemSrc1En, io.bypassMem.data, Mux(bypassWbSrc1En, io.bypassWb.data, exReg.src1)) 38 | protected val src2 = Mux(bypassMemSrc2En, io.bypassMem.data, Mux(bypassWbSrc2En, io.bypassWb.data, exReg.src2)) 39 | 40 | protected val alu = Module(new ALU) 41 | alu.io.isa := isa 42 | alu.io.imm := imm 43 | alu.io.src1 := src1 44 | alu.io.src2 := src2 45 | protected val aluRes = alu.io.res 46 | 47 | // protected val mdu = Module(new MDU) 48 | // mdu.io.isa := isa 49 | // mdu.io.src1 := src1 50 | // mdu.io.src2 := src2 51 | // protected val mduRes = mdu.io.res 52 | 53 | // protected val agu = Module(new AGU) 54 | // agu.io.isa := isa 55 | // agu.io.src1 := src1 56 | // agu.io.src2 := src2 57 | // protected val aguRes = agu.io.res 58 | 59 | protected val beu = Module(new BEU) 60 | beu.io.isa := isa 61 | beu.io.imm := imm 62 | beu.io.src1 := src1 63 | beu.io.src2 := src2 64 | beu.io.pc := pc 65 | beu.io.branIdx := branIdx 66 | beu.io.branchInfo <> io.branchInfo 67 | protected val branch = beu.io.branch 68 | protected val tgt = beu.io.tgt 69 | 70 | protected val link = SignExt(((isa === instJAL) | (isa === instJALR)).asUInt, 64) & (pc + 4.U) 71 | protected val auipc = SignExt((isa === instAUIPC).asUInt, 64) & (pc + imm) 72 | 73 | protected val csrReg = Module(new CSRReg) 74 | protected val csrData = csrReg.io.data 75 | protected val timeIntrEn = csrReg.io.timeIntrEn 76 | protected val ecallEn = csrReg.io.ecallEn 77 | csrReg.io.globalEn := io.globalEn 78 | csrReg.io.pc := pc 79 | csrReg.io.inst := Mux(valid, inst, NOPInst) 80 | csrReg.io.src := src1 81 | csrReg.io.mtip := io.mtip 82 | 83 | io.nxtPC.trap := valid && (timeIntrEn || ecallEn) 84 | io.nxtPC.mtvec := csrReg.io.csrState.mtvec 85 | io.nxtPC.mret := valid && (isa === instMRET) 86 | io.nxtPC.mepc := csrReg.io.csrState.mepc 87 | // (pred, fact)--->(NT, T) or (T, NT) 88 | protected val predNTfactT = branch && !predTaken 89 | protected val predTfactNT = !branch && predTaken 90 | io.nxtPC.branch := valid && (predNTfactT || predTfactNT) 91 | io.nxtPC.tgt := Mux(valid && predNTfactT, tgt, Mux(valid && predTfactNT, pc + 4.U, 0.U(XLen.W))) 92 | io.stall := valid && (io.nxtPC.branch || timeIntrEn || ecallEn || (isa === instMRET)) 93 | 94 | io.ex2mem.valid := Mux(timeIntrEn, false.B, valid) 95 | io.ex2mem.inst := inst 96 | io.ex2mem.pc := pc 97 | io.ex2mem.branIdx := branIdx 98 | io.ex2mem.predTaken := predTaken 99 | io.ex2mem.isa := isa 100 | io.ex2mem.src1 := src1 101 | io.ex2mem.src2 := src2 102 | io.ex2mem.imm := imm 103 | io.ex2mem.wen := wen 104 | io.ex2mem.wdest := wdest 105 | io.ex2mem.aluRes := aluRes 106 | io.ex2mem.branch := branch 107 | io.ex2mem.tgt := tgt 108 | io.ex2mem.link := link 109 | io.ex2mem.auipc := auipc 110 | io.ex2mem.csrData := csrData 111 | io.ex2mem.timeIntrEn := timeIntrEn 112 | io.ex2mem.ecallEn := ecallEn 113 | io.ex2mem.csr.mstatus := csrReg.io.csrState.mstatus 114 | io.ex2mem.csr.mcause := csrReg.io.csrState.mcause 115 | io.ex2mem.csr.mepc := csrReg.io.csrState.mepc 116 | io.ex2mem.csr.mie := csrReg.io.csrState.mie 117 | io.ex2mem.csr.mscratch := csrReg.io.csrState.mscratch 118 | io.ex2mem.csr.medeleg := csrReg.io.csrState.medeleg 119 | io.ex2mem.csr.mtvec := csrReg.io.csrState.mtvec 120 | io.ex2mem.csr.mhartid := 0.U 121 | io.ex2mem.csr.mcycle := 0.U 122 | io.ex2mem.csr.mip := 0.U 123 | } 124 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ex/MDU.scala: -------------------------------------------------------------------------------- 1 | // package treecorel2 2 | 3 | // import chisel3._ 4 | // import chisel3.util._ 5 | 6 | // object MDUOpType { 7 | // def mul = "b0000".U 8 | // def mulh = "b0001".U 9 | // def mulhsu = "b0010".U 10 | // def mulhu = "b0011".U 11 | // def mulw = "b0100".U 12 | 13 | // def div = "b1000".U 14 | // def divu = "b1001".U 15 | // def divuw = "b1010".U 16 | // def divw = "b1011".U 17 | // def rem = "b1100".U 18 | // def remu = "b1101".U 19 | // def remuw = "b1110".U 20 | // def remw = "b1111".U 21 | 22 | // def nop = "b1001".U 23 | 24 | // def isMul(op: UInt) = !op(3) 25 | // def isDiv(op: UInt) = op(3) && !(!op(2) && !op(1) && op(0)) 26 | // def isLhsSign(op: UInt) = false.B 27 | // def isRhsSign(op: UInt) = false.B 28 | // def isDivSign(op: UInt) = false.B 29 | // def isHiRem(op: UInt) = false.B 30 | // def isW(op: UInt) = false.B 31 | // } 32 | 33 | // class MDU extends Module { 34 | // val io = IO(new Bundle { 35 | // val isa = Input(new ISAIO) 36 | // val src1 = Input(UInt(64.W)) 37 | // val src2 = Input(UInt(64.W)) 38 | // val res = Output(UInt(64.W)) 39 | // val valid = Output(Bool()) 40 | // }) 41 | 42 | // protected val mduOp = RegInit(MDUOpType.nop) 43 | // when(io.isa.MUL) { 44 | // mduOp := MDUOpType.mul 45 | // }.elsewhen(io.isa.MULH) { 46 | // mduOp := MDUOpType.mulh 47 | // }.elsewhen(io.isa.MULHSU) { 48 | // mduOp := MDUOpType.mulhsu 49 | // }.elsewhen(io.isa.MULHU) { 50 | // mduOp := MDUOpType.mulhu 51 | // }.elsewhen(io.isa.DIV) { 52 | // mduOp := MDUOpType.div 53 | // }.elsewhen(io.isa.DIVU) { 54 | // mduOp := MDUOpType.divu 55 | // }.elsewhen(io.isa.REM) { 56 | // mduOp := MDUOpType.rem 57 | // }.elsewhen(io.isa.REMU) { 58 | // mduOp := MDUOpType.remu 59 | // }.elsewhen(io.isa.MULW) { 60 | // mduOp := MDUOpType.mulw 61 | // }.elsewhen(io.isa.DIVW) { 62 | // mduOp := MDUOpType.divw 63 | // }.elsewhen(io.isa.DIVUW) { 64 | // mduOp := MDUOpType.divuw 65 | // }.elsewhen(io.isa.REMW) { 66 | // mduOp := MDUOpType.remw 67 | // }.elsewhen(io.isa.REMUW) { 68 | // mduOp := MDUOpType.remuw 69 | // } 70 | 71 | // protected val isLhsSign = MDUOpType.isLhsSign(mduOp) 72 | // protected val isRhsSign = MDUOpType.isRhsSign(mduOp) 73 | // protected val isMul = MDUOpType.isMul(mduOp) 74 | // protected val isDiv = MDUOpType.isDiv(mduOp) 75 | // protected val isHiRem = MDUOpType.isHiRem(mduOp) 76 | 77 | // protected val multiplier = Module(new Multiplier(64)) 78 | 79 | // protected val isSrc1Neg = isLhsSign && io.src1(63) 80 | // protected val isSrc2Neg = isRhsSign && io.src2(63) 81 | // protected val isAnsNeg = isSrc1Neg ^ isSrc2Neg 82 | // protected val src1 = Mux(isSrc1Neg, -io.src1, io.src1) 83 | // protected val src2 = Mux(isSrc2Neg, -io.src2, io.src2) 84 | // multiplier.io.en := isMul 85 | // multiplier.io.flush := false.B 86 | // multiplier.io.src1 := src1 87 | // multiplier.io.src2 := src2 88 | 89 | // protected val mulRes = Mux(isAnsNeg, -multiplier.io.res, multiplier.io.res) 90 | 91 | // protected val divider = Module(new Divider(64)) 92 | // protected val fillOnes = Fill(64, 1.U) 93 | // protected val srcMin = 1.U << 64 94 | // protected val isDivOverflow = isLhsSign && src1 === srcMin && src2 === fillOnes 95 | // protected val isRemNeg = isLhsSign && (io.src1(63) ^ divider.io.rem(63)) 96 | // protected val divQuo = Mux(isAnsNeg, -divider.io.quo, divider.io.quo) 97 | // protected val divAnsQuo = Mux(divider.io.divZero, fillOnes, Mux(isDivOverflow, srcMin, divQuo)) 98 | // protected val divRem = Mux(isRemNeg, -divider.io.rem, divider.io.rem) 99 | // protected val divAnsRem = Mux(divider.io.divZero, io.src1, Mux(isDivOverflow, 0.U, divRem)) 100 | // protected val divRes = Mux(isHiRem, divAnsRem, divAnsQuo) 101 | // divider.io.en := isDiv 102 | // divider.io.flush := false.B 103 | // divider.io.divident := src1 104 | // divider.io.divisor := src2 105 | 106 | // io.valid := Mux(isMul, multiplier.io.done, Mux(isDiv, divider.io.done, true.B)) 107 | // io.res := Mux(isMul, mulRes, Mux(isDiv, divRes, 0.U(64.W))) 108 | // } 109 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ex/Multiplier.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class Multiplier(val len: Int, val latency: Int = 0) extends Module { 7 | val io = IO(new Bundle { 8 | val en = Input(Bool()) 9 | val flush = Input(Bool()) 10 | val done = Output(Bool()) 11 | val src1 = Input(UInt(len.W)) 12 | val src2 = Input(UInt(len.W)) 13 | val res = Output(UInt((len * 2).W)) 14 | }) 15 | 16 | require(latency >= 0) 17 | 18 | protected val res = io.src1 * io.src2 19 | 20 | def generatePipe(en: Bool, data: UInt, latency: Int): (Bool, UInt) = { 21 | if (latency == 0) { 22 | (en, data) 23 | } else { 24 | val done = RegNext(Mux(io.flush, false.B, en), false.B) 25 | val bits = RegEnable(data, en) 26 | generatePipe(done, bits, latency - 1) 27 | } 28 | } 29 | 30 | protected val (en, data) = generatePipe(io.en, res, latency) 31 | io.done := en 32 | io.res := data 33 | } 34 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/id/IDU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class IDU extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val globalEn = Input(Bool()) 9 | val stall = Input(Bool()) 10 | val if2id = Flipped(new IF2IDIO) 11 | val wbdata = Flipped(new WBDATAIO) 12 | val id2ex = new ID2EXIO 13 | val gpr = Output(Vec(RegfileNum, UInt(XLen.W))) 14 | }) 15 | 16 | protected val idReg = RegEnable(io.if2id, WireInit(0.U.asTypeOf(new IF2IDIO())), io.globalEn) 17 | protected val inst = idReg.inst 18 | protected val rs1 = inst(19, 15) 19 | protected val rs2 = inst(24, 20) 20 | protected val wdest = inst(11, 7) 21 | 22 | protected val decoder = Module(new ISADecoder) 23 | decoder.io.inst := inst 24 | 25 | protected val regfile = new RegFile 26 | protected val src1En = io.wbdata.wen && (rs1 === io.wbdata.wdest) && (rs1 =/= 0.U) 27 | protected val src2En = io.wbdata.wen && (rs2 === io.wbdata.wdest) && (rs2 =/= 0.U) 28 | protected val src1 = Mux(src1En, io.wbdata.data, regfile.read(rs1)) 29 | protected val src2 = Mux(src2En, io.wbdata.data, regfile.read(rs2)) 30 | 31 | when(io.globalEn) { 32 | regfile.write(io.wbdata.wen, io.wbdata.wdest, io.wbdata.data) 33 | } 34 | 35 | io.id2ex.valid := Mux(io.stall, false.B, idReg.valid) 36 | io.id2ex.inst := inst 37 | io.id2ex.pc := idReg.pc 38 | io.id2ex.branIdx := idReg.branIdx 39 | io.id2ex.predTaken := idReg.predTaken 40 | io.id2ex.src1 := src1 41 | io.id2ex.src2 := src2 42 | io.id2ex.isa := decoder.io.isa 43 | io.id2ex.imm := decoder.io.imm 44 | io.id2ex.wen := decoder.io.wen 45 | io.id2ex.wdest := wdest 46 | io.gpr := regfile.gpr 47 | } 48 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/id/ISADecoder.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | object ISADecoder { 7 | // according to the The RISC-V Instruction Set Manual Volume I: Unprivileged ISA 8 | // Document Version: 20191213 9 | // DESC page [15-25] ABI page[130-131] 10 | 11 | /* Integer Register-Immediate Instructions */ 12 | // I type inst 13 | def ADDI = BitPat("b?????????????????000?????0010011") 14 | def ADDIW = BitPat("b?????????????????000?????0011011") 15 | def SLTI = BitPat("b?????????????????010?????0010011") 16 | def SLTIU = BitPat("b?????????????????011?????0010011") 17 | 18 | def ANDI = BitPat("b?????????????????111?????0010011") 19 | def ORI = BitPat("b?????????????????110?????0010011") 20 | def XORI = BitPat("b?????????????????100?????0010011") 21 | 22 | // special I type inst 23 | def SLLI = BitPat("b000000???????????001?????0010011") 24 | def SLLIW = BitPat("b0000000??????????001?????0011011") 25 | def SRLI = BitPat("b000000???????????101?????0010011") 26 | def SRLIW = BitPat("b0000000??????????101?????0011011") 27 | def SRAI = BitPat("b010000???????????101?????0010011") 28 | def SRAIW = BitPat("b0100000??????????101?????0011011") 29 | // U type inst 30 | // LUI - rd = {imm, 12b'0} 31 | def LUI = BitPat("b?????????????????????????0110111") 32 | // AUIPC - rd = PC + {imm, 12b'0} 33 | def AUIPC = BitPat("b?????????????????????????0010111") 34 | 35 | /* Integer Register-Register Operations */ 36 | // R type inst 37 | def ADD = BitPat("b0000000??????????000?????0110011") 38 | def ADDW = BitPat("b0000000??????????000?????0111011") 39 | def SLT = BitPat("b0000000??????????010?????0110011") 40 | def SLTU = BitPat("b0000000??????????011?????0110011") 41 | 42 | def AND = BitPat("b0000000??????????111?????0110011") 43 | def OR = BitPat("b0000000??????????110?????0110011") 44 | def XOR = BitPat("b0000000??????????100?????0110011") 45 | 46 | def SLL = BitPat("b0000000??????????001?????0110011") 47 | def SLLW = BitPat("b0000000??????????001?????0111011") 48 | def SRL = BitPat("b0000000??????????101?????0110011") 49 | def SRLW = BitPat("b0000000??????????101?????0111011") 50 | 51 | def SUB = BitPat("b0100000??????????000?????0110011") 52 | def SUBW = BitPat("b0100000??????????000?????0111011") 53 | def SRA = BitPat("b0100000??????????101?????0110011") 54 | def SRAW = BitPat("b0100000??????????101?????0111011") 55 | 56 | // NOP - ADDI x0, 0x00(x0) 57 | def NOP = BitPat("b00000000000000000000000000010011") 58 | 59 | /* Control Transfer Instructions */ 60 | // J type inst 61 | def JAL = BitPat("b?????????????????????????1101111") 62 | // I type inst 63 | def JALR = BitPat("b?????????????????000?????1100111") 64 | // B type inst 65 | def BEQ = BitPat("b?????????????????000?????1100011") 66 | def BNE = BitPat("b?????????????????001?????1100011") 67 | def BLT = BitPat("b?????????????????100?????1100011") 68 | def BLTU = BitPat("b?????????????????110?????1100011") 69 | def BGE = BitPat("b?????????????????101?????1100011") 70 | def BGEU = BitPat("b?????????????????111?????1100011") 71 | 72 | /* Load and Store Instructions */ 73 | // I type inst 74 | def LB = BitPat("b?????????????????000?????0000011") 75 | def LBU = BitPat("b?????????????????100?????0000011") 76 | def LH = BitPat("b?????????????????001?????0000011") 77 | def LHU = BitPat("b?????????????????101?????0000011") 78 | def LW = BitPat("b?????????????????010?????0000011") 79 | def LWU = BitPat("b?????????????????110?????0000011") 80 | def LD = BitPat("b?????????????????011?????0000011") 81 | 82 | // S type inst 83 | def SB = BitPat("b?????????????????000?????0100011") 84 | def SH = BitPat("b?????????????????001?????0100011") 85 | def SW = BitPat("b?????????????????010?????0100011") 86 | def SD = BitPat("b?????????????????011?????0100011") 87 | 88 | // CSR inst 89 | def CSRRW = BitPat("b?????????????????001?????1110011") 90 | def CSRRS = BitPat("b?????????????????010?????1110011") 91 | def CSRRC = BitPat("b?????????????????011?????1110011") 92 | def CSRRWI = BitPat("b?????????????????101?????1110011") 93 | def CSRRSI = BitPat("b?????????????????110?????1110011") 94 | def CSRRCI = BitPat("b?????????????????111?????1110011") 95 | 96 | // system inst 97 | def ECALL = BitPat("b00000000000000000000000001110011") 98 | def EBREAK = BitPat("b00000000000100000000000001110011") 99 | def URET = BitPat("b00000000001000000000000001110011") 100 | def SRET = BitPat("b00010000001000000000000001110011") 101 | def MRET = BitPat("b00110000001000000000000001110011") 102 | def WFI = BitPat("b00010000010100000000000001110011") 103 | def SFENCE_VMA = BitPat("b0001001??????????000000001110011") 104 | def FENCE = BitPat("b0000????????00000000000000001111") 105 | def FENCE_I = BitPat("b00000000000000000001000000001111") 106 | // custom inst such as 0x7B 107 | def CUST = BitPat("b0000000??????????000?????1111011") 108 | } 109 | 110 | class ISADecoder extends Module with InstConfig { 111 | val io = IO(new Bundle { 112 | val inst = Input(UInt(InstLen.W)) 113 | val isa = Output(UInt(InstValLen.W)) 114 | val imm = Output(UInt(XLen.W)) 115 | val csr = Output(new Bool()) 116 | val wen = Output(new Bool()) 117 | }) 118 | 119 | protected val csr = (io.isa === instCSRRW) || (io.isa === instCSRRS) || (io.isa === instCSRRC) || (io.isa === instCSRRWI) || (io.isa === instCSRRSI) || (io.isa === instCSRRCI) 120 | protected val decodeTable = Array( 121 | // i type inst 122 | ISADecoder.ADDI -> List(iInstType, wtRegTrue, instADDI), 123 | ISADecoder.ADDIW -> List(iInstType, wtRegTrue, instADDIW), 124 | ISADecoder.SLTI -> List(iInstType, wtRegTrue, instSLTI), 125 | ISADecoder.SLTIU -> List(iInstType, wtRegTrue, instSLTIU), 126 | ISADecoder.ANDI -> List(iInstType, wtRegTrue, instANDI), 127 | ISADecoder.ORI -> List(iInstType, wtRegTrue, instORI), 128 | ISADecoder.XORI -> List(iInstType, wtRegTrue, instXORI), 129 | ISADecoder.SLLI -> List(iInstType, wtRegTrue, instSLLI), 130 | ISADecoder.SLLIW -> List(iInstType, wtRegTrue, instSLLIW), 131 | ISADecoder.SRLI -> List(iInstType, wtRegTrue, instSRLI), 132 | ISADecoder.SRLIW -> List(iInstType, wtRegTrue, instSRLIW), 133 | ISADecoder.SRAI -> List(iInstType, wtRegTrue, instSRAI), 134 | ISADecoder.SRAIW -> List(iInstType, wtRegTrue, instSRAIW), 135 | // u type inst 136 | ISADecoder.LUI -> List(uInstType, wtRegTrue, instLUI), 137 | ISADecoder.AUIPC -> List(uInstType, wtRegTrue, instAUIPC), 138 | // r type inst 139 | ISADecoder.ADD -> List(rInstType, wtRegTrue, instADD), 140 | ISADecoder.ADDW -> List(rInstType, wtRegTrue, instADDW), 141 | ISADecoder.SLT -> List(rInstType, wtRegTrue, instSLT), 142 | ISADecoder.SLTU -> List(rInstType, wtRegTrue, instSLTU), 143 | ISADecoder.AND -> List(rInstType, wtRegTrue, instAND), 144 | ISADecoder.OR -> List(rInstType, wtRegTrue, instOR), 145 | ISADecoder.XOR -> List(rInstType, wtRegTrue, instXOR), 146 | ISADecoder.SLL -> List(rInstType, wtRegTrue, instSLL), 147 | ISADecoder.SLLW -> List(rInstType, wtRegTrue, instSLLW), 148 | ISADecoder.SRL -> List(rInstType, wtRegTrue, instSRL), 149 | ISADecoder.SRLW -> List(rInstType, wtRegTrue, instSRLW), 150 | ISADecoder.SUB -> List(rInstType, wtRegTrue, instSUB), 151 | ISADecoder.SUBW -> List(rInstType, wtRegTrue, instSUBW), 152 | ISADecoder.SRA -> List(rInstType, wtRegTrue, instSRA), 153 | ISADecoder.SRAW -> List(rInstType, wtRegTrue, instSRAW), 154 | // nop inst 155 | ISADecoder.NOP -> List(nopInstType, wtRegFalse, instNOP), 156 | // j type inst 157 | ISADecoder.JAL -> List(jInstType, wtRegTrue, instJAL), 158 | ISADecoder.JALR -> List(iInstType, wtRegTrue, instJALR), 159 | // b type inst 160 | ISADecoder.BEQ -> List(bInstType, wtRegFalse, instBEQ), 161 | ISADecoder.BNE -> List(bInstType, wtRegFalse, instBNE), 162 | ISADecoder.BLT -> List(bInstType, wtRegFalse, instBLT), 163 | ISADecoder.BLTU -> List(bInstType, wtRegFalse, instBLTU), 164 | ISADecoder.BGE -> List(bInstType, wtRegFalse, instBGE), 165 | ISADecoder.BGEU -> List(bInstType, wtRegFalse, instBGEU), 166 | // special i type inst 167 | ISADecoder.LB -> List(iInstType, wtRegTrue, instLB), 168 | ISADecoder.LBU -> List(iInstType, wtRegTrue, instLBU), 169 | ISADecoder.LH -> List(iInstType, wtRegTrue, instLH), 170 | ISADecoder.LHU -> List(iInstType, wtRegTrue, instLHU), 171 | ISADecoder.LW -> List(iInstType, wtRegTrue, instLW), 172 | ISADecoder.LWU -> List(iInstType, wtRegTrue, instLWU), 173 | ISADecoder.LD -> List(iInstType, wtRegTrue, instLD), 174 | // s type inst 175 | ISADecoder.SB -> List(sInstType, wtRegFalse, instSB), 176 | ISADecoder.SH -> List(sInstType, wtRegFalse, instSH), 177 | ISADecoder.SW -> List(sInstType, wtRegFalse, instSW), 178 | ISADecoder.SD -> List(sInstType, wtRegFalse, instSD), 179 | // csr inst 180 | ISADecoder.CSRRW -> List(iInstType, wtRegTrue, instCSRRW), 181 | ISADecoder.CSRRS -> List(iInstType, wtRegTrue, instCSRRS), 182 | ISADecoder.CSRRC -> List(iInstType, wtRegTrue, instCSRRC), 183 | ISADecoder.CSRRWI -> List(iInstType, wtRegTrue, instCSRRWI), 184 | ISADecoder.CSRRSI -> List(iInstType, wtRegTrue, instCSRRSI), 185 | ISADecoder.CSRRCI -> List(iInstType, wtRegTrue, instCSRRCI), 186 | // system inst 187 | ISADecoder.ECALL -> List(nopInstType, wtRegFalse, instECALL), 188 | ISADecoder.MRET -> List(nopInstType, wtRegFalse, instMRET), 189 | ISADecoder.FENCE -> List(nopInstType, wtRegFalse, instFENCE), 190 | ISADecoder.FENCE_I -> List(nopInstType, wtRegFalse, instFENCE_I), 191 | // custom inst 192 | ISADecoder.CUST -> List(nopInstType, wtRegFalse, instCUST) 193 | ) 194 | 195 | protected val immExten = Module(new ImmExten) 196 | protected val defRes = List(nopInstType, wtRegFalse, instNOP) 197 | protected val decRes = ListLookup(io.inst, defRes, decodeTable) 198 | immExten.io.inst := io.inst 199 | immExten.io.instType := decRes(0) 200 | io.isa := decRes(2) 201 | io.imm := immExten.io.imm 202 | io.csr := csr 203 | io.wen := decRes(1) // NOTE: the csr inst type 204 | } 205 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/id/ImmExten.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class ImmExten extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val inst = Input(UInt(InstLen.W)) 9 | val instType = Input(UInt(InstTypeLen.W)) 10 | val imm = Output(UInt(XLen.W)) 11 | }) 12 | 13 | // construct different type immediate 14 | protected val rTypeImm = 0.U(XLen.W) 15 | protected val iTypeImm = SignExt(io.inst(31, 20), XLen) 16 | protected val sTypeImm = SignExt(Cat(io.inst(31, 25), io.inst(11, 7)), XLen) 17 | protected val bTypeImm = SignExt(Cat(io.inst(31), io.inst(7), io.inst(30, 25), io.inst(11, 8), 0.U(1.W)), XLen) 18 | protected val uTypeImm = SignExt(Cat(io.inst(31, 12), 0.U(12.W)), XLen) 19 | protected val jTypeImm = SignExt(Cat(io.inst(31), io.inst(19, 12), io.inst(20), io.inst(30, 21), 0.U(1.W)), XLen) 20 | 21 | io.imm := MuxLookup( 22 | io.instType, 23 | 0.U(XLen.W), 24 | Seq( 25 | rInstType -> rTypeImm, 26 | iInstType -> iTypeImm, 27 | sInstType -> sTypeImm, 28 | bInstType -> bTypeImm, 29 | uInstType -> uTypeImm, 30 | jInstType -> jTypeImm 31 | ) 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/id/RegFile.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class RegFile extends InstConfig { 7 | // public registers 8 | val gpr = RegInit(VecInit(Seq.fill(RegfileNum)(0.U(XLen.W)))) 9 | // io oper 10 | def read(addr: UInt): UInt = { gpr(addr) } 11 | def write(wen: Bool, addr: UInt, data: UInt): Unit = { 12 | when(wen && addr =/= 0.U) { gpr(addr) := data } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/if/BPU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class BPU extends Module with InstConfig { 7 | // 2BP 2BC 8 | // Two-level adaptive predictor 9 | val io = IO(new Bundle { 10 | val branchInfo = Flipped(new BRANCHIO) 11 | // predictor interface 12 | val lookupPc = Input(UInt(XLen.W)) 13 | val predTaken = Output(Bool()) 14 | val predTgt = Output(UInt(XLen.W)) 15 | val predIdx = Output(UInt(GHRLen.W)) 16 | }) 17 | 18 | protected val ghr = Module(new GHR) 19 | protected val pht = Module(new PHT) 20 | protected val btb = Module(new BTB) 21 | 22 | ghr.io.branch := io.branchInfo.branch 23 | ghr.io.taken := io.branchInfo.taken 24 | 25 | // G-share 26 | protected val idx = io.lookupPc(GHRLen - 1, 0) ^ ghr.io.idx 27 | pht.io.prevBranch := io.branchInfo.branch 28 | pht.io.prevTaken := io.branchInfo.taken 29 | pht.io.prevIdx := io.branchInfo.idx 30 | pht.io.idx := idx 31 | 32 | // wire BTB 33 | btb.io.branch := io.branchInfo.branch 34 | btb.io.jump := io.branchInfo.jump 35 | btb.io.pc := io.branchInfo.pc 36 | btb.io.tgt := io.branchInfo.tgt 37 | btb.io.lookupPc := io.lookupPc 38 | 39 | // wire output signals 40 | // now uncond jump is always no-taken to solve 'ret' inst return 'taken' 41 | // when multiple sections call same function 42 | when(btb.io.lookupJump) { 43 | io.predTaken := false.B 44 | }.otherwise { 45 | io.predTaken := btb.io.lookupBranch && pht.io.taken 46 | } 47 | // io.predTaken := btb.io.lookupBranch && (pht.io.taken || btb.io.lookupJump) 48 | io.predTgt := btb.io.lookupTgt 49 | io.predIdx := idx 50 | } 51 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/if/BTB.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class BTBLine extends Bundle with IOConfig { 7 | val pc = UInt(XLen.W) 8 | val tgt = UInt(XLen.W) 9 | val jump = Bool() 10 | } 11 | 12 | class BTB extends Module with InstConfig { 13 | val io = IO(new Bundle { 14 | // branch info (from idu) 15 | val branch = Input(Bool()) 16 | val jump = Input(Bool()) 17 | val pc = Input(UInt(XLen.W)) 18 | val tgt = Input(UInt(XLen.W)) 19 | // BTB lookup interface 20 | val lookupBranch = Output(Bool()) 21 | val lookupJump = Output(Bool()) 22 | val lookupPc = Input(UInt(XLen.W)) 23 | val lookupTgt = Output(UInt(XLen.W)) 24 | }) 25 | 26 | // definitions of BTB lines and valid bits 27 | protected val valids = RegInit(VecInit(Seq.fill(BTBSize) { false.B })) 28 | protected val lines = Mem(BTBSize, new BTBLine) 29 | 30 | // branch info for BTB lines 31 | protected val idx = io.pc(BTBIdxLen - 1, 0) 32 | // write to BTB lines 33 | when(io.branch) { 34 | valids(idx) := true.B 35 | lines(idx).jump := io.jump 36 | lines(idx).pc := io.pc 37 | lines(idx).tgt := io.tgt 38 | } 39 | 40 | // signals about BTB lookup 41 | protected val lookupIdx = io.lookupPc(BTBIdxLen - 1, 0) 42 | protected val lookupPcSel = io.lookupPc 43 | protected val btbHit = valids(lookupIdx) && lines(lookupIdx).pc === lookupPcSel 44 | 45 | // BTB lookup 46 | io.lookupBranch := btbHit 47 | io.lookupJump := Mux(btbHit, lines(lookupIdx).jump, false.B) 48 | io.lookupTgt := Mux(btbHit, lines(lookupIdx).tgt, 0.U(64.W)) 49 | } 50 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/if/Cache.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class CacheReqIO extends Bundle with InstConfig { 7 | val addr = UInt(XLen.W) 8 | val data = UInt(XLen.W) // for write 9 | val mask = UInt((XLen / 8).W) // for write 10 | } 11 | 12 | class CacheRespIO extends Bundle with InstConfig { 13 | val data = UInt(XLen.W) 14 | } 15 | 16 | class CacheCoreIO extends Bundle { 17 | val abort = Input(Bool()) 18 | val req = Flipped(Valid(new CacheReqIO)) 19 | val resp = Valid(new CacheRespIO) 20 | } 21 | 22 | class CacheMemReqIO extends Bundle with InstConfig { 23 | val id = UInt(4.W) 24 | val cmd = UInt(4.W) 25 | val addr = UInt(XLen.W) 26 | val data = UInt(XLen.W) 27 | val len = UInt(2.W) 28 | } 29 | 30 | class CacheMemRespIO extends Bundle with InstConfig { 31 | val id = UInt(4.W) 32 | val cmd = UInt(4.W) 33 | val data = UInt(XLen.W) 34 | 35 | } 36 | 37 | class CacheMemIO extends Bundle { 38 | val req = Decoupled(new CacheMemReqIO) 39 | val resp = Flipped(Decoupled(new CacheMemRespIO)) 40 | } 41 | 42 | class Cache(val cacheType: String) extends Module with InstConfig { 43 | val io = IO(new Bundle { 44 | val core = new CacheCoreIO 45 | val mem = new CacheMemIO 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/if/GHR.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class GHR extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val branch = Input(Bool()) 9 | val taken = Input(Bool()) 10 | val idx = Output(UInt(GHRLen.W)) 11 | }) 12 | 13 | protected val shiftReg = Reg(UInt(GHRLen.W)) 14 | 15 | when(io.branch) { 16 | shiftReg := Cat(shiftReg(GHRLen - 2, 0), io.taken) 17 | } 18 | 19 | io.idx := shiftReg 20 | } 21 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/if/IFU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class IFU extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val globalEn = Input(Bool()) 9 | val stall = Input(Bool()) 10 | val socEn = Input(Bool()) 11 | val branchInfo = Flipped(new BRANCHIO) 12 | val nxtPC = Flipped(new NXTPCIO) 13 | val fetch = new IFIO 14 | val if2id = new IF2IDIO 15 | }) 16 | 17 | protected val startAddr = Mux(io.socEn, FlashStartAddr, SimStartAddr) 18 | protected val pc = RegInit(startAddr) 19 | protected val valid = Mux(reset.asBool(), false.B, true.B) 20 | 21 | protected val bpu = Module(new BPU) 22 | bpu.io.branchInfo <> io.branchInfo 23 | bpu.io.lookupPc := pc 24 | 25 | when(io.globalEn) { 26 | when(io.nxtPC.trap) { 27 | pc := io.nxtPC.mtvec 28 | }.elsewhen(io.nxtPC.mret) { 29 | pc := io.nxtPC.mepc 30 | }.elsewhen(io.nxtPC.branch) { 31 | pc := io.nxtPC.tgt 32 | }.elsewhen(bpu.io.predTaken) { 33 | pc := bpu.io.predTgt 34 | }.otherwise { 35 | pc := pc + 4.U 36 | } 37 | } 38 | 39 | io.if2id.valid := Mux(io.stall, false.B, valid) 40 | io.if2id.inst := io.fetch.data 41 | io.if2id.pc := pc 42 | io.if2id.branIdx := bpu.io.predIdx 43 | io.if2id.predTaken := bpu.io.predTaken 44 | // comm with crossbar to get inst back 45 | io.fetch.en := valid 46 | io.fetch.addr := pc 47 | } 48 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/if/PHT.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class PHT extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | // branch info (from idu) 9 | val prevBranch = Input(Bool()) 10 | val prevTaken = Input(Bool()) 11 | val prevIdx = Input(UInt(GHRLen.W)) 12 | // index for looking up counter table 13 | val idx = Input(UInt(GHRLen.W)) 14 | // prediction result 15 | val taken = Output(Bool()) 16 | }) 17 | 18 | protected val init = Seq.fill(PHTSize) { "b10".U(2.W) } 19 | protected val counters = RegInit(VecInit(init)) 20 | 21 | // update counter 22 | when(io.prevBranch) { 23 | when(counters(io.prevIdx) === "b11".U) { 24 | when(!io.prevTaken) { 25 | counters(io.prevIdx) := counters(io.prevIdx) - 1.U 26 | } 27 | }.elsewhen(counters(io.prevIdx) === "b00".U) { 28 | when(io.prevTaken) { 29 | counters(io.prevIdx) := counters(io.prevIdx) + 1.U 30 | } 31 | }.otherwise { 32 | when(!io.prevTaken) { 33 | counters(io.prevIdx) := counters(io.prevIdx) - 1.U 34 | }.otherwise { 35 | counters(io.prevIdx) := counters(io.prevIdx) + 1.U 36 | } 37 | } 38 | } 39 | 40 | io.taken := counters(io.idx)(1) 41 | } 42 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ma/CLINT.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class CLINT extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val valid = Input(Bool()) 9 | val mtip = Output(Bool()) 10 | val cvalid = Output(Bool()) 11 | val cld = Flipped(new LDIO) 12 | val csd = Flipped(new SDIO) 13 | val ld = new LDIO 14 | val sd = new SDIO 15 | }) 16 | 17 | // now only use the 32bit range addr 18 | protected val addr = Mux(io.cld.en, io.cld.addr(31, 0), 0.U) | Mux(io.csd.en, io.csd.addr(31, 0), 0.U) 19 | protected val wdata = io.csd.data 20 | protected val mtimeVis = addr === ClintBaseAddr + MTimeOffset 21 | protected val mtimecmpVis = addr === ClintBaseAddr + MTimeCmpOffset 22 | 23 | // check if a mmio access 24 | protected val cren = io.cld.en && (mtimecmpVis || mtimeVis) && io.valid 25 | protected val cwen = io.csd.en && (mtimecmpVis || mtimeVis) && io.valid 26 | protected val cvalid = cren || cwen 27 | 28 | // generate low speed clock 29 | protected val (tickCnt, cntWrap) = Counter(true.B, 5) 30 | protected val mtime = RegInit(0.U(XLen.W)) 31 | protected val mtimecmp = RegInit(0.U(XLen.W)) 32 | 33 | when(cwen && mtimeVis) { 34 | mtime := wdata 35 | }.otherwise { 36 | mtime := Mux(cntWrap, mtime + 1.U, mtime) 37 | } 38 | 39 | when(cwen && mtimecmpVis) { mtimecmp := wdata } 40 | 41 | protected val mtimeVal = Mux(cren && mtimeVis, mtime, 0.U) 42 | protected val mtimecmpVal = Mux(cren && mtimecmpVis, mtimecmp, 0.U) 43 | protected val rdata = mtimeVal | mtimecmpVal 44 | 45 | // stall or bypass the sig 46 | io.ld.en := Mux(cvalid, false.B, io.cld.en) 47 | io.ld.addr := io.cld.addr 48 | io.ld.size := io.cld.size 49 | io.cld.data := Mux(cvalid, rdata, io.ld.data) 50 | 51 | io.sd.en := Mux(cvalid, false.B, io.csd.en) 52 | io.sd.addr := io.csd.addr 53 | io.sd.data := io.csd.data 54 | io.sd.mask := io.csd.mask 55 | 56 | io.mtip := mtime >= mtimecmp 57 | io.cvalid := cvalid 58 | } 59 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ma/LSU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class LSU extends Module with InstConfig { 7 | val io = IO(new Bundle { 8 | val valid = Input(Bool()) 9 | val isa = Input(UInt(InstValLen.W)) 10 | val src1 = Input(UInt(XLen.W)) 11 | val src2 = Input(UInt(XLen.W)) 12 | val imm = Input(UInt(XLen.W)) 13 | val ld = new LDIO 14 | val sd = new SDIO 15 | val ldData = Output(UInt(XLen.W)) 16 | }) 17 | 18 | protected val ldInstVis = (io.isa === instLD) || (io.isa === instLW) || (io.isa === instLH) || (io.isa === instLB) || (io.isa === instLWU) || (io.isa === instLHU) || (io.isa === instLBU) 19 | protected val sdInstVis = (io.isa === instSD) || (io.isa === instSW) || (io.isa === instSH) || (io.isa === instSB) 20 | 21 | io.ld.en := io.valid && ldInstVis 22 | io.ld.addr := io.src1 + io.imm 23 | 24 | protected val ldSize = MuxLookup( 25 | io.isa, 26 | 0.U(LDSize.W), 27 | Seq( 28 | instLH -> 1.U(LDSize.W), 29 | instLHU -> 1.U(LDSize.W), 30 | instLW -> 2.U(LDSize.W), 31 | instLWU -> 2.U(LDSize.W), 32 | instLD -> 3.U(LDSize.W) 33 | ) 34 | ) 35 | io.ld.size := ldSize 36 | 37 | protected val dInstData = io.ld.data 38 | protected val wInstData = Mux(io.ld.addr(2).asBool(), dInstData(63, 32), dInstData(31, 0)) 39 | protected val hTypeData = Mux(io.ld.addr(1).asBool(), wInstData(31, 16), wInstData(15, 0)) 40 | protected val bTypeData = Mux(io.ld.addr(0).asBool(), hTypeData(15, 8), hTypeData(7, 0)) 41 | 42 | io.ldData := MuxLookup( 43 | io.isa, 44 | 0.U(XLen.W), 45 | Seq( 46 | instLD -> dInstData, 47 | instLW -> (SignExt(wInstData, XLen)), 48 | instLH -> (SignExt(hTypeData, XLen)), 49 | instLB -> (SignExt(bTypeData, XLen)), 50 | instLWU -> (ZeroExt(wInstData, XLen)), 51 | instLHU -> (ZeroExt(hTypeData, XLen)), 52 | instLBU -> (ZeroExt(bTypeData, XLen)) 53 | ) 54 | ) 55 | 56 | // store signals 57 | io.sd.en := io.valid && sdInstVis 58 | io.sd.addr := io.src1 + io.imm 59 | protected val storeData = MuxLookup( 60 | io.isa, 61 | 0.U(XLen.W), 62 | Seq( 63 | instSD -> io.src2, 64 | instSW -> Cat(io.src2(31, 0), io.src2(31, 0)), 65 | instSH -> Cat(io.src2(15, 0), io.src2(15, 0), io.src2(15, 0), io.src2(15, 0)), 66 | instSB -> Cat(io.src2(7, 0), io.src2(7, 0), io.src2(7, 0), io.src2(7, 0), io.src2(7, 0), io.src2(7, 0), io.src2(7, 0), io.src2(7, 0)) 67 | ) 68 | ) 69 | 70 | val sdMask = MuxLookup( 71 | io.isa, 72 | 0.U(MaskLen.W), // NOTE: important!!! 73 | Seq( 74 | instSD -> "b1111_1111".U(MaskLen.W), 75 | instSW -> ("b0000_1111".U(MaskLen.W) << io.sd.addr(2, 0)), 76 | instSH -> ("b0000_0011".U(MaskLen.W) << io.sd.addr(2, 0)), 77 | instSB -> ("b0000_0001".U(MaskLen.W) << io.sd.addr(2, 0)) 78 | ) 79 | ) 80 | 81 | val tmpMask = Wire(Vec(8, UInt((XLen / 8).W))) 82 | for (i <- 0 until 8) { 83 | tmpMask(i) := Mux(sdMask(i).asBool(), "hff".U((XLen / 8).W), 0.U((XLen / 8).W)) 84 | } 85 | protected val extenMask = tmpMask.asUInt() 86 | 87 | io.sd.data := storeData & extenMask 88 | io.sd.mask := sdMask 89 | } 90 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/ma/MAU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class MAU extends Module { 7 | val io = IO(new Bundle { 8 | val globalEn = Input(Bool()) 9 | val ex2mem = Flipped(new EX2MEMIO) 10 | val mem2wb = new MEM2WBIO 11 | val ld = new LDIO 12 | val sd = new SDIO 13 | val bypassMem = new WBDATAIO 14 | val mtip = Output(Bool()) 15 | }) 16 | 17 | protected val memReg = RegEnable(io.ex2mem, WireInit(0.U.asTypeOf(new EX2MEMIO())), io.globalEn) 18 | protected val valid = memReg.valid 19 | protected val inst = memReg.inst 20 | protected val isa = memReg.isa 21 | protected val imm = memReg.imm 22 | protected val src1 = memReg.src1 23 | protected val src2 = memReg.src2 24 | protected val csr = memReg.csr 25 | 26 | protected val lsu = Module(new LSU) 27 | lsu.io.valid := valid 28 | lsu.io.isa := isa 29 | lsu.io.src1 := src1 30 | lsu.io.src2 := src2 31 | lsu.io.imm := imm 32 | protected val ldData = lsu.io.ldData 33 | 34 | protected val clint = Module(new CLINT) 35 | clint.io.valid := valid 36 | clint.io.cld <> lsu.io.ld 37 | clint.io.csd <> lsu.io.sd 38 | io.ld <> clint.io.ld 39 | io.sd <> clint.io.sd 40 | 41 | protected val isLoad = lsu.io.ld.en 42 | protected val memWbdata = memReg.aluRes | memReg.link | memReg.auipc | memReg.csrData 43 | 44 | // bypass path 45 | io.bypassMem.wen := Mux(isLoad, true.B, memReg.wen) && valid 46 | io.bypassMem.wdest := Mux(isLoad, memReg.wdest, memReg.wdest) 47 | io.bypassMem.data := Mux(isLoad, ldData, memWbdata) 48 | 49 | io.mem2wb.valid := valid 50 | io.mem2wb.inst := inst 51 | io.mem2wb.pc := memReg.pc 52 | io.mem2wb.branIdx := memReg.branIdx 53 | io.mem2wb.predTaken := memReg.predTaken 54 | io.mem2wb.isa := isa 55 | io.mem2wb.src1 := src1 56 | io.mem2wb.src2 := src2 57 | io.mem2wb.imm := imm 58 | io.mem2wb.wen := memReg.wen 59 | io.mem2wb.wdest := memReg.wdest 60 | io.mem2wb.aluRes := memReg.aluRes 61 | io.mem2wb.branch := memReg.branch 62 | io.mem2wb.tgt := memReg.tgt 63 | io.mem2wb.link := memReg.link 64 | io.mem2wb.auipc := memReg.auipc 65 | io.mem2wb.csrData := memReg.csrData 66 | io.mem2wb.ldData := ldData 67 | io.mem2wb.cvalid := clint.io.cvalid 68 | io.mem2wb.timeIntrEn := memReg.timeIntrEn 69 | io.mem2wb.ecallEn := memReg.ecallEn 70 | io.mem2wb.csr := memReg.csr 71 | io.mtip := clint.io.mtip 72 | } 73 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/core/wb/WBU.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | import difftest._ 7 | 8 | class WBU extends Module with InstConfig { 9 | val io = IO(new Bundle { 10 | val globalEn = Input(Bool()) 11 | val socEn = Input(Bool()) 12 | val mem2wb = Flipped(new MEM2WBIO) 13 | val wbdata = new WBDATAIO 14 | val gpr = Input(Vec(RegfileNum, UInt(XLen.W))) 15 | }) 16 | 17 | protected val wbReg = RegEnable(io.mem2wb, WireInit(0.U.asTypeOf(new MEM2WBIO())), io.globalEn) 18 | protected val valid = wbReg.valid 19 | protected val inst = wbReg.inst 20 | protected val pc = wbReg.pc 21 | protected val isa = wbReg.isa 22 | protected val wen = wbReg.wen 23 | protected val wdest = wbReg.wdest 24 | protected val aluRes = wbReg.aluRes 25 | protected val link = wbReg.link 26 | protected val auipc = wbReg.auipc 27 | protected val ldData = wbReg.ldData 28 | protected val csrData = wbReg.csrData 29 | protected val cvalid = wbReg.cvalid 30 | protected val timeIntrEn = wbReg.timeIntrEn 31 | protected val csr = wbReg.csr 32 | 33 | protected val wbdata = aluRes | link | auipc | ldData | csrData 34 | 35 | io.wbdata.wen := valid && wen 36 | io.wbdata.wdest := wdest 37 | io.wbdata.data := wbdata 38 | 39 | protected val printVis = inst === customInst 40 | protected val haltVis = inst === haltInst 41 | 42 | when(~io.socEn) { 43 | when(io.globalEn && valid && printVis) { 44 | printf("%c", io.gpr(10)) 45 | } 46 | } 47 | 48 | // for difftest commit 49 | if (!SoCEna) { 50 | val mmioEn = cvalid 51 | val csrVis = (isa === instCSRRW) || (isa === instCSRRS) || (isa === instCSRRC) || (isa === instCSRRWI) || (isa === instCSRRSI) || (isa === instCSRRCI) 52 | val mcycleVis = csrVis && (inst(31, 20) === mcycleAddr) 53 | val mipVis = csrVis && (inst(31, 20) === mipAddr) 54 | val timeIntrEnReg = RegEnable(timeIntrEn, false.B, io.globalEn) 55 | val diffValid = io.globalEn && (RegEnable(valid, false.B, io.globalEn) || timeIntrEnReg) 56 | 57 | val instComm = Module(new DifftestInstrCommit) 58 | val archIntRegState = Module(new DifftestArchIntRegState) 59 | val csrState = Module(new DifftestCSRState) 60 | val trapEvt = Module(new DifftestTrapEvent) 61 | val archFpRegState = Module(new DifftestArchFpRegState) 62 | val archEvt = Module(new DifftestArchEvent) 63 | val cycleCnt = Counter(Int.MaxValue) // NOTE: maybe overflow? 64 | val instrCnt = Counter(Int.MaxValue) 65 | cycleCnt.inc() 66 | when(io.globalEn && valid) { instrCnt.inc() } 67 | 68 | instComm.io.clock := clock 69 | instComm.io.coreid := 0.U 70 | instComm.io.index := 0.U 71 | instComm.io.valid := diffValid && ~timeIntrEnReg 72 | instComm.io.pc := RegEnable(pc, 0.U, io.globalEn) 73 | instComm.io.instr := RegEnable(inst, 0.U, io.globalEn) 74 | instComm.io.special := 0.U 75 | instComm.io.skip := diffValid && RegEnable(printVis || mcycleVis || mmioEn || mipVis, false.B, io.globalEn) 76 | instComm.io.isRVC := false.B 77 | instComm.io.scFailed := false.B 78 | instComm.io.wen := RegEnable(wen, false.B, io.globalEn) 79 | instComm.io.wdata := RegEnable(wbdata, 0.U, io.globalEn) 80 | instComm.io.wdest := RegEnable(wdest, 0.U, io.globalEn) 81 | archIntRegState.io.clock := clock 82 | archIntRegState.io.coreid := 0.U 83 | archIntRegState.io.gpr := io.gpr 84 | csrState.io.clock := clock 85 | csrState.io.coreid := 0.U 86 | csrState.io.mstatus := csr.mstatus 87 | csrState.io.mcause := csr.mcause 88 | csrState.io.mepc := csr.mepc 89 | csrState.io.sstatus := csr.mstatus & "h8000_0003_000d_e122".U 90 | csrState.io.scause := 0.U 91 | csrState.io.sepc := 0.U 92 | csrState.io.satp := 0.U 93 | csrState.io.mip := 0.U 94 | csrState.io.mie := csr.mie 95 | csrState.io.mscratch := csr.mscratch 96 | csrState.io.sscratch := 0.U 97 | csrState.io.mideleg := 0.U 98 | csrState.io.medeleg := csr.medeleg 99 | csrState.io.mtval := 0.U 100 | csrState.io.stval := 0.U 101 | csrState.io.mtvec := csr.mtvec 102 | csrState.io.stvec := 0.U 103 | csrState.io.priviledgeMode := 3.U 104 | archEvt.io.clock := clock 105 | archEvt.io.coreid := 0.U 106 | archEvt.io.intrNO := Mux(diffValid && timeIntrEnReg, 7.U, 0.U) 107 | archEvt.io.cause := 0.U 108 | archEvt.io.exceptionPC := RegEnable(pc, 0.U, io.globalEn) 109 | archEvt.io.exceptionInst := RegEnable(inst, 0.U, io.globalEn) 110 | trapEvt.io.clock := clock 111 | trapEvt.io.coreid := 0.U 112 | trapEvt.io.valid := diffValid && RegEnable(haltVis, false.B, io.globalEn) 113 | trapEvt.io.code := io.gpr(10)(7, 0) 114 | trapEvt.io.pc := RegEnable(pc, 0.U, io.globalEn) 115 | trapEvt.io.cycleCnt := cycleCnt.value 116 | trapEvt.io.instrCnt := instrCnt.value 117 | archFpRegState.io.clock := clock 118 | archFpRegState.io.coreid := 0.U 119 | archFpRegState.io.fpr := RegInit(VecInit(Seq.fill(RegfileNum)(0.U(XLen.W)))) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/AXI4IO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class SOCAXI4ARWIO extends Bundle with AXI4Config { 7 | val addr = Output(UInt(32.W)) 8 | val id = Output(UInt(AxiIdLen.W)) 9 | val len = Output(UInt(AxiLen.W)) 10 | val size = Output(UInt(AxiSizeLen.W)) 11 | val burst = Output(UInt(AxiBurstLen.W)) 12 | } 13 | 14 | class AXI4ARWIO extends SOCAXI4ARWIO { 15 | override val addr = Output(UInt(XLen.W)) 16 | val prot = Output(UInt(AxiProtLen.W)) 17 | val user = Output(UInt(AxiUserLen.W)) 18 | val lock = Output(Bool()) 19 | val cache = Output(UInt(AxiCacheLen.W)) 20 | val qos = Output(UInt(AxiQosLen.W)) 21 | } 22 | 23 | class SOCAXI4WIO extends Bundle with AXI4Config { 24 | val data = Output(UInt(XLen.W)) 25 | val strb = Output(UInt(AxiStrb.W)) 26 | val last = Output(Bool()) 27 | } 28 | 29 | class AXI4WIO extends SOCAXI4WIO {} 30 | 31 | class SOCAXI4BIO extends Bundle with AXI4Config { 32 | val resp = Output(UInt(AxiRespLen.W)) 33 | val id = Output(UInt(AxiIdLen.W)) 34 | } 35 | 36 | class AXI4BIO extends SOCAXI4BIO { 37 | val user = Output(UInt(AxiUserLen.W)) 38 | } 39 | 40 | class SOCAXI4RIO extends Bundle with AXI4Config { 41 | val resp = Output(UInt(AxiRespLen.W)) 42 | val data = Output(UInt(XLen.W)) 43 | val last = Output(Bool()) 44 | val id = Output(UInt(AxiIdLen.W)) 45 | } 46 | 47 | class AXI4RIO extends SOCAXI4RIO { 48 | val user = Output(UInt(AxiUserLen.W)) 49 | } 50 | 51 | class SOCAXI4IO extends Bundle { 52 | val aw = Decoupled(new SOCAXI4ARWIO) 53 | val w = Decoupled(new SOCAXI4WIO) 54 | val b = Flipped(Decoupled(new SOCAXI4BIO)) 55 | val ar = Decoupled(new SOCAXI4ARWIO) 56 | val r = Flipped(Decoupled(new SOCAXI4RIO)) 57 | } 58 | 59 | class AXI4IO extends SOCAXI4IO { 60 | override val aw = Decoupled(new AXI4ARWIO) 61 | override val w = Decoupled(new AXI4WIO) 62 | override val b = Flipped(Decoupled(new AXI4BIO)) 63 | override val ar = Decoupled(new AXI4ARWIO) 64 | override val r = Flipped(Decoupled(new AXI4RIO)) 65 | } 66 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/BRANCHIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class BRANCHIO extends Bundle with IOConfig { 7 | val branch = Output(Bool()) // prev inst is a b/j 8 | val jump = Output(Bool()) // is 'jal' or 'jalr' 9 | val taken = Output(Bool()) // is prev branch taken 10 | val idx = Output(UInt(GHRLen.W)) // prev idx of PHT(GHRLen) 11 | val pc = Output(UInt(XLen.W)) // prev instruction PC 12 | val tgt = Output(UInt(XLen.W)) // prev branch tgt 13 | } 14 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/COREIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class COREIO extends Bundle { 7 | val globalEn = Output(Bool()) 8 | val fetch = Flipped(new IFIO) 9 | val ld = Flipped(new LDIO) 10 | val sd = Flipped(new SDIO) 11 | } 12 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/CSRIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class csr extends Bundle with IOConfig { 7 | val mcycle = UInt(XLen.W) 8 | val mstatus = UInt(XLen.W) 9 | val mtvec = UInt(XLen.W) 10 | val mcause = UInt(XLen.W) 11 | val mepc = UInt(XLen.W) 12 | val mie = UInt(XLen.W) 13 | val mip = UInt(XLen.W) 14 | val mscratch = UInt(XLen.W) 15 | val medeleg = UInt(XLen.W) 16 | val mhartid = UInt(XLen.W) 17 | } 18 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/DXCHGIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class DXCHGIO extends Bundle with IOConfig { 7 | val ren = Output(Bool()) 8 | val raddr = Output(UInt(XLen.W)) 9 | val rdata = Input(UInt(XLen.W)) 10 | val rsize = Output(UInt(LDSize.W)) 11 | val wen = Output(Bool()) 12 | val waddr = Output(UInt(XLen.W)) 13 | val wdata = Output(UInt(XLen.W)) 14 | val wmask = Output(UInt(MaskLen.W)) 15 | } 16 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/EX2MEMIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class EX2MEMIO extends ID2EXIO with IOConfig { 7 | val aluRes = Output(UInt(XLen.W)) 8 | val branch = Output(Bool()) 9 | val tgt = Output(UInt(XLen.W)) 10 | val link = Output(UInt(XLen.W)) 11 | val auipc = Output(UInt(XLen.W)) 12 | val csrData = Output(UInt(XLen.W)) 13 | val timeIntrEn = Output(Bool()) 14 | val ecallEn = Output(Bool()) 15 | val csr = Output(new csr) 16 | } 17 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/ID2EXIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class ID2EXIO extends IF2IDIO with IOConfig { 7 | val isa = Output(UInt(ISALen.W)) 8 | val src1 = Output(UInt(XLen.W)) 9 | val src2 = Output(UInt(XLen.W)) 10 | val imm = Output(UInt(XLen.W)) 11 | val wen = Output(Bool()) 12 | val wdest = Output(UInt(RegfileLen.W)) 13 | } 14 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/IF2IDIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class IF2IDIO extends Bundle with IOConfig { 7 | val valid = Output(Bool()) 8 | val inst = Output(UInt(InstLen.W)) 9 | val pc = Output(UInt(XLen.W)) 10 | val branIdx = Output(UInt(GHRLen.W)) 11 | val predTaken = Output(Bool()) 12 | } 13 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/IFIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class IFIO extends Bundle with IOConfig { 7 | val en = Output(Bool()) 8 | val addr = Output(UInt(XLen.W)) 9 | val data = Input(UInt(InstLen.W)) 10 | } 11 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/LSIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class LDIO extends Bundle with IOConfig { 7 | val en = Output(Bool()) 8 | val addr = Output(UInt(XLen.W)) 9 | val data = Input(UInt(XLen.W)) 10 | val size = Output(UInt(LDSize.W)) 11 | } 12 | 13 | class SDIO extends Bundle with IOConfig { 14 | val en = Output(Bool()) 15 | val addr = Output(UInt(XLen.W)) 16 | val data = Output(UInt(XLen.W)) 17 | val mask = Output(UInt(MaskLen.W)) 18 | } 19 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/MDUIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class MulDivIO(val len: Int) extends Bundle { 7 | val in = Flipped(DecoupledIO(Vec(2, Output(UInt(len.W))))) 8 | val res = DecoupledIO(Output(UInt((len * 2).W))) 9 | } 10 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/MEM2WBIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class MEM2WBIO extends EX2MEMIO with IOConfig { 7 | val ldData = Output(UInt(XLen.W)) 8 | val cvalid = Output(Bool()) 9 | } 10 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/NXTPCIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class NXTPCIO extends Bundle with IOConfig { 7 | val trap = Output(Bool()) 8 | val mtvec = Output(UInt(XLen.W)) 9 | val mret = Output(Bool()) 10 | val mepc = Output(UInt(XLen.W)) 11 | val branch = Output(Bool()) 12 | val tgt = Output(UInt(XLen.W)) 13 | } 14 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/port/WBDATAIO.scala: -------------------------------------------------------------------------------- 1 | package treecorel2 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class WBDATAIO extends Bundle with IOConfig { 7 | val wen = Output(Bool()) 8 | val wdest = Output(UInt(RegfileLen.W)) 9 | val data = Output(UInt(XLen.W)) 10 | } 11 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/top/SimTop.scala: -------------------------------------------------------------------------------- 1 | package sim 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | import difftest._ 7 | import treecorel2._ 8 | 9 | class SimTop extends Module { 10 | val io = IO(new Bundle { 11 | val logCtrl = new LogCtrlIO 12 | val perfInfo = new PerfInfoIO 13 | val uart = new UARTIO 14 | val memAXI_0 = new AXI4IO 15 | }) 16 | 17 | protected val proc = Module(new Processor) 18 | protected val axiBridge = Module(new AXI4Bridge) 19 | 20 | io.uart.in.valid := false.B 21 | io.uart.out.valid := false.B 22 | io.uart.out.ch := 0.U 23 | 24 | proc.io.runEn <> axiBridge.io.runEn 25 | proc.io.dxchg <> axiBridge.io.dxchg 26 | proc.io.socEn := false.B 27 | axiBridge.io.socEn := false.B 28 | 29 | io.memAXI_0 <> axiBridge.io.axi 30 | } 31 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/top/SoCTop.scala: -------------------------------------------------------------------------------- 1 | package sim 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import treecorel2._ 6 | 7 | class SoCTop extends Module { 8 | val io = IO(new Bundle { 9 | val interrupt = Input(Bool()) 10 | val master = new SOCAXI4IO 11 | val slave = Flipped(new SOCAXI4IO) 12 | }) 13 | 14 | val proc = Module(new Processor) 15 | val axiBridge = Module(new AXI4Bridge) 16 | proc.io.runEn <> axiBridge.io.runEn 17 | proc.io.dxchg <> axiBridge.io.dxchg 18 | proc.io.socEn := true.B 19 | axiBridge.io.socEn := true.B 20 | 21 | io.master <> axiBridge.io.axi 22 | 23 | io.slave.aw.ready := false.B 24 | io.slave.w.ready := false.B 25 | io.slave.b.valid := false.B 26 | io.slave.b.bits.resp := 0.U 27 | io.slave.b.bits.id := 0.U 28 | io.slave.ar.ready := false.B 29 | io.slave.r.valid := false.B 30 | io.slave.r.bits.resp := 0.U 31 | io.slave.r.bits.data := 0.U 32 | io.slave.r.bits.last := false.B 33 | io.slave.r.bits.id := 0.U 34 | } 35 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/top/TopMain.scala: -------------------------------------------------------------------------------- 1 | package top 2 | 3 | import sim._ 4 | 5 | import treecorel2.InstConfig 6 | 7 | object TopMain extends App with InstConfig { 8 | if (!SoCEna) { 9 | (new chisel3.stage.ChiselStage).execute( 10 | args, 11 | Seq( 12 | chisel3.stage.ChiselGeneratorAnnotation(() => new SimTop()) 13 | ) 14 | ) 15 | } else { 16 | (new chisel3.stage.ChiselStage).execute( 17 | args, 18 | Seq( 19 | chisel3.stage.ChiselGeneratorAnnotation(() => new SoCTop()), 20 | firrtl.stage.RunFirrtlTransformAnnotation(new AddModulePrefix()), 21 | ModulePrefixAnnotation("ysyx_210324_") 22 | ) 23 | ) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/utils/AddModulePrefix.scala: -------------------------------------------------------------------------------- 1 | // ref: https://github.com/OSCPU/ysyxSoC/blob/master/ysyx/module-prefix/AddModulePrefix.scala 2 | // thanks to (Jiawei Lin)https://github.com/ljwljwljwljw 3 | package sim // modify to your package name 4 | 5 | import firrtl._ 6 | import firrtl.annotations.{ModuleTarget, NoTargetAnnotation} 7 | import firrtl.ir._ 8 | import firrtl.stage.Forms 9 | import firrtl.stage.TransformManager.TransformDependency 10 | import firrtl.transforms.DontTouchAnnotation 11 | 12 | case class ModulePrefixAnnotation(prefix: String) extends NoTargetAnnotation 13 | 14 | class AddModulePrefix extends Transform with DependencyAPIMigration { 15 | 16 | override def prerequisites: Seq[TransformDependency] = Forms.LowForm 17 | override def optionalPrerequisites: Seq[TransformDependency] = Forms.LowFormOptimized 18 | override def optionalPrerequisiteOf: Seq[TransformDependency] = Forms.LowEmitters 19 | override def invalidates(a: Transform): Boolean = false 20 | 21 | override protected def execute(state: CircuitState): CircuitState = { 22 | val c = state.circuit 23 | 24 | val prefix = state.annotations.collectFirst { 25 | case ModulePrefixAnnotation(p) => p 26 | }.get 27 | 28 | val blacklist = List( 29 | "S011HD1P_X32Y2D128", 30 | "ysyx_210324" 31 | ) 32 | 33 | val extModules = state.circuit.modules 34 | .filter({ m => 35 | m match { 36 | case blackbox: ExtModule => true 37 | case other => false 38 | } 39 | }) 40 | .map(_.name) 41 | 42 | def rename(old: String): String = if (blacklist.map(_ == old).reduce(_ || _)) old 43 | else if (extModules.contains(old)) old 44 | else prefix + old 45 | 46 | // val renameMap = RenameMap() 47 | val renameMap = firrtl.renamemap.MutableRenameMap() // for firrtl 1.5 under the chisel 3.5.x 48 | 49 | def onStmt(s: Statement): Statement = s match { 50 | case DefInstance(info, name, module, tpe) => 51 | DefInstance(info, name, rename(module), tpe) 52 | case other => 53 | other.mapStmt(onStmt) 54 | } 55 | 56 | def onModule(m: DefModule): DefModule = m match { 57 | case Module(info, name, ports, body) => 58 | val newName = rename(name) 59 | renameMap.record( 60 | ModuleTarget(c.main, name), 61 | ModuleTarget(c.main, newName) 62 | ) 63 | Module(info, newName, ports, body).mapStmt(onStmt) 64 | case extModule: ExtModule => extModule 65 | } 66 | 67 | val newCircuit = c.mapModule(onModule) 68 | state.copy( 69 | circuit = newCircuit.copy(main = rename(c.main)), 70 | renames = Some(renameMap) 71 | ) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/utils/Debug.scala: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rtl/TreeCoreL2/tc_l2/src/main/scala/utils/Difftest.scala: -------------------------------------------------------------------------------- 1 | /** ************************************************************************************* 2 | * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3 | * Copyright (c) 2020-2021 Peng Cheng Laboratory 4 | * 5 | * XiangShan is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | * ************************************************************************************* 16 | */ 17 | 18 | package difftest 19 | 20 | import chisel3._ 21 | import chisel3.util._ 22 | import Chisel.BlackBox 23 | 24 | trait DifftestParameter {} 25 | 26 | trait DifftestWithClock { 27 | val clock = Input(Clock()) 28 | } 29 | 30 | trait DifftestWithCoreid { 31 | val coreid = Input(UInt(8.W)) 32 | } 33 | 34 | trait DifftestWithIndex { 35 | val index = Input(UInt(8.W)) 36 | } 37 | 38 | abstract class DifftestBundle extends Bundle with DifftestParameter with DifftestWithClock with DifftestWithCoreid 39 | 40 | class DiffArchEventIO extends DifftestBundle { 41 | val intrNO = Input(UInt(32.W)) 42 | val cause = Input(UInt(32.W)) 43 | val exceptionPC = Input(UInt(64.W)) 44 | val exceptionInst = Input(UInt(32.W)) 45 | } 46 | 47 | class DiffInstrCommitIO extends DifftestBundle with DifftestWithIndex { 48 | val valid = Input(Bool()) 49 | val pc = Input(UInt(64.W)) 50 | val instr = Input(UInt(32.W)) 51 | val special = Input(UInt(8.W)) 52 | val skip = Input(Bool()) 53 | val isRVC = Input(Bool()) 54 | val scFailed = Input(Bool()) 55 | val wen = Input(Bool()) 56 | val wdata = Input(UInt(64.W)) 57 | val wdest = Input(UInt(8.W)) 58 | } 59 | 60 | class DiffTrapEventIO extends DifftestBundle { 61 | val valid = Input(Bool()) 62 | val code = Input(UInt(3.W)) 63 | val pc = Input(UInt(64.W)) 64 | val cycleCnt = Input(UInt(64.W)) 65 | val instrCnt = Input(UInt(64.W)) 66 | } 67 | 68 | class DiffCSRStateIO extends DifftestBundle { 69 | val priviledgeMode = Input(UInt(2.W)) 70 | val mstatus = Input(UInt(64.W)) 71 | val sstatus = Input(UInt(64.W)) 72 | val mepc = Input(UInt(64.W)) 73 | val sepc = Input(UInt(64.W)) 74 | val mtval = Input(UInt(64.W)) 75 | val stval = Input(UInt(64.W)) 76 | val mtvec = Input(UInt(64.W)) 77 | val stvec = Input(UInt(64.W)) 78 | val mcause = Input(UInt(64.W)) 79 | val scause = Input(UInt(64.W)) 80 | val satp = Input(UInt(64.W)) 81 | val mip = Input(UInt(64.W)) 82 | val mie = Input(UInt(64.W)) 83 | val mscratch = Input(UInt(64.W)) 84 | val sscratch = Input(UInt(64.W)) 85 | val mideleg = Input(UInt(64.W)) 86 | val medeleg = Input(UInt(64.W)) 87 | } 88 | 89 | class DiffArchIntRegStateIO extends DifftestBundle { 90 | val gpr = Input(Vec(32, UInt(64.W))) 91 | } 92 | 93 | class DiffArchFpRegStateIO extends DifftestBundle { 94 | val fpr = Input(Vec(32, UInt(64.W))) 95 | } 96 | 97 | class DiffSbufferEventIO extends DifftestBundle { 98 | val sbufferResp = Input(Bool()) 99 | val sbufferAddr = Input(UInt(64.W)) 100 | val sbufferData = Input(Vec(64, UInt(8.W))) 101 | val sbufferMask = Input(UInt(64.W)) 102 | } 103 | 104 | class DiffStoreEventIO extends DifftestBundle with DifftestWithIndex { 105 | val valid = Input(Bool()) 106 | val storeAddr = Input(UInt(64.W)) 107 | val storeData = Input(UInt(64.W)) 108 | val storeMask = Input(UInt(8.W)) 109 | } 110 | 111 | class DiffLoadEventIO extends DifftestBundle with DifftestWithIndex { 112 | val valid = Input(Bool()) 113 | val paddr = Input(UInt(64.W)) 114 | val opType = Input(UInt(8.W)) 115 | val fuType = Input(UInt(8.W)) 116 | } 117 | 118 | class DiffAtomicEventIO extends DifftestBundle { 119 | val atomicResp = Input(Bool()) 120 | val atomicAddr = Input(UInt(64.W)) 121 | val atomicData = Input(UInt(64.W)) 122 | val atomicMask = Input(UInt(8.W)) 123 | val atomicFuop = Input(UInt(8.W)) 124 | val atomicOut = Input(UInt(64.W)) 125 | } 126 | 127 | class DiffPtwEventIO extends DifftestBundle { 128 | val ptwResp = Input(Bool()) 129 | val ptwAddr = Input(UInt(64.W)) 130 | val ptwData = Input(Vec(4, UInt(64.W))) 131 | } 132 | 133 | class DiffRefillEventIO extends DifftestBundle { 134 | val valid = Input(Bool()) 135 | val addr = Input(UInt(64.W)) 136 | val data = Input(Vec(8, UInt(64.W))) 137 | } 138 | 139 | class DifftestArchEvent extends BlackBox { 140 | val io = IO(new DiffArchEventIO) 141 | } 142 | 143 | class DifftestInstrCommit extends BlackBox { 144 | val io = IO(new DiffInstrCommitIO) 145 | } 146 | 147 | class DifftestTrapEvent extends BlackBox { 148 | val io = IO(new DiffTrapEventIO) 149 | } 150 | 151 | class DifftestCSRState extends BlackBox { 152 | val io = IO(new DiffCSRStateIO) 153 | } 154 | 155 | class DifftestArchIntRegState extends BlackBox { 156 | val io = IO(new DiffArchIntRegStateIO) 157 | } 158 | 159 | class DifftestArchFpRegState extends BlackBox { 160 | val io = IO(new DiffArchFpRegStateIO) 161 | } 162 | 163 | class DifftestSbufferEvent extends BlackBox { 164 | val io = IO(new DiffSbufferEventIO) 165 | } 166 | 167 | class DifftestStoreEvent extends BlackBox { 168 | val io = IO(new DiffStoreEventIO) 169 | } 170 | 171 | class DifftestLoadEvent extends BlackBox { 172 | val io = IO(new DiffLoadEventIO) 173 | } 174 | 175 | class DifftestAtomicEvent extends BlackBox { 176 | val io = IO(new DiffAtomicEventIO) 177 | } 178 | 179 | class DifftestPtwEvent extends BlackBox { 180 | val io = IO(new DiffPtwEventIO) 181 | } 182 | 183 | class DifftestRefillEvent extends BlackBox { 184 | val io = IO(new DiffRefillEventIO) 185 | } 186 | 187 | // Difftest emulator top 188 | 189 | // XiangShan log / perf ctrl, should be inited in SimTop IO 190 | // If not needed, just ingore these signals 191 | class PerfInfoIO extends Bundle { 192 | val clean = Input(Bool()) 193 | val dump = Input(Bool()) 194 | } 195 | 196 | class LogCtrlIO extends Bundle { 197 | val log_begin, log_end = Input(UInt(64.W)) 198 | val log_level = Input(UInt(64.W)) // a cpp uint 199 | } 200 | 201 | // UART IO, if needed, should be inited in SimTop IO 202 | // If not needed, just hardwire all output to 0 203 | class UARTIO extends Bundle { 204 | val out = new Bundle { 205 | val valid = Output(Bool()) 206 | val ch = Output(UInt(8.W)) 207 | } 208 | val in = new Bundle { 209 | val valid = Output(Bool()) 210 | val ch = Input(UInt(8.W)) 211 | } 212 | } 213 | 214 | package object difftest {} 215 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | this is used to test the rtl code. -------------------------------------------------------------------------------- /tests/compile_rtl.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import filecmp 3 | import subprocess 4 | import sys 5 | import os 6 | 7 | 8 | # 主函数 9 | def main(): 10 | rtl_dir = r'../../' 11 | tb_file = r'/tb/tinyriscv_soc_tb.v' 12 | # iverilog程序 13 | iverilog_cmd = ['iverilog'] 14 | # 顶层模块 15 | # iverilog_cmd += ['-s', r'tinyriscv_soc_tb'] 16 | # 编译生成文件 17 | iverilog_cmd += ['-o', r'out.vvp'] 18 | # 头文件(defines.v)路径 19 | iverilog_cmd += ['-I', rtl_dir + r'/rtl/tc_l1/core'] 20 | # 宏定义,仿真输出文件 21 | iverilog_cmd += ['-D', r'OUTPUT="signature.output"'] 22 | # testbench文件 23 | iverilog_cmd.append(rtl_dir + tb_file) 24 | # ../rtl/tc_l1/core 25 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/clint.v') 26 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/csr_reg.v') 27 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/ctrl.v') 28 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/defines.v') 29 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/div.v') 30 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/ex.v') 31 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/ex_mem.v') 32 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/mem.v') 33 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/mem_wb.v') 34 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/wb.v') 35 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/id.v') 36 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/id_ex.v') 37 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/if_id.v') 38 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/pc_reg.v') 39 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/regs.v') 40 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/rib.v') 41 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/core/tinyriscv.v') 42 | # ../rtl/tc_l1/comp 43 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/comp/ram.v') 44 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/comp/rom.v') 45 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/comp/timer.v') 46 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/comp/uart.v') 47 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/comp/gpio.v') 48 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/comp/spi.v') 49 | # ../rtl/tc_l1/debug 50 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/debug/jtag_dm.v') 51 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/debug/jtag_driver.v') 52 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/debug/jtag_top.v') 53 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/debug/uart_debug.v') 54 | # ../rtl/tc_l1/soc 55 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/soc/tinyriscv_soc_top.v') 56 | # ../rtl/tc_l1/utils 57 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/utils/full_handshake_rx.v') 58 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/utils/full_handshake_tx.v') 59 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/utils/gen_buf.v') 60 | iverilog_cmd.append(rtl_dir + r'/rtl/tc_l1/utils/gen_dff.v') 61 | 62 | # 编译 63 | process = subprocess.Popen(iverilog_cmd) 64 | process.wait(timeout=5) 65 | 66 | 67 | if __name__ == '__main__': 68 | sys.exit(main()) 69 | -------------------------------------------------------------------------------- /tests/compliance_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import filecmp 3 | import subprocess 4 | import sys 5 | import os 6 | 7 | 8 | # 找出path目录下的所有reference_output文件 9 | def list_ref_files(path): 10 | files = [] 11 | list_dir = os.walk(path) 12 | for maindir, subdir, all_file in list_dir: 13 | for filename in all_file: 14 | apath = os.path.join(maindir, filename) 15 | if apath.endswith('.reference_output'): 16 | files.append(apath) 17 | # print(files) 18 | return files 19 | 20 | # 根据bin文件找到对应的reference_output文件 21 | def get_reference_file(bin_file): 22 | file_path, file_name = os.path.split(bin_file) 23 | tmp = file_name.split('.') 24 | # 得到bin文件的前缀部分 25 | prefix = tmp[0] 26 | #print('bin prefix: %s' % prefix) 27 | 28 | files = [] 29 | if (bin_file.find('rv32im') != -1): 30 | files = list_ref_files(r'../riscv-compliance/riscv-test-suite/rv32im/references') 31 | elif (bin_file.find('rv32i') != -1): 32 | files = list_ref_files(r'../riscv-compliance/riscv-test-suite/rv32i/references') 33 | elif (bin_file.find('rv32Zicsr') != -1): 34 | files = list_ref_files(r'../riscv-compliance/riscv-test-suite/rv32Zicsr/references') 35 | elif (bin_file.find('rv32Zifencei') != -1): 36 | files = list_ref_files(r'../riscv-compliance/riscv-test-suite/rv32Zifencei/references') 37 | else: 38 | return None 39 | 40 | # 根据bin文件前缀找到对应的reference_output文件 41 | for file in files: 42 | if (file.find(prefix) != -1): 43 | return file, prefix 44 | 45 | return None, prefix 46 | 47 | # 主函数 48 | def main(): 49 | # print(sys.argv[0] + ' ' + sys.argv[1]) 50 | 51 | build_dir = os.getcwd() + '/build' 52 | # print(build_dir) 53 | # 判断是否已经存在该目录 54 | if not os.path.exists(build_dir): 55 | # 目录不存在,进行创建操作 56 | os.makedirs(build_dir) #使用os.makedirs()方法创建多层目录 57 | 58 | # 0. 59 | os.chdir('./build') 60 | # print(os.getcwd()) 61 | 62 | # 1.将bin文件转成mem文件 63 | cmd = r'python ../../tools/bin2mem.py' + r' ../' + sys.argv[1] + ' inst.data' 64 | # print(cmd) 65 | f = os.popen(cmd) 66 | f.close() 67 | 68 | # 2.编译rtl文件 69 | cmd = r'python ../compile_rtl.py' 70 | f = os.popen(cmd) 71 | f.close() 72 | 73 | # 3.运行 74 | logfile = open('run.log', 'w') 75 | vvp_cmd = [r'vvp'] 76 | vvp_cmd.append(r'out.vvp') 77 | process = subprocess.Popen(vvp_cmd, stdout=logfile, stderr=logfile) 78 | process.wait(timeout=5) 79 | logfile.close() 80 | 81 | # 4.比较结果 82 | ref_file, ref_file_prefix = get_reference_file(sys.argv[1]) 83 | print('[ISA COMPLIANCE TEST]--->[', ref_file_prefix, ']') 84 | print('START...') 85 | 86 | if (ref_file != None): 87 | # 如果文件大小不一致,直接报fail 88 | if (os.path.getsize('signature.output') != os.path.getsize(ref_file)): 89 | print('!!! FAIL, size != !!!') 90 | return 91 | f1 = open('signature.output') 92 | f2 = open(ref_file) 93 | f1_lines = f1.readlines() 94 | i = 0 95 | # 逐行比较 96 | for line in f2.readlines(): 97 | # 只要有一行内容不一样就报fail 98 | if (f1_lines[i] != line): 99 | print('!!! FAIL, content != !!!') 100 | f1.close() 101 | f2.close() 102 | return 103 | i = i + 1 104 | f1.close() 105 | f2.close() 106 | print('### PASS! ###') 107 | else: 108 | print('No ref file found, please check result by yourself.') 109 | 110 | if __name__ == '__main__': 111 | sys.exit(main()) 112 | -------------------------------------------------------------------------------- /tests/run_all_isa_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import filecmp 3 | import subprocess 4 | import sys 5 | import os 6 | 7 | 8 | # 找出path目录下的所有bin文件 9 | def list_binfiles(path): 10 | files = [] 11 | list_dir = os.walk(path) 12 | for maindir, subdir, all_file in list_dir: 13 | for filename in all_file: 14 | apath = os.path.join(maindir, filename) 15 | if apath.endswith('.bin'): 16 | files.append(apath) 17 | 18 | # print(maindir) 19 | # print(all_file) 20 | return files 21 | 22 | # 主函数 23 | def main(): 24 | bin_files = list_binfiles(r'./riscv-compliance/build_generated/rv32i') 25 | bin_files += list_binfiles(r'./riscv-compliance/build_generated/rv32im') 26 | # print(bin_files) 27 | 28 | # 对每一个bin文件进行测试 29 | pass_cnt = 0 30 | fail_cnt = 0 31 | fail_info = [] 32 | for file in bin_files: 33 | # print(file) 34 | cmd = r'python compliance_test.py ' + ' ' + file 35 | f = os.popen(cmd) 36 | r = f.read() 37 | f.close() 38 | # print(r) 39 | if (r.find('PASS') != -1): 40 | print(file + ' [PASS]') 41 | pass_cnt = pass_cnt + 1 42 | 43 | else: 44 | print(file + ' [FAIL]') 45 | fail_cnt = fail_cnt + 1 46 | fail_info.append(file) 47 | 48 | print('######', 'PASS(%d), FAIL(%d)' % (pass_cnt, fail_cnt), '######', sep=' ') 49 | print('Fail File Name:') 50 | for val in fail_info: 51 | print(val); 52 | 53 | if __name__ == '__main__': 54 | sys.exit(main()) -------------------------------------------------------------------------------- /tools/bin2mem.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | 5 | def bin2mem(infile, outfile): 6 | binfile = open(infile, 'rb') 7 | binfile_content = binfile.read(os.path.getsize(infile)) 8 | datafile = open(outfile, 'w') 9 | 10 | index = 0 11 | b0 = 0 12 | b1 = 0 13 | b2 = 0 14 | b3 = 0 15 | 16 | for b in binfile_content: 17 | if index == 0: 18 | b0 = b 19 | index = index + 1 20 | elif index == 1: 21 | b1 = b 22 | index = index + 1 23 | elif index == 2: 24 | b2 = b 25 | index = index + 1 26 | elif index == 3: 27 | b3 = b 28 | index = 0 29 | array = [] 30 | array.append(b3) 31 | array.append(b2) 32 | array.append(b1) 33 | array.append(b0) 34 | datafile.write(bytearray(array).hex() + '\n') 35 | 36 | binfile.close() 37 | datafile.close() 38 | 39 | 40 | if __name__ == '__main__': 41 | if len(sys.argv) == 3: 42 | bin2mem(sys.argv[1], sys.argv[2]) 43 | else: 44 | print('Usage: %s binfile datafile' % sys.argv[0], sys.argv[1], sys.argv[2]) 45 | -------------------------------------------------------------------------------- /tools/bin2mif.py: -------------------------------------------------------------------------------- 1 | import binascii 2 | import sys 3 | import os 4 | 5 | try: 6 | ram_size = 8192 7 | 8 | filePath0 = sys.argv[1] 9 | filePath2 = sys.argv[2] 10 | 11 | file0 = open(filePath0,'rb') 12 | file2 = open(filePath2,'w') 13 | 14 | inst_len = os.path.getsize(filePath0) 15 | 16 | file2.write('DEPTH = {0};\n'.format(ram_size)) 17 | file2.write('WIDTH = {0};\n'.format(32)) 18 | file2.write('\n') 19 | file2.write('ADDRESS_RADIX = HEX;\n') 20 | file2.write('DATA_RADIX = HEX;\n') 21 | file2.write('\n') 22 | file2.write('CONTENT BEGIN\n') 23 | 24 | line_num = 0 25 | for i in range(inst_len >> 2): 26 | temp = file0.read(4) 27 | temp = binascii.b2a_hex(temp[::-1]) 28 | temp = temp.decode() 29 | temp = str(temp).upper() 30 | 31 | file2.write('\t%04x: %s;\n' % (line_num, temp)) 32 | line_num = line_num + 1 33 | 34 | inst_tail_len = inst_len % 4; 35 | 36 | if(inst_tail_len): 37 | temp = file0.read(inst_tail_len) 38 | temp = binascii.b2a_hex(temp[::-1]) 39 | temp = temp.decode() 40 | temp = str(temp).upper() 41 | temp = (4 - inst_tail_len) * '00' + temp; 42 | 43 | file2.write('\t%04x: %s;\n' % (line_num, temp)) 44 | line_num = line_num + 1 45 | 46 | inst_word_len = (inst_len >> 2) + 1; 47 | else: 48 | inst_word_len = (inst_len >> 2); 49 | 50 | file2.write('\t%04x: %s;\n' % (line_num, temp)) 51 | line_num = line_num + 1 52 | 53 | file2.write('\n') 54 | file2.write('END;') 55 | 56 | file0.close() 57 | file2.close() 58 | 59 | except: 60 | print("Unexpected error:", sys.exc_info()) 61 | print(filePath2) 62 | -------------------------------------------------------------------------------- /tools/env/hello_world_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI 3 | [*] Mon Jan 25 14:34:16 2021 4 | [*] 5 | [dumpfile] "/home/myyerrol/Workspaces/tree_core_cpu/env/hello_world_tb.vcd" 6 | [dumpfile_mtime] "Mon Jan 25 14:34:07 2021" 7 | [dumpfile_size] 639 8 | [savefile] "/home/myyerrol/Workspaces/tree_core_cpu/env/hello_world_tb.gtkw" 9 | [timestart] 0 10 | [size] 1839 1050 11 | [pos] -1 -1 12 | *-15.000000 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [sst_width] 252 14 | [signals_width] 235 15 | [sst_expanded] 1 16 | [sst_vpaned_height] 319 17 | @28 18 | hello_world_tb.clk 19 | hello_world_tb.rst_n 20 | [pattern_trace] 1 21 | [pattern_trace] 0 22 | -------------------------------------------------------------------------------- /tools/env/hello_world_tb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 设置测试与波形文件的路径 4 | # Set the path of test and wavefrom file 5 | TEST_MODULE="hello_world_tb" 6 | TEST_FILE="./${TEST_MODULE}.v" 7 | GTKW_FILE="./${TEST_MODULE}.gtkw" 8 | 9 | # 判断iverilog是否安装 10 | # Judge whether iverilog is installed 11 | if command -v iverilog > /dev/null 2>&1; then 12 | # 判断gtkwave是否安装 13 | # Judge whether gtkwave is installed 14 | if command -v gtkwave > /dev/null 2>&1; then 15 | # 生成vvp仿真文件 16 | # Generate vvp simulation file 17 | iverilog -o "${TEST_MODULE}.vvp" ${TEST_FILE} 18 | # 执行vvp仿真文件 19 | # Execute vvp simulation file 20 | vvp "${TEST_MODULE}.vvp" 21 | # 判断波形文件是否存在 22 | # Judge whether the wavefrom file exists. 23 | if [ -f ${GTKW_FILE} ]; then 24 | # 如果存在则直接加载波形文件执行 25 | # If it exists, directly load the wavefrom file to execute 26 | gtkwave ${GTKW_FILE} 27 | else 28 | # 如果不存在则加载vcd文件后执行 29 | # If it doesn't exist, load the vcd file and execute 30 | gtkwave "${TEST_MODULE}.vcd" 31 | fi 32 | else 33 | echo "gtkwave has not been installed!" 34 | fi 35 | else 36 | echo "iverilog has not been installed!" 37 | fi 38 | -------------------------------------------------------------------------------- /tools/env/hello_world_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module hello_world_tb; 4 | // 设置时钟周期为10ns 5 | // Set the clock cycle to 10ns 6 | parameter CYCLE = 10; 7 | 8 | reg clk; 9 | reg rst_n; 10 | 11 | // 每半个时钟周期变更一次时钟信号的高低状态 12 | always #(CYCLE / 2) clk = ~clk; 13 | 14 | initial 15 | begin 16 | // 生成vcd文件以供波形仿真使用 17 | // Generate vcd file for waveform simulation 18 | $dumpfile("hello_world_tb.vcd"); 19 | // 将模块的信号都添加到vcd文件中 20 | // Add the module's signals to the vcd file 21 | $dumpvars(0, hello_world_tb); 22 | // 在仿真过程中打印相应的字符串 23 | // Print the string in the simulation process 24 | $display("Hello World!"); 25 | clk = 0; 26 | rst_n = 0; 27 | // 延迟10个时钟周期 28 | // Delay 10 clock cycles 29 | repeat(10) @(posedge clk); 30 | rst_n = 1; 31 | // 延迟10个时钟周期 32 | // Delay 10 clock cycles 33 | repeat(10) @(posedge clk); 34 | $finish; 35 | end 36 | 37 | endmodule 38 | --------------------------------------------------------------------------------