├── .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 |
3 |
TreeCore CPU: A Series of RISCV Processors Written from Scratch
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
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 |
--------------------------------------------------------------------------------