Compare commits
189 Commits
Author | SHA1 | Date |
---|---|---|
liangkangnan | 280a548e62 | |
liangkangnan | 6942faa82d | |
liangkangnan | 5745f0140d | |
liangkangnan | 47b744a7ec | |
liangkangnan | d65cdee729 | |
liangkangnan | 574474acc8 | |
liangkangnan | e379fdd445 | |
liangkangnan | 5dd0fa4034 | |
liangkangnan | b61fd21057 | |
liangkangnan | 6d37b9fc9c | |
liangkangnan | ad3dbd1a51 | |
liangkangnan | 6c6f6cf7af | |
liangkangnan | da19d3ebe5 | |
liangkangnan | 3eaa4cdc97 | |
liangkangnan | f704e47e4a | |
liangkangnan | 6aa5f18429 | |
liangkangnan | 9aba174156 | |
liangkangnan | b3cfa2dfa6 | |
liangkangnan | 1b296983eb | |
liangkangnan | 09c0b531b0 | |
liangkangnan | d6a14415c9 | |
liangkangnan | 7993b97612 | |
liangkangnan | 8bfee71fd0 | |
liangkangnan | 36380133f4 | |
liangkangnan | 769f93c70a | |
liangkangnan | 384320c7b1 | |
liangkangnan | ccadad262f | |
liangkangnan | 26a221a132 | |
liangkangnan | 22407f4b1f | |
liangkangnan | ed2644b66e | |
liangkangnan | 53ae450762 | |
liangkangnan | a27d949a5d | |
liangkangnan | 490c52054b | |
liangkangnan | 4c16dfb254 | |
liangkangnan | 4958cb66c2 | |
liangkangnan | 504f836de5 | |
liangkangnan | 3666009efc | |
liangkangnan | 5b7b657384 | |
liangkangnan | 92e89292b1 | |
liangkangnan | bed8ed965e | |
liangkangnan | 3120110be3 | |
liangkangnan | d67f1abab3 | |
liangkangnan | 4720d020e4 | |
liangkangnan | cfc170f896 | |
liangkangnan | 27dc2ed0c1 | |
liangkangnan | 8f4c2cb7fe | |
liangkangnan | e097662c62 | |
liangkangnan | ecd4ecafc6 | |
liangkangnan | 15928977e1 | |
liangkangnan | 274b19363b | |
liangkangnan | 1e510dab9d | |
liangkangnan | d8a7a67787 | |
liangkangnan | 90d9349128 | |
liangkangnan | 448f733f22 | |
liangkangnan | b6d3b39f4d | |
liangkangnan | 04d4dd8dfa | |
liangkangnan | 0667139d7e | |
liangkangnan | 2d9aab4ecb | |
liangkangnan | 9a8637be12 | |
liangkangnan | 22e6866dea | |
liangkangnan | 75de08cfc8 | |
liangkangnan | 718e16a46d | |
liangkangnan | 3903d9e7f4 | |
liangkangnan | d40f39a091 | |
liangkangnan | 3b7fa13a73 | |
liangkangnan | 22a038cc09 | |
liangkangnan | 519ef32ae7 | |
liangkangnan | 55f37e93fa | |
liangkangnan | 4086a2d863 | |
liangkangnan | 4d0f63ef86 | |
liangkangnan | 57690b00bd | |
liangkangnan | f74f2d8f5d | |
liangkangnan | 574708bd89 | |
liangkangnan | ae3ff5a211 | |
liangkangnan | f7231a2f15 | |
liangkangnan | 2c11873056 | |
liangkangnan | e708eb6d4d | |
liangkangnan | 7e57d8db17 | |
liangkangnan | 9905a7c3a2 | |
liangkangnan | 08492931fc | |
liangkangnan | 92e1e5a77a | |
liangkangnan | facd5d31f4 | |
liangkangnan | 3f400f2fb8 | |
liangkangnan | 1218a1ef4b | |
liangkangnan | 4ac826a398 | |
liangkangnan | cd9e219d1b | |
liangkangnan | 2afcba47ea | |
liangkangnan | 6143d9ee6a | |
liangkangnan | 12467d1554 | |
liangkangnan | d4b670217a | |
liangkangnan | 477d9efc34 | |
liangkangnan | fdd953c0f0 | |
liangkangnan | 5fa659a084 | |
liangkangnan | 9387f56a33 | |
liangkangnan | aaa5684cc9 | |
liangkangnan | 0437ff99da | |
liangkangnan | 79f83c1ad4 | |
liangkangnan | ad5adcb843 | |
liangkangnan | c4fe45ffaf | |
liangkangnan | 64041b4d2b | |
liangkangnan | f6c8a046c7 | |
liangkangnan | c178a8fbb2 | |
liangkangnan | 72b982d133 | |
liangkangnan | 58f180a92f | |
liangkangnan | cba47c1f64 | |
liangkangnan | 9e7653a96a | |
liangkangnan | 3227fb1ffd | |
liangkangnan | e9044a7efe | |
liangkangnan | 5ebb41c477 | |
liangkangnan | 8f3aa6bb2c | |
liangkangnan | ac245a5d6c | |
liangkangnan | 18de7f2e00 | |
liangkangnan | fd2c981317 | |
liangkangnan | 53e4263706 | |
liangkangnan | 34218536c1 | |
liangkangnan | 3269041c0b | |
liangkangnan | 2db9e7dbb9 | |
liangkangnan | 96d6976c44 | |
liangkangnan | 5f56e8d0fb | |
liangkangnan | 4e99bd4f33 | |
liangkangnan | 7196d33074 | |
liangkangnan | e26dda807e | |
liangkangnan | f9f78976fb | |
liangkangnan | 6121a21322 | |
liangkangnan | 4436e0cc6a | |
liangkangnan | b7b8572542 | |
liangkangnan | d9a1f89fd2 | |
liangkangnan | 6059c4c3a7 | |
liangkangnan | c847244c5b | |
liangkangnan | 646bc96419 | |
liangkangnan | 6d8015727e | |
liangkangnan | 247a5b6354 | |
liangkangnan | cd9ac0adae | |
liangkangnan | fb461a6176 | |
liangkangnan | c6163aaff1 | |
liangkangnan | fd5413791d | |
liangkangnan | 87849fbd35 | |
liangkangnan | 5353371516 | |
liangkangnan | bffeebd0bf | |
liangkangnan | b98e1c5538 | |
liangkangnan | af63e677d9 | |
liangkangnan | 01c3159a83 | |
liangkangnan | a67fba652d | |
liangkangnan | 5efa66ee64 | |
liangkangnan | c7a374acb8 | |
liangkangnan | f08fd1b17e | |
liangkangnan | 6cd6532423 | |
liangkangnan | 136dc45a09 | |
liangkangnan | 536d28ede3 | |
liangkangnan | b0f4592322 | |
liangkangnan | 6e466fbbf7 | |
liangkangnan | 5811bdde13 | |
liangkangnan | b02b38bddc | |
liangkangnan | 36147d9391 | |
liangkangnan | 4a4c08bc69 | |
liangkangnan | 10d8d35a13 | |
liangkangnan | 738fba1d6f | |
liangkangnan | 53865371ce | |
liangkangnan | dfa8bf490e | |
liangkangnan | f9412fca3c | |
liangkangnan | 77812d60df | |
liangkangnan | 4da79b6046 | |
liangkangnan | 65a26842c4 | |
liangkangnan | ec65381ba9 | |
liangkangnan | 462cc4c786 | |
liangkangnan | 05e2441d24 | |
liangkangnan | 9ac1b31965 | |
liangkangnan | 7803e89d68 | |
liangkangnan | e53f681063 | |
liangkangnan | bd2d372c66 | |
liangkangnan | 16fa475ba7 | |
liangkangnan | ad775ef316 | |
liangkangnan | f1f09584ee | |
liangkangnan | e3667e0ddd | |
liangkangnan | 9943d02600 | |
liangkangnan | c070f0b49d | |
liangkangnan | 9322b595bc | |
Blue Liang | e2c07ec19b | |
Blue Liang | b4b54d831b | |
liangkangnan | f23b545499 | |
Blue Liang | 8214134b89 | |
liangkangnan | 5c87fc09ef | |
liangkangnan | fdc776ab5e | |
liangkangnan | f03f42fc9b | |
liangkangnan | ceddc1af24 | |
liangkangnan | 5c9f1a140e | |
Blue Liang | 60a4f7d6df | |
liangkangnan | eb5647915a | |
liangkangnan | 2b44f1e8f3 |
|
@ -2,5 +2,5 @@
|
||||||
*.o
|
*.o
|
||||||
*.ko
|
*.ko
|
||||||
*.obj
|
*.obj
|
||||||
|
*.bin
|
||||||
tools/gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64
|
*.dump
|
||||||
|
|
232
README.md
|
@ -1,203 +1,143 @@
|
||||||
与本项目配套的设计文档[《从零开始写RISC-V处理器》](https://liangkangnan.gitee.io/2020/04/29/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E5%86%99RISC-V%E5%A4%84%E7%90%86%E5%99%A8/),目前已经更新完第三章硬件篇,开始更新软件篇。
|
# 1.概述
|
||||||
|
|
||||||
# 1.初衷
|
本分支是在bram分支的基础上进行改进的。
|
||||||
|
|
||||||
本开源项目的初衷是本人想入门RISC-V,熟悉RISC-V的指令内容和汇编语法。
|
改进的地方主要有:
|
||||||
|
|
||||||
本人对RISC-V很感兴趣,很看好RISC-V的发展前景,觉得RISC-V就是CPU中的Linux。由于RISC-V是这两年才开始迅速发展的,因此关于RISC-V的学习参考资料目前还很少,特别是适合入门的资料,因此学习起来进度很缓慢,于是萌生了自己从零开始写RISC-V处理器核的想法。
|
1. 开发环境切换到Linux(Ubuntu18.04)系统下;
|
||||||
|
2. 仿真器使用verilator;
|
||||||
|
3. 内部总线使用OBI总线(详细内容见doc/OBI-v1.0.pdf文档);
|
||||||
|
4. 增加指令trace功能;
|
||||||
|
6. JTAG模块全面改进和优化,支持3个硬件断点,单步等功能,支持gdb调试;
|
||||||
|
7. 增加静态分支预测功能;
|
||||||
|
|
||||||
本人是一名FPGA小白,为了快速入门、深入掌握RISC-V,我开始了学习FPGA和verilog的"艰难"历程。我工作的内容是和嵌入式软件相关的,平时根本不会接触到FPGA,也不会用到RISC-V,因此只能用业余时间来学习RISC-V。
|
# 2.使用方法
|
||||||
|
|
||||||
网上有不少关于RISC-V的开源项目,但是大多都写得很"高深",对于我这种小白来说学习起来是非常吃力的,不太适合入门。本项目目前的代码量非常少,是很简单易懂的,对于想入门RISC-V的同学来说是一个很好的参考,希望能够吸引更多的同学参与到RISC-V的学习中来,促进RISC-V的发展,如果能起到抛砖引玉的作用的话那就更好了,也许说是砖的话就有点夸大了,但哪怕是起到一颗沙子的作用,也就足矣。
|
## 2.1安装gcc工具链
|
||||||
|
|
||||||
# 2.介绍
|
下载gcc工具链([百度云链接](https://pan.baidu.com/s/1iRiZoPnt9M1upXsUkvLEfA),提取码:yaib),使用下面的命令解压到/opt/riscv32目录下:
|
||||||
|
|
||||||
本项目实现的是一个单核32位的小型RISC-V处理器核(tinyriscv),采用verilog语言编写。设计目标是对标ARM Cortex-M3系列处理器。tinyriscv有以下特点:
|
```
|
||||||
|
sudo tar zxf tinyriscv-gcc-toolchain.tar.gz -C /
|
||||||
|
```
|
||||||
|
|
||||||
1. 支持RV32IM指令集,通过RISC-V指令兼容性测试;
|
## 2.2下载代码
|
||||||
3. 采用三级流水线,即取指,译码,执行;
|
|
||||||
4. 可以运行C语言程序;
|
|
||||||
5. 支持JTAG,可以通过openocd读写内存(在线更新程序);
|
|
||||||
6. 支持中断;
|
|
||||||
6. 支持总线;
|
|
||||||
7. 支持FreeRTOS;
|
|
||||||
8. 支持通过串口更新程序;
|
|
||||||
9. 容易移植到任何FPGA平台(如果资源足够的话);
|
|
||||||
|
|
||||||
项目中的各目录说明:
|
下载本项目verilator分支的代码:
|
||||||
|
|
||||||
**rtl**:该目录包含tinyriscv的所有verilog源码;
|
```
|
||||||
|
git clone -b verilator https://gitee.com/liangkangnan/tinyriscv.git
|
||||||
|
```
|
||||||
|
|
||||||
**sim**:该目录包含仿真批处理bat文件和脚本;
|
## 2.3运行仿真
|
||||||
|
|
||||||
**tests**:该目录包含测试程序源码,其中example目录为C语言程序例程源码,isa目录为RV32指令测试源码;
|
打开终端,进入到sim目录下,执行以下的命令编译:
|
||||||
|
|
||||||
**tools**:该目录包含编译汇编和C语言程序所需GNU工具链和将二进制文件转成仿真所需的mem格式文件的工具BinToMem,还有通过串口下载程序的脚本。BinToMem\_CLI.exe需要在cmd窗口下执行,BinToMem\_GUI.exe提供图形界面,双击即可运行;
|
```
|
||||||
|
make recompile
|
||||||
|
```
|
||||||
|
|
||||||
**pic**:存放图片;
|
这个命令会重新编译整个rtl源码和sdk/examples/simple这个C语言例程。如果需要使用其他例程,可以用PROG参数指定,比如:
|
||||||
|
|
||||||
**tb**:该目录包含仿真的testbench文件;
|
```
|
||||||
|
make PROG=/path/sdk/examples/hello_world/hello_world.mem recompile
|
||||||
|
```
|
||||||
|
|
||||||
**fpga**:存放FPGA相关文件,比如约束文件;
|
执行以下命令运行仿真:
|
||||||
|
|
||||||
tinyriscv的整体框架如下:
|
```
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
|
||||||
![tinyriscv整体框架](./pic/arch.jpg)
|
![make_run](./pic/make_run.png)
|
||||||
|
|
||||||
tinyriscv目前外挂了6个外设,每个外设的空间大小为256MB,地址空间分配如下图所示:
|
打开另一个终端,进入到tools/openocd目录下,运行openocd:
|
||||||
|
|
||||||
<img src="./pic/addr_alloc.jpg" alt="地址空间分配" style="zoom:70%;" />
|
```
|
||||||
|
./openocd_linux -f ../../sim/remote_bitbang.cfg
|
||||||
|
```
|
||||||
|
|
||||||
# 3.CoreMark测试
|
![openocd](./pic/openocd.png)
|
||||||
|
|
||||||
目前tinyriscv在Xilinx Artix-7 35T FPGA平台(时钟50MHz)上运行CoreMark跑分程序的结果如下图所示:
|
可以看到openocd已经连上了,可以使用telnet或者gdb进行调试了。
|
||||||
|
|
||||||
![tinyriscv跑分](./pic/tinyriscv_coremark.png)
|
### 2.3.1使用telnet进行调试
|
||||||
|
|
||||||
可知,tinyriscv的跑分成绩为2.4。此成绩是基于指令在rom存储和数据在ram存储的情况下得出的,如果指令和数据都在ram的话跑分上3.0问题应该不大。
|
再打开另一个终端,输入以下命令连接telnet:
|
||||||
|
|
||||||
选了几款其他MCU的跑分结果如下图所示:
|
```
|
||||||
|
telnet localhost 4444
|
||||||
|
```
|
||||||
|
|
||||||
![其他MCU跑分结果](./pic/other_coremark.png)
|
![telnet](./pic/telnet.png)
|
||||||
|
|
||||||
更多MCU的跑分结果,可以到[coremark](https://www.eembc.org/coremark/scores.php)官网查询。
|
然后就可以使用各种命令进行调试了。下面介绍一些常用的命令:
|
||||||
|
|
||||||
# 4.如何使用
|
**halt**:停住MCU,进入调试模式;
|
||||||
|
|
||||||
本项目运行在windows平台,编译仿真工具使用的是iverilog和vpp,波形查看工具使用的是gtkwave。
|
**resume**:MCU从停住的地方继续执行,退出调试模式;
|
||||||
|
|
||||||
## 4.1安装环境
|
**reset**:复位MCU,复位之后就开始执行。通常在下载完程序后使用该命令来运行程序;
|
||||||
|
|
||||||
在使用之前需要安装以下工具:
|
**reset halt**:复位MCU,然后停住MCU,即MCU停在复位地址处;
|
||||||
|
|
||||||
1. 安装iverilog工具
|
**bp 0x00000010 4 hw**:打断点,其中0x00000010是断点的地址,4表示地址长度为4个字节,hw表示硬件断点。tinyriscv只支持硬件断点。
|
||||||
|
|
||||||
可以在这里[http://bleyer.org/icarus/](http://bleyer.org/icarus/)下载,安装过程中记得同意把iverilog添加到环境变量中,当然也可以在安装完成后手动进行添加。安装完成后iverilog、vvp和gtkwave等工具也就安装好了。
|
**rbp 0x00000010**:删除0x00000010地址处的断点;
|
||||||
|
|
||||||
2. 安装GNU工具链
|
**bp**:查看所有断点信息;
|
||||||
|
|
||||||
可以通过百度网盘下载(链接: https://pan.baidu.com/s/1bYgslKxHMjtiZtIPsB2caQ 提取码: 9n3c),或者通过微云下载[https://share.weiyun.com/5bMOsu9](https://share.weiyun.com/5bMOsu9),下载完成后将压缩包解压到本项目的tools目录下。注意目录的层次结构,解压后的工具路径应该如下所示:
|
**step**:单步执行,每次执行一条指令;
|
||||||
|
|
||||||
`tinyriscv\tools\gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64\bin\riscv-none-embed-gcc`
|
**mww 0x00000010 0x1234**:即memory write word,往0x00000010地址处写入0x1234,长度为4个字节;
|
||||||
|
|
||||||
3. 安装make工具
|
**mdw 0x00000010 2**:即memory display word,从0x00000010地址处读取2个word;
|
||||||
|
|
||||||
可以通过百度网盘下载(链接: https://pan.baidu.com/s/1nFaUIwv171PDXuF7TziDFg 提取码: 9ntc),或者通过微云下载[https://share.weiyun.com/59xtmWR](https://share.weiyun.com/59xtmWR),下载完成后直接解压,然后将make所在的路径添加到环境变量里。
|
**reg sp**:读取sp寄存器的值;
|
||||||
|
|
||||||
4. 安装python3
|
**reg sp 0x10**:往sp寄存器写入0x10;
|
||||||
|
|
||||||
到[python官网](https://www.python.org/)下载win版本的python,注意要下载python3版本的。网速慢的同学可以通过百度网盘下载(链接: https://pan.baidu.com/s/1gNC8L5dZTsN6E5TJD2rmnQ 提取码: 3b4t),或者通过微云下载[https://share.weiyun.com/XwzSQHND](https://share.weiyun.com/XwzSQHND)。安装完后将python添加到环境变量里。
|
**load_image**:加载image文件,比如:load_image filename address bin min_address max_length,其中filename表示要加载的文件,address表示要加载到哪个地址,bin表示文件的类型,min_address表示最小地址,该值与address相同即可,max_length表示文件的最大长度。目前使用这个命令来下载C语言程序。
|
||||||
|
|
||||||
5. 下载代码
|
**verify_image**:比如:verify_image filename offset,其中filename表示已经下载了的文件,offset表示从哪个地址开始校验。使用这个命令来校验下载进去的程序是否正确。
|
||||||
|
|
||||||
使用git clone命令下载,不要使用zip方式下载,否则有些文件会有格式问题。
|
**load_bin**:如果觉得load_image命令的参数比较多,可以使用load_bin命令,比如:load_bin bin_file 0x0 1,表示将bin_file二进制文件下载到0x0地址处,并且校验。
|
||||||
|
|
||||||
`git clone https://gitee.com/liangkangnan/tinyriscv.git`
|
### 2.3.2使用gdb进行调试
|
||||||
|
|
||||||
## 4.2运行指令测试程序
|
除了使用telnet进行调试之外,还可以使用gdb进行调试,这也是大部分IDE(eclipse等)所使用的调试方式。
|
||||||
|
|
||||||
### 4.2.1 运行旧的指令测试程序
|
openocd连上之后,打开另一个终端,执行以下命令运行gdb:
|
||||||
|
|
||||||
旧的指令测试程序属于比较早的指令兼容性测试方法,虽然目前RISC-V官方已经不更新了,但仍然是一个比较好的测试参考。
|
```
|
||||||
|
/opt/riscv32/bin/riscv32-unknown-elf-gdb ~/tinyriscv/sdk/examples/simple/simple
|
||||||
|
```
|
||||||
|
|
||||||
下面以add指令为例,说明如何运行旧的指令测试程序。
|
接着,设置一下超时时间:
|
||||||
|
|
||||||
打开CMD窗口,进入到sim目录,执行以下命令:
|
```
|
||||||
|
set remotetimeout 2000
|
||||||
|
```
|
||||||
|
|
||||||
```sim_new_nowave.bat ..\tests\isa\generated\rv32ui-p-add.bin inst.data```
|
连接openocd服务:
|
||||||
|
|
||||||
如果运行成功的话就可以看到"PASS"的打印。其他指令使用方法类似。
|
```
|
||||||
|
target remote localhost:3333
|
||||||
|
```
|
||||||
|
|
||||||
![](./pic/test_output.png)
|
加载程序:
|
||||||
|
|
||||||
也可以一次性对所有指令进行测试,方法如下。
|
```
|
||||||
|
load
|
||||||
|
```
|
||||||
|
|
||||||
打开CMD窗口进入到sim目录下,执行以下命令:
|
之后就可以用gdb命令来调试了,比如打印mul变量的值:
|
||||||
|
|
||||||
`python .\test_all_isa.py`
|
```
|
||||||
|
print mul
|
||||||
|
```
|
||||||
|
|
||||||
### 4.2.2运行新的指令测试程序
|
![gdb](./pic/gdb.png)
|
||||||
|
|
||||||
新的指令兼容性([riscv-compliance](https://github.com/riscv/riscv-compliance))测试项相对于旧的指令兼容性测试项来说对指令的测试更加严谨,可以精确到每一条指令的运行结果,而且RISC-V官方一直在更新。
|
注意,如果要用gdb进行调试,则编译C程序时必须加上-g参数。
|
||||||
|
|
||||||
下面以add指令为例,说明如何运行新的指令测试程序。
|
|
||||||
|
|
||||||
打开CMD窗口,进入到sim/compliance_test目录,执行以下命令:
|
|
||||||
|
|
||||||
`python compliance_test.py ..\..\tests\riscv-compliance\build_generated\rv32i\I-ADD-01.elf.bin inst.data`
|
|
||||||
|
|
||||||
如果运行成功的话就可以看到"PASS"的打印。其他指令使用方法类似。
|
|
||||||
|
|
||||||
![new_test_output](./pic/new_test_output.png)
|
|
||||||
|
|
||||||
## 4.3运行C语言程序
|
|
||||||
|
|
||||||
C语言程序例程位于tests\example目录里。
|
|
||||||
|
|
||||||
下面以simple程序为例进行说明。
|
|
||||||
|
|
||||||
首先打开CMD窗口,进入到tests\example\simple目录,执行以下命令清除旧的目标文件:
|
|
||||||
|
|
||||||
`make clean`
|
|
||||||
|
|
||||||
然后重新编译:
|
|
||||||
|
|
||||||
`make`
|
|
||||||
|
|
||||||
编译成功之后,进入到sim目录,执行以下命令开始测试:
|
|
||||||
|
|
||||||
` .\sim_new_nowave.bat ..\tests\example\simple\simple.bin inst.data`
|
|
||||||
|
|
||||||
# 5.移植到FPGA
|
|
||||||
|
|
||||||
详细的移植方法请查看本项目下的fpga目录中的README.md文件。
|
|
||||||
|
|
||||||
# 6.未来计划
|
|
||||||
|
|
||||||
1. 写设计文档;
|
|
||||||
2. 优化资源和功耗(主要是译码和执行部分);
|
|
||||||
3. 支持硬件中断嵌套和快速实时中断;
|
|
||||||
4. ......
|
|
||||||
|
|
||||||
# 7.更新记录
|
|
||||||
|
|
||||||
2020-07-04:支持通过UART烧写固件;
|
|
||||||
|
|
||||||
2020-05-27:增加新的指令兼容性(riscv-compliance)测试项。
|
|
||||||
|
|
||||||
2020-05-05:支持spi master,增加spi测试例程。
|
|
||||||
|
|
||||||
2020-04-25:支持FreeRTOS(v10.3.1)。
|
|
||||||
|
|
||||||
2020-04-18:适当添加代码注释;优化中断管理模块。
|
|
||||||
|
|
||||||
2020-04-11:增加CoreMark跑分例程和跑分成绩。
|
|
||||||
|
|
||||||
2020-04-05:支持CSR指令。
|
|
||||||
|
|
||||||
2020-03-29:重大更新,主要更新如下:
|
|
||||||
|
|
||||||
1. 支持RIB(RISC-V Internal Bus)总线;
|
|
||||||
2. 优化乘法代码,节省了2/3的DSP资源;
|
|
||||||
3. 优化除法代码,解决了除法模块的BUG;
|
|
||||||
4. 完善C语言例程、启动代码和链接脚本;
|
|
||||||
5. 增加一次性对所有指令进行测试的脚本;
|
|
||||||
|
|
||||||
2020-03-08:支持中断,为此增加了timer模块来验证。
|
|
||||||
|
|
||||||
2020-03-01:支持JTAG,配合openocd可进行内存读写。JTAG文档参考[深入浅出RISC-V调试](https://liangkangnan.gitee.io/2020/03/21/深入浅出RISC-V调试/)。
|
|
||||||
|
|
||||||
2020-02-23:支持在Xilinx Artix-7平台上运行。详见[tinyriscv_vivado](https://gitee.com/liangkangnan/tinyriscv_vivado)。
|
|
||||||
|
|
||||||
2020-01-13:支持RV32M的除法指令。其C语言实现详见[div](https://gitee.com/liangkangnan/div)。
|
|
||||||
|
|
||||||
2020-01-02:支持RV32M的乘法指令。
|
|
||||||
|
|
||||||
2019-12-06:第一次发布。
|
|
||||||
|
|
||||||
# 8.其他
|
|
||||||
|
|
||||||
如有疑问或者建议,欢迎在下方评论、或者私信、或者发邮件(liangkangnan@163.com)给我,24小时内必回复。
|
|
||||||
|
|
||||||
如果您热爱RISC-V或者对RISC-V感兴趣,欢迎发邮件或者私信我,我把您拉进群里面交流RISC-V相关的技术。
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# 1.概述
|
# 1.概述
|
||||||
|
|
||||||
介绍如何将tinyriscv移植到FPGA平台上和如何通过JTAG或者UART下载程序到FPGA。
|
介绍如何将tinyriscv移植到FPGA平台上和如何通过JTAG下载程序到FPGA。
|
||||||
|
|
||||||
1.软件:xilinx vivado(以2018.1版本为例)开发环境。
|
1.软件:xilinx vivado(以2018.1版本为例)开发环境。
|
||||||
|
|
||||||
2.FPGA:xilinx Artix-7 35T。
|
2.FPGA:xilinx Artix-7 35T。
|
||||||
|
|
||||||
3.调试器:CMSIS-DAP或者DAPLink。
|
3.调试器:CMSIS-DAP或者DAPLink(要带JTAG功能)。
|
||||||
|
|
||||||
这里只是以Xilinx平台为例,实际上可以移植到任何FPGA平台(只要资源足够)。
|
这里只是以Xilinx平台为例,实际上可以移植到任何FPGA平台(只要资源足够)。
|
||||||
|
|
||||||
|
@ -66,6 +66,8 @@
|
||||||
|
|
||||||
勾选上红色框里那两项,然后点击Finish按钮。
|
勾选上红色框里那两项,然后点击Finish按钮。
|
||||||
|
|
||||||
|
最后,还要添加顶层文件,即fpga/xilinx/perf-v/tinyriscv_soc_top.sv文件。
|
||||||
|
|
||||||
至此,RTL源文件添加完成。
|
至此,RTL源文件添加完成。
|
||||||
|
|
||||||
## 2.3添加约束文件
|
## 2.3添加约束文件
|
||||||
|
@ -82,7 +84,7 @@
|
||||||
|
|
||||||
![](./images/add_src_6.png)
|
![](./images/add_src_6.png)
|
||||||
|
|
||||||
点击Add Files按钮,选择tinyriscv项目里的FPGA/constrs/tinyriscv.xdc文件,如下图所示:
|
点击Add Files按钮,选择tinyriscv项目里的fpga/xilinx/perf-v/constrs/tinyriscv.xdc文件,如下图所示:
|
||||||
|
|
||||||
![](./images/add_src_7.png)
|
![](./images/add_src_7.png)
|
||||||
|
|
||||||
|
@ -156,9 +158,9 @@
|
||||||
|
|
||||||
打开一个CMD窗口,然后cd进入到tinyriscv项目的tools/openocd目录,执行命令:
|
打开一个CMD窗口,然后cd进入到tinyriscv项目的tools/openocd目录,执行命令:
|
||||||
|
|
||||||
`openocd.exe -f tinyriscv.cfg`
|
`openocd_win.exe -f tinyriscv_cmsisdap_jtag.cfg`
|
||||||
|
|
||||||
如果执行成功的话则会如下图所示:
|
如果执行成功的话则会如下图所示(由于项目一直在更新,图片上的信息可能会跟实际的不一致,以文字描述为准):
|
||||||
|
|
||||||
![openocd](./images/openocd.png)
|
![openocd](./images/openocd.png)
|
||||||
|
|
||||||
|
@ -166,55 +168,29 @@
|
||||||
|
|
||||||
`telnet localhost 4444`
|
`telnet localhost 4444`
|
||||||
|
|
||||||
然后在这个CMD窗口下使用load_image命令将固件下载到FPGA,这里以freertos.bin文件为例,如下所示:
|
然后在这个CMD窗口下使用load_bin命令将固件下载到FPGA的ROM里(掉电会消失),这里以freertos.bin文件为例,如下所示:
|
||||||
|
|
||||||
`load_image D:/gitee/open/tinyriscv/tests/example/FreeRTOS/Demo/tinyriscv_GCC/freertos.bin 0x0 bin 0x0 0x1000000`
|
`load_bin D:/gitee/open/tinyriscv/tests/example/FreeRTOS/Demo/tinyriscv_GCC/freertos.bin 0x0 1`
|
||||||
|
|
||||||
使用verify_image命令来校验是否下载成功,如下所示:
|
load_bin命令用法:
|
||||||
|
|
||||||
`verify_image D:/gitee/open/tinyriscv/tests/example/FreeRTOS/Demo/tinyriscv_GCC/freertos.bin 0x0`
|
`load_bin file address verify[0|1]`
|
||||||
|
|
||||||
如果下载出错的话会有提示的,没有提示则说明下载成功。
|
file:表示要下载的bin文件
|
||||||
|
|
||||||
|
address:表示要下载的地址
|
||||||
|
|
||||||
|
verify:表示是否检验,1:校验,0:不校验
|
||||||
|
|
||||||
最后执行以下命令让程序跑起来:
|
最后执行以下命令让程序跑起来:
|
||||||
|
|
||||||
`resume 0`
|
`resume 0`
|
||||||
|
|
||||||
|
或者
|
||||||
|
|
||||||
|
`reset`
|
||||||
|
|
||||||
|
或者短按一下开发板上的复位按键。
|
||||||
|
|
||||||
**注意:每次下载程序前记得先执行halt命令停住CPU。**
|
**注意:每次下载程序前记得先执行halt命令停住CPU。**
|
||||||
|
|
||||||
## 3.2通过UART方式下载
|
|
||||||
|
|
||||||
通过UART方式下载前需要先使能UART debug模块。在约束文件里指定的uart_debug_en引脚,当其输入为高电平时表示使能UART debug模块,输入为低电平时表示关闭UART debug模块。
|
|
||||||
|
|
||||||
当使能了UART debug模块后,就可以通过tools/tinyriscv_fw_downloader.py脚本来下载程序。
|
|
||||||
|
|
||||||
tinyriscv_fw_downloader.py脚本使用方法:
|
|
||||||
|
|
||||||
`python tinyriscv_fw_downloader.py 串口号 bin文件`
|
|
||||||
|
|
||||||
打开CMD窗口,进入到tools目录,比如输入以下命令:
|
|
||||||
|
|
||||||
![uart_debug](./images/uart_debug.png)
|
|
||||||
|
|
||||||
即可下载freertos.bin程序到软核里。下载完后,先关闭UART debug模块,然后按板子上的复位(rst)按键即可让程序跑起来。
|
|
||||||
|
|
||||||
# 4.Vivado仿真设置
|
|
||||||
|
|
||||||
如果要在vivado里进行RTL仿真的话,还需要添加tb目录里的tinyriscv_soc_tb.v文件,具体方法和添加RTL源文件类似,只是在源文件类型里选择simulation sources,如下图所示:
|
|
||||||
|
|
||||||
![add_sim](./images/add_sim.png)
|
|
||||||
|
|
||||||
最后设置一下define.v文件的路径,如下图所示:
|
|
||||||
|
|
||||||
![defines](./images/defines.png)
|
|
||||||
|
|
||||||
最后,还要指定inst.data文件的路径,即修改tinyriscv_soc_tb.v文件里的下面这一行:
|
|
||||||
|
|
||||||
```
|
|
||||||
// read mem data
|
|
||||||
initial begin
|
|
||||||
$readmemh ("F://yourpath/inst.data", tinyriscv_soc_top_0.u_rom._rom);
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
设置完成后,即可进行RTL仿真。
|
|
|
@ -1,81 +0,0 @@
|
||||||
# 时钟约束50MHz
|
|
||||||
set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports {clk}];
|
|
||||||
create_clock -add -name sys_clk_pin -period 20.00 -waveform {0 10} [get_ports {clk}];
|
|
||||||
|
|
||||||
# 时钟引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports clk]
|
|
||||||
set_property PACKAGE_PIN N14 [get_ports clk]
|
|
||||||
|
|
||||||
# 复位引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports rst]
|
|
||||||
set_property PACKAGE_PIN L13 [get_ports rst]
|
|
||||||
|
|
||||||
# 程序执行完毕指示引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports over]
|
|
||||||
set_property PACKAGE_PIN M16 [get_ports over]
|
|
||||||
|
|
||||||
# 程序执行成功指示引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports succ]
|
|
||||||
set_property PACKAGE_PIN N16 [get_ports succ]
|
|
||||||
|
|
||||||
# CPU停住指示引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports halted_ind]
|
|
||||||
set_property PACKAGE_PIN P15 [get_ports halted_ind]
|
|
||||||
|
|
||||||
# 串口下载使能引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports uart_debug_pin]
|
|
||||||
set_property PACKAGE_PIN K13 [get_ports uart_debug_pin]
|
|
||||||
|
|
||||||
# 串口发送引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports uart_tx_pin]
|
|
||||||
set_property PACKAGE_PIN M6 [get_ports uart_tx_pin]
|
|
||||||
|
|
||||||
# 串口接收引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports uart_rx_pin]
|
|
||||||
set_property PACKAGE_PIN N6 [get_ports uart_rx_pin]
|
|
||||||
|
|
||||||
# GPIO0引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports {gpio[0]}]
|
|
||||||
set_property PACKAGE_PIN P16 [get_ports {gpio[0]}]
|
|
||||||
|
|
||||||
# GPIO1引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports {gpio[1]}]
|
|
||||||
set_property PACKAGE_PIN T15 [get_ports {gpio[1]}]
|
|
||||||
|
|
||||||
# JTAG TCK引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TCK]
|
|
||||||
set_property PACKAGE_PIN N11 [get_ports jtag_TCK]
|
|
||||||
|
|
||||||
#create_clock -name jtag_clk_pin -period 300 [get_ports {jtag_TCK}];
|
|
||||||
|
|
||||||
# JTAG TMS引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TMS]
|
|
||||||
set_property PACKAGE_PIN N3 [get_ports jtag_TMS]
|
|
||||||
|
|
||||||
# JTAG TDI引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TDI]
|
|
||||||
set_property PACKAGE_PIN N2 [get_ports jtag_TDI]
|
|
||||||
|
|
||||||
# JTAG TDO引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TDO]
|
|
||||||
set_property PACKAGE_PIN M1 [get_ports jtag_TDO]
|
|
||||||
|
|
||||||
# SPI MISO引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports spi_miso]
|
|
||||||
set_property PACKAGE_PIN P1 [get_ports spi_miso]
|
|
||||||
|
|
||||||
# SPI MOSI引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports spi_mosi]
|
|
||||||
set_property PACKAGE_PIN N1 [get_ports spi_mosi]
|
|
||||||
|
|
||||||
# SPI SS引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports spi_ss]
|
|
||||||
set_property PACKAGE_PIN M5 [get_ports spi_ss]
|
|
||||||
|
|
||||||
# SPI CLK引脚
|
|
||||||
set_property IOSTANDARD LVCMOS33 [get_ports spi_clk]
|
|
||||||
set_property PACKAGE_PIN N4 [get_ports spi_clk]
|
|
||||||
|
|
||||||
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
|
|
||||||
set_property CONFIG_MODE SPIx4 [current_design]
|
|
||||||
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
out/
|
||||||
|
.Xil/
|
||||||
|
*.log
|
||||||
|
*.html
|
||||||
|
*.xml
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
VIVADO_BASE := /home/ubuntu/Xilinx/Vivado/2018.1/bin
|
||||||
|
VIVADO := $(VIVADO_BASE)/vivado
|
||||||
|
|
||||||
|
VIVADOFLAGS := \
|
||||||
|
-nojournal -mode batch \
|
||||||
|
-source scripts/init.tcl
|
||||||
|
|
||||||
|
.PHONY: synth
|
||||||
|
synth:
|
||||||
|
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl
|
||||||
|
|
||||||
|
.PHONY: impl
|
||||||
|
impl:
|
||||||
|
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl
|
||||||
|
|
||||||
|
.PHONY: bit
|
||||||
|
bit:
|
||||||
|
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl -source scripts/bit.tcl -source scripts/report.tcl
|
||||||
|
|
||||||
|
.PHONY: bin
|
||||||
|
bin:
|
||||||
|
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl -source scripts/bit.tcl -source scripts/bin.tcl -source scripts/report.tcl
|
||||||
|
|
||||||
|
.PHONY: mcs
|
||||||
|
mcs:
|
||||||
|
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl -source scripts/bit.tcl -source scripts/mcs.tcl -source scripts/report.tcl
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean::
|
||||||
|
rm -rf .Xil .ip_user_files *.log *.jou out usage_statistics_webtalk.xml usage_statistics_webtalk.html
|
|
@ -0,0 +1,16 @@
|
||||||
|
本目录包含FPGA约束文件,vivado tcl脚本和顶层文件。
|
||||||
|
|
||||||
|
```
|
||||||
|
constrs:包含FPGA约束文件
|
||||||
|
scripts:包含vivado tcl脚本
|
||||||
|
tinyriscv_soc_top.sv:整个SOC的顶层文件
|
||||||
|
```
|
||||||
|
|
||||||
|
根据vivado的安装路径,修改Makefile文件。
|
||||||
|
|
||||||
|
生成bit文件:
|
||||||
|
|
||||||
|
`make bit`
|
||||||
|
|
||||||
|
即可在out目录下生成bit文件。
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
## 12 MHz Clock Signal
|
||||||
|
set_property -dict { PACKAGE_PIN L17 IOSTANDARD LVCMOS33 } [get_ports { clk_12m_i }]; #IO_L12P_T1_MRCC_14 Sch=gclk
|
||||||
|
create_clock -add -name sys_clk_pin -period 83.33 -waveform {0 41.66} [get_ports {clk_12m_i}]
|
||||||
|
|
||||||
|
## 复位引脚
|
||||||
|
set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports rst_ext_i]; #IO_L19P_T3_16 Sch=btn[1]
|
||||||
|
|
||||||
|
## CPU停住指示引脚
|
||||||
|
set_property -dict { PACKAGE_PIN A17 IOSTANDARD LVCMOS33 } [get_ports halted_ind_pin]; #IO_L12N_T1_MRCC_16 Sch=led[1]
|
||||||
|
|
||||||
|
## 串口引脚
|
||||||
|
# UART0 TX
|
||||||
|
set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports {io_pins[0]}]; #IO_L7N_T1_D10_14 Sch=uart_rxd_out
|
||||||
|
# UART0 RX
|
||||||
|
set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports {io_pins[3]}]; #IO_L7P_T1_D09_14 Sch=uart_txd_in
|
||||||
|
|
||||||
|
## I2C引脚(EEPROM)
|
||||||
|
# I2C0 SCL引脚
|
||||||
|
set_property -dict { PACKAGE_PIN L1 IOSTANDARD LVCMOS33 } [get_ports {io_pins[6]}]; #IO_L6N_T0_VREF_35 Sch=pio[13]
|
||||||
|
# I2C0 SDA引脚
|
||||||
|
set_property -dict { PACKAGE_PIN L2 IOSTANDARD LVCMOS33 } [get_ports {io_pins[8]}]; #IO_L5N_T0_AD13N_35 Sch=pio[14]
|
||||||
|
|
||||||
|
## DS18B20
|
||||||
|
set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports {io_pins[5]}]; #IO_L11P_T1_SRCC_16 Sch=pio[05]
|
||||||
|
|
||||||
|
## WS2812
|
||||||
|
set_property -dict { PACKAGE_PIN P1 IOSTANDARD LVCMOS33 } [get_ports {io_pins[4]}]; #IO_L19N_T3_VREF_35 Sch=pio[23]
|
||||||
|
|
||||||
|
## USER KEY
|
||||||
|
# KEY1
|
||||||
|
set_property -dict { PACKAGE_PIN U4 IOSTANDARD LVCMOS33 } [get_ports {io_pins[1]}]; #IO_L11P_T1_SRCC_34 Sch=pio[38]
|
||||||
|
# KEY2
|
||||||
|
set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports {io_pins[2]}]; #IO_L16N_T2_34 Sch=pio[39]
|
||||||
|
|
||||||
|
## ANI
|
||||||
|
# PWM_V
|
||||||
|
set_property -dict { PACKAGE_PIN M3 IOSTANDARD LVCMOS33 } [get_ports {io_pins[7]}]; #IO_L8N_T1_AD14N_35 Sch=pio[01]
|
||||||
|
# C_OUT
|
||||||
|
set_property -dict { PACKAGE_PIN L3 IOSTANDARD LVCMOS33 } [get_ports {io_pins[9]}]; #IO_L8P_T1_AD14P_35 Sch=pio[02]
|
||||||
|
|
||||||
|
## SPI/LED
|
||||||
|
# SS
|
||||||
|
set_property -dict { PACKAGE_PIN M1 IOSTANDARD LVCMOS33 } [get_ports {io_pins[11]}]; #IO_L9N_T1_DQS_AD7N_35 Sch=pio[17]
|
||||||
|
# DQ1
|
||||||
|
set_property -dict { PACKAGE_PIN N3 IOSTANDARD LVCMOS33 } [get_ports {io_pins[13]}]; #IO_L12P_T1_MRCC_35 Sch=pio[18]
|
||||||
|
# DQ2/LED7
|
||||||
|
set_property -dict { PACKAGE_PIN P3 IOSTANDARD LVCMOS33 } [get_ports {io_pins[14]}]; #IO_L12N_T1_MRCC_35 Sch=pio[19]
|
||||||
|
# DQ3/LED6
|
||||||
|
set_property -dict { PACKAGE_PIN M2 IOSTANDARD LVCMOS33 } [get_ports {io_pins[15]}]; #IO_L9P_T1_DQS_AD7P_35 Sch=pio[20]
|
||||||
|
# SCK/LED5
|
||||||
|
set_property -dict { PACKAGE_PIN N1 IOSTANDARD LVCMOS33 } [get_ports {io_pins[10]}]; #IO_L10N_T1_AD15N_35 Sch=pio[21]
|
||||||
|
# DQ0/LED4
|
||||||
|
set_property -dict { PACKAGE_PIN N2 IOSTANDARD LVCMOS33 } [get_ports {io_pins[12]}]; #IO_L10P_T1_AD15P_35 Sch=pio[22]
|
||||||
|
|
||||||
|
## QSPI Flash引脚(存放程序)
|
||||||
|
# CLK
|
||||||
|
set_property -dict { PACKAGE_PIN J1 IOSTANDARD LVCMOS33 } [get_ports flash_spi_clk_pin]; #IO_L3N_T0_DQS_AD5N_35 Sch=pio[11]
|
||||||
|
# SS
|
||||||
|
set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports flash_spi_ss_pin]; #IO_L6N_T0_VREF_16 Sch=pio[07]
|
||||||
|
# DQ0
|
||||||
|
set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports {flash_spi_dq_pin[0]}]; #IO_L5P_T0_AD13P_35 Sch=pio[12]
|
||||||
|
# DQ1
|
||||||
|
set_property -dict { PACKAGE_PIN B15 IOSTANDARD LVCMOS33 } [get_ports {flash_spi_dq_pin[1]}]; #IO_L11N_T1_SRCC_16 Sch=pio[08]
|
||||||
|
# DQ2
|
||||||
|
set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports {flash_spi_dq_pin[2]}]; #IO_L6P_T0_16 Sch=pio[09]
|
||||||
|
# DQ3
|
||||||
|
set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports {flash_spi_dq_pin[3]}]; #IO_L7P_T1_AD6P_35 Sch=pio[10]
|
||||||
|
|
||||||
|
## JTAG引脚
|
||||||
|
# JTAG TCK引脚
|
||||||
|
#set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_TCK_pin]
|
||||||
|
set_property -dict { PACKAGE_PIN W7 IOSTANDARD LVCMOS33 } [get_ports jtag_TCK_pin]; #IO_L13P_T2_MRCC_34 Sch=pio[46]
|
||||||
|
# JTAG TMS引脚
|
||||||
|
set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports jtag_TMS_pin]; #IO_L14P_T2_SRCC_34 Sch=pio[47]
|
||||||
|
# JTAG TDI引脚
|
||||||
|
set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports jtag_TDI_pin]; #IO_L14N_T2_SRCC_34 Sch=pio[48]
|
||||||
|
# JTAG TDO引脚
|
||||||
|
set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports jtag_TDO_pin]; #IO_L19P_T3_34 Sch=pio[45]
|
||||||
|
|
||||||
|
## Set unused pin pullnone
|
||||||
|
set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]
|
||||||
|
|
||||||
|
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
|
||||||
|
set_property CONFIG_MODE SPIx4 [current_design]
|
||||||
|
set_property BITSTREAM.CONFIG.CONFIGRATE 6 [current_design]
|
|
@ -0,0 +1 @@
|
||||||
|
write_cfgmem -format bin -size 4 -interface SPIx4 -loadbit {up 0x00000000 "out/tinyriscv_soc_top.bit" } -force -file "out/tinyriscv_soc_top.bin"
|
|
@ -0,0 +1 @@
|
||||||
|
write_bitstream -force [file join $outdir "${top_module}.bit"]
|
|
@ -0,0 +1,5 @@
|
||||||
|
opt_design
|
||||||
|
place_design
|
||||||
|
phys_opt_design
|
||||||
|
power_opt_design
|
||||||
|
route_design
|
|
@ -0,0 +1,43 @@
|
||||||
|
set prj_name {tinyriscv}
|
||||||
|
set part_fpga {xc7a15tcpg236-1}
|
||||||
|
set top_module {tinyriscv_soc_top}
|
||||||
|
|
||||||
|
set scriptsdir ./scripts
|
||||||
|
set constrsdir ./constrs
|
||||||
|
set outdir ./out
|
||||||
|
set srcdir ../../../rtl
|
||||||
|
|
||||||
|
# 在某目录下递归查找所有指定文件
|
||||||
|
proc rec_glob { basedir pattern } {
|
||||||
|
set dirlist [glob -nocomplain -directory $basedir -type d *]
|
||||||
|
set findlist [glob -nocomplain -directory $basedir $pattern]
|
||||||
|
foreach dir $dirlist {
|
||||||
|
set reclist [rec_glob $dir $pattern]
|
||||||
|
set findlist [concat $findlist $reclist]
|
||||||
|
}
|
||||||
|
return $findlist
|
||||||
|
}
|
||||||
|
|
||||||
|
# 创建工程(内存模式)
|
||||||
|
create_project -part $part_fpga -in_memory
|
||||||
|
|
||||||
|
# 创建sources_1
|
||||||
|
if {[get_filesets -quiet sources_1] eq ""} {
|
||||||
|
create_fileset -srcset sources_1
|
||||||
|
}
|
||||||
|
set src_pkg_files [rec_glob $srcdir "*pkg.sv"]
|
||||||
|
set src_verilog_files [rec_glob $srcdir "*.sv"]
|
||||||
|
set src_all_files [concat $src_pkg_files $src_verilog_files]
|
||||||
|
# 添加verilog文件
|
||||||
|
add_files -norecurse -fileset sources_1 $src_all_files
|
||||||
|
add_files -norecurse -fileset sources_1 ./tinyriscv_soc_top.sv
|
||||||
|
|
||||||
|
# 创建constrs_1
|
||||||
|
if {[get_filesets -quiet constrs_1] eq ""} {
|
||||||
|
create_fileset -constrset constrs_1
|
||||||
|
}
|
||||||
|
# 添加约束文件
|
||||||
|
add_files -norecurse -fileset constrs_1 [glob -directory $constrsdir {*.xdc}]
|
||||||
|
|
||||||
|
# 创建输出目录
|
||||||
|
file mkdir $outdir
|
|
@ -0,0 +1 @@
|
||||||
|
write_cfgmem -format mcs -size 4 -interface SPIx4 -loadbit {up 0x00000000 "out/tinyriscv_soc_top.bit" } -force -file "out/tinyriscv_soc_top.mcs"
|
|
@ -0,0 +1,12 @@
|
||||||
|
set rptdir [file join $outdir report]
|
||||||
|
file mkdir $rptdir
|
||||||
|
set rptutil [file join $rptdir utilization.txt]
|
||||||
|
report_datasheet -file [file join $rptdir datasheet.txt]
|
||||||
|
report_utilization -hierarchical -file $rptutil
|
||||||
|
report_clock_utilization -file $rptutil -append
|
||||||
|
report_ram_utilization -file $rptutil -append -detail
|
||||||
|
report_timing_summary -file [file join $rptdir timing.txt] -max_paths 10
|
||||||
|
report_high_fanout_nets -file [file join $rptdir fanout.txt] -timing -load_types -max_nets 25
|
||||||
|
report_drc -file [file join $rptdir drc.txt]
|
||||||
|
report_io -file [file join $rptdir io.txt]
|
||||||
|
report_clocks -file [file join $rptdir clocks.txt]
|
|
@ -0,0 +1 @@
|
||||||
|
synth_design -top $top_module
|
|
@ -0,0 +1,668 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "../../../rtl/core/defines.sv"
|
||||||
|
`include "../../../rtl/debug/jtag_def.sv"
|
||||||
|
|
||||||
|
// tinyriscv soc顶层模块
|
||||||
|
module tinyriscv_soc_top #(
|
||||||
|
parameter bit TRACE_ENABLE = 1'b0,
|
||||||
|
parameter int GPIO_NUM = 16,
|
||||||
|
parameter int I2C_NUM = 2,
|
||||||
|
parameter int UART_NUM = 3,
|
||||||
|
parameter int SPI_NUM = 1
|
||||||
|
)(
|
||||||
|
input wire clk_12m_i, // 时钟引脚
|
||||||
|
input wire rst_ext_i, // 复位引脚,高电平有效
|
||||||
|
|
||||||
|
output wire halted_ind_pin, // jtag是否已经halt住CPU,高电平有效
|
||||||
|
|
||||||
|
inout wire[GPIO_NUM-1:0] io_pins, // IO引脚,1bit代表一个IO
|
||||||
|
|
||||||
|
output wire flash_spi_clk_pin, // flash spi clk引脚
|
||||||
|
output wire flash_spi_ss_pin, // flash spi ss引脚
|
||||||
|
inout wire [3:0] flash_spi_dq_pin, // flash spi dq引脚
|
||||||
|
|
||||||
|
input wire jtag_TCK_pin, // JTAG TCK引脚
|
||||||
|
input wire jtag_TMS_pin, // JTAG TMS引脚
|
||||||
|
input wire jtag_TDI_pin, // JTAG TDI引脚
|
||||||
|
output wire jtag_TDO_pin // JTAG TDO引脚
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam int MASTERS = 3; // Number of master ports
|
||||||
|
localparam int SLAVES = 17; // Number of slave ports
|
||||||
|
|
||||||
|
// masters
|
||||||
|
localparam int JtagHost = 0;
|
||||||
|
localparam int CoreD = 1;
|
||||||
|
localparam int CoreI = 2;
|
||||||
|
|
||||||
|
// slaves
|
||||||
|
localparam int Rom = 0;
|
||||||
|
localparam int Ram = 1;
|
||||||
|
localparam int JtagDevice = 2;
|
||||||
|
localparam int Timer0 = 3;
|
||||||
|
localparam int Gpio = 4;
|
||||||
|
localparam int Uart0 = 5;
|
||||||
|
localparam int Rvic = 6;
|
||||||
|
localparam int I2c0 = 7;
|
||||||
|
localparam int Spi0 = 8;
|
||||||
|
localparam int Pinmux = 9;
|
||||||
|
localparam int Uart1 = 10;
|
||||||
|
localparam int Uart2 = 11;
|
||||||
|
localparam int I2c1 = 12;
|
||||||
|
localparam int Timer1 = 13;
|
||||||
|
localparam int Timer2 = 14;
|
||||||
|
localparam int Xip = 15;
|
||||||
|
localparam int Bootrom = 16;
|
||||||
|
|
||||||
|
wire master_req [MASTERS];
|
||||||
|
wire master_gnt [MASTERS];
|
||||||
|
wire master_rvalid [MASTERS];
|
||||||
|
wire [31:0] master_addr [MASTERS];
|
||||||
|
wire master_we [MASTERS];
|
||||||
|
wire [ 3:0] master_be [MASTERS];
|
||||||
|
wire [31:0] master_rdata [MASTERS];
|
||||||
|
wire [31:0] master_wdata [MASTERS];
|
||||||
|
|
||||||
|
wire slave_req [SLAVES];
|
||||||
|
wire slave_gnt [SLAVES];
|
||||||
|
wire slave_rvalid [SLAVES];
|
||||||
|
wire [31:0] slave_addr [SLAVES];
|
||||||
|
wire slave_we [SLAVES];
|
||||||
|
wire [ 3:0] slave_be [SLAVES];
|
||||||
|
wire [31:0] slave_rdata [SLAVES];
|
||||||
|
wire [31:0] slave_wdata [SLAVES];
|
||||||
|
|
||||||
|
wire [31:0] slave_addr_mask [SLAVES];
|
||||||
|
wire [31:0] slave_addr_base [SLAVES];
|
||||||
|
|
||||||
|
wire clk;
|
||||||
|
wire rst_ext_n;
|
||||||
|
wire ndmreset;
|
||||||
|
wire ndmreset_n;
|
||||||
|
wire debug_req;
|
||||||
|
wire core_halted;
|
||||||
|
|
||||||
|
reg[31:0] irq_src;
|
||||||
|
wire int_req;
|
||||||
|
wire[7:0] int_id;
|
||||||
|
|
||||||
|
wire timer0_irq;
|
||||||
|
wire timer1_irq;
|
||||||
|
wire timer2_irq;
|
||||||
|
wire uart0_irq;
|
||||||
|
wire uart1_irq;
|
||||||
|
wire uart2_irq;
|
||||||
|
wire gpio0_irq;
|
||||||
|
wire gpio1_irq;
|
||||||
|
wire i2c0_irq;
|
||||||
|
wire i2c1_irq;
|
||||||
|
wire spi0_irq;
|
||||||
|
wire gpio2_4_irq;
|
||||||
|
wire gpio5_7_irq;
|
||||||
|
wire gpio8_irq;
|
||||||
|
wire gpio9_irq;
|
||||||
|
wire gpio10_12_irq;
|
||||||
|
wire gpio13_15_irq;
|
||||||
|
|
||||||
|
wire[GPIO_NUM-1:0] gpio_data_in;
|
||||||
|
wire[GPIO_NUM-1:0] gpio_oe;
|
||||||
|
wire[GPIO_NUM-1:0] gpio_data_out;
|
||||||
|
|
||||||
|
wire[GPIO_NUM-1:0] io_data_in;
|
||||||
|
wire[GPIO_NUM-1:0] io_oe;
|
||||||
|
wire[GPIO_NUM-1:0] io_data_out;
|
||||||
|
|
||||||
|
wire[I2C_NUM-1:0] i2c_scl_in;
|
||||||
|
wire[I2C_NUM-1:0] i2c_scl_oe;
|
||||||
|
wire[I2C_NUM-1:0] i2c_scl_out;
|
||||||
|
wire[I2C_NUM-1:0] i2c_sda_in;
|
||||||
|
wire[I2C_NUM-1:0] i2c_sda_oe;
|
||||||
|
wire[I2C_NUM-1:0] i2c_sda_out;
|
||||||
|
|
||||||
|
wire[UART_NUM-1:0] uart_tx;
|
||||||
|
wire[UART_NUM-1:0] uart_rx;
|
||||||
|
|
||||||
|
wire[SPI_NUM-1:0] spi_clk_in;
|
||||||
|
wire[SPI_NUM-1:0] spi_clk_oe;
|
||||||
|
wire[SPI_NUM-1:0] spi_clk_out;
|
||||||
|
wire[SPI_NUM-1:0] spi_ss_in;
|
||||||
|
wire[SPI_NUM-1:0] spi_ss_oe;
|
||||||
|
wire[SPI_NUM-1:0] spi_ss_out;
|
||||||
|
wire[3:0] spi_dq_in[SPI_NUM-1:0];
|
||||||
|
wire[3:0] spi_dq_oe[SPI_NUM-1:0];
|
||||||
|
wire[3:0] spi_dq_out[SPI_NUM-1:0];
|
||||||
|
|
||||||
|
wire[31:0] core_instr_addr;
|
||||||
|
wire[31:0] core_data_addr;
|
||||||
|
|
||||||
|
wire[3:0] flash_spi_dq_in;
|
||||||
|
wire[3:0] flash_spi_dq_oe;
|
||||||
|
wire[3:0] flash_spi_dq_out;
|
||||||
|
|
||||||
|
// 中断源
|
||||||
|
always @ (*) begin
|
||||||
|
irq_src = 32'h0;
|
||||||
|
irq_src[ 0] = timer0_irq;
|
||||||
|
irq_src[ 1] = uart0_irq;
|
||||||
|
irq_src[ 2] = gpio0_irq;
|
||||||
|
irq_src[ 3] = gpio1_irq;
|
||||||
|
irq_src[ 4] = i2c0_irq;
|
||||||
|
irq_src[ 5] = spi0_irq;
|
||||||
|
irq_src[ 6] = gpio2_4_irq;
|
||||||
|
irq_src[ 7] = gpio5_7_irq;
|
||||||
|
irq_src[ 8] = gpio8_irq;
|
||||||
|
irq_src[ 9] = gpio9_irq;
|
||||||
|
irq_src[10] = gpio10_12_irq;
|
||||||
|
irq_src[11] = gpio13_15_irq;
|
||||||
|
irq_src[12] = uart1_irq;
|
||||||
|
irq_src[13] = uart2_irq;
|
||||||
|
irq_src[14] = i2c1_irq;
|
||||||
|
irq_src[15] = timer1_irq;
|
||||||
|
irq_src[16] = timer2_irq;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign rst_ext_n = ~rst_ext_i;
|
||||||
|
assign halted_ind_pin = core_halted;
|
||||||
|
|
||||||
|
assign master_we[CoreI] = '0;
|
||||||
|
assign master_be[CoreI] = '0;
|
||||||
|
tinyriscv_core #(
|
||||||
|
.DEBUG_HALT_ADDR(`DEBUG_ADDR_BASE + `HaltAddress),
|
||||||
|
.DEBUG_EXCEPTION_ADDR(`DEBUG_ADDR_BASE + `ExceptionAddress),
|
||||||
|
.BranchPredictor(1'b1),
|
||||||
|
.TRACE_ENABLE(TRACE_ENABLE)
|
||||||
|
) u_tinyriscv_core (
|
||||||
|
.clk (clk),
|
||||||
|
.rst_n (ndmreset_n),
|
||||||
|
|
||||||
|
.instr_req_o (master_req[CoreI]),
|
||||||
|
.instr_gnt_i (master_gnt[CoreI]),
|
||||||
|
.instr_rvalid_i (master_rvalid[CoreI]),
|
||||||
|
.instr_addr_o (master_addr[CoreI]),
|
||||||
|
.instr_rdata_i (master_rdata[CoreI]),
|
||||||
|
.instr_err_i (1'b0),
|
||||||
|
|
||||||
|
.data_req_o (master_req[CoreD]),
|
||||||
|
.data_gnt_i (master_gnt[CoreD]),
|
||||||
|
.data_rvalid_i (master_rvalid[CoreD]),
|
||||||
|
.data_we_o (master_we[CoreD]),
|
||||||
|
.data_be_o (master_be[CoreD]),
|
||||||
|
.data_addr_o (master_addr[CoreD]),
|
||||||
|
.data_wdata_o (master_wdata[CoreD]),
|
||||||
|
.data_rdata_i (master_rdata[CoreD]),
|
||||||
|
.data_err_i (1'b0),
|
||||||
|
|
||||||
|
.int_req_i (int_req),
|
||||||
|
.int_id_i (int_id),
|
||||||
|
|
||||||
|
.debug_req_i (debug_req)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Rom] = `ROM_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Rom] = `ROM_ADDR_BASE;
|
||||||
|
// 1.指令存储器
|
||||||
|
rom #(
|
||||||
|
.DP(`ROM_DEPTH)
|
||||||
|
) u_rom (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.req_i (slave_req[Rom]),
|
||||||
|
.addr_i (slave_addr[Rom]),
|
||||||
|
.data_i (slave_wdata[Rom]),
|
||||||
|
.be_i (slave_be[Rom]),
|
||||||
|
.we_i (slave_we[Rom]),
|
||||||
|
.gnt_o (slave_gnt[Rom]),
|
||||||
|
.rvalid_o (slave_rvalid[Rom]),
|
||||||
|
.data_o (slave_rdata[Rom])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Ram] = `RAM_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Ram] = `RAM_ADDR_BASE;
|
||||||
|
// 2.数据存储器
|
||||||
|
ram #(
|
||||||
|
.DP(`RAM_DEPTH)
|
||||||
|
) u_ram (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.req_i (slave_req[Ram]),
|
||||||
|
.addr_i (slave_addr[Ram]),
|
||||||
|
.data_i (slave_wdata[Ram]),
|
||||||
|
.be_i (slave_be[Ram]),
|
||||||
|
.we_i (slave_we[Ram]),
|
||||||
|
.gnt_o (slave_gnt[Ram]),
|
||||||
|
.rvalid_o (slave_rvalid[Ram]),
|
||||||
|
.data_o (slave_rdata[Ram])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Timer0] = `TIMER0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Timer0] = `TIMER0_ADDR_BASE;
|
||||||
|
// 3.定时器0模块
|
||||||
|
timer_top timer0(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.irq_o (timer0_irq),
|
||||||
|
.req_i (slave_req[Timer0]),
|
||||||
|
.we_i (slave_we[Timer0]),
|
||||||
|
.be_i (slave_be[Timer0]),
|
||||||
|
.addr_i (slave_addr[Timer0]),
|
||||||
|
.data_i (slave_wdata[Timer0]),
|
||||||
|
.gnt_o (slave_gnt[Timer0]),
|
||||||
|
.rvalid_o(slave_rvalid[Timer0]),
|
||||||
|
.data_o (slave_rdata[Timer0])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Timer1] = `TIMER1_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Timer1] = `TIMER1_ADDR_BASE;
|
||||||
|
// 4.定时器1模块
|
||||||
|
timer_top timer1(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.irq_o (timer1_irq),
|
||||||
|
.req_i (slave_req[Timer1]),
|
||||||
|
.we_i (slave_we[Timer1]),
|
||||||
|
.be_i (slave_be[Timer1]),
|
||||||
|
.addr_i (slave_addr[Timer1]),
|
||||||
|
.data_i (slave_wdata[Timer1]),
|
||||||
|
.gnt_o (slave_gnt[Timer1]),
|
||||||
|
.rvalid_o(slave_rvalid[Timer1]),
|
||||||
|
.data_o (slave_rdata[Timer1])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Timer2] = `TIMER2_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Timer2] = `TIMER2_ADDR_BASE;
|
||||||
|
// 5.定时器2模块
|
||||||
|
timer_top timer2(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.irq_o (timer2_irq),
|
||||||
|
.req_i (slave_req[Timer2]),
|
||||||
|
.we_i (slave_we[Timer2]),
|
||||||
|
.be_i (slave_be[Timer2]),
|
||||||
|
.addr_i (slave_addr[Timer2]),
|
||||||
|
.data_i (slave_wdata[Timer2]),
|
||||||
|
.gnt_o (slave_gnt[Timer2]),
|
||||||
|
.rvalid_o(slave_rvalid[Timer2]),
|
||||||
|
.data_o (slave_rdata[Timer2])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Gpio] = `GPIO_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Gpio] = `GPIO_ADDR_BASE;
|
||||||
|
// 6.GPIO模块
|
||||||
|
gpio_top #(
|
||||||
|
.GPIO_NUM(GPIO_NUM)
|
||||||
|
) u_gpio (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.gpio_oe_o (gpio_oe),
|
||||||
|
.gpio_data_o (gpio_data_out),
|
||||||
|
.gpio_data_i (gpio_data_in),
|
||||||
|
.irq_gpio0_o (gpio0_irq),
|
||||||
|
.irq_gpio1_o (gpio1_irq),
|
||||||
|
.irq_gpio2_4_o (gpio2_4_irq),
|
||||||
|
.irq_gpio5_7_o (gpio5_7_irq),
|
||||||
|
.irq_gpio8_o (gpio8_irq),
|
||||||
|
.irq_gpio9_o (gpio9_irq),
|
||||||
|
.irq_gpio10_12_o(gpio10_12_irq),
|
||||||
|
.irq_gpio13_15_o(gpio13_15_irq),
|
||||||
|
.req_i (slave_req[Gpio]),
|
||||||
|
.we_i (slave_we[Gpio]),
|
||||||
|
.be_i (slave_be[Gpio]),
|
||||||
|
.addr_i (slave_addr[Gpio]),
|
||||||
|
.data_i (slave_wdata[Gpio]),
|
||||||
|
.gnt_o (slave_gnt[Gpio]),
|
||||||
|
.rvalid_o (slave_rvalid[Gpio]),
|
||||||
|
.data_o (slave_rdata[Gpio])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Uart0] = `UART0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Uart0] = `UART0_ADDR_BASE;
|
||||||
|
// 7.串口0模块
|
||||||
|
uart_top uart0 (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.rx_i (uart_rx[0]),
|
||||||
|
.tx_o (uart_tx[0]),
|
||||||
|
.irq_o (uart0_irq),
|
||||||
|
.req_i (slave_req[Uart0]),
|
||||||
|
.we_i (slave_we[Uart0]),
|
||||||
|
.be_i (slave_be[Uart0]),
|
||||||
|
.addr_i (slave_addr[Uart0]),
|
||||||
|
.data_i (slave_wdata[Uart0]),
|
||||||
|
.gnt_o (slave_gnt[Uart0]),
|
||||||
|
.rvalid_o (slave_rvalid[Uart0]),
|
||||||
|
.data_o (slave_rdata[Uart0])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Uart1] = `UART1_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Uart1] = `UART1_ADDR_BASE;
|
||||||
|
// 8.串口1模块
|
||||||
|
uart_top uart1 (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.rx_i (uart_rx[1]),
|
||||||
|
.tx_o (uart_tx[1]),
|
||||||
|
.irq_o (uart1_irq),
|
||||||
|
.req_i (slave_req[Uart1]),
|
||||||
|
.we_i (slave_we[Uart1]),
|
||||||
|
.be_i (slave_be[Uart1]),
|
||||||
|
.addr_i (slave_addr[Uart1]),
|
||||||
|
.data_i (slave_wdata[Uart1]),
|
||||||
|
.gnt_o (slave_gnt[Uart1]),
|
||||||
|
.rvalid_o (slave_rvalid[Uart1]),
|
||||||
|
.data_o (slave_rdata[Uart1])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Uart2] = `UART2_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Uart2] = `UART2_ADDR_BASE;
|
||||||
|
// 9.串口2模块
|
||||||
|
uart_top uart2 (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.rx_i (uart_rx[2]),
|
||||||
|
.tx_o (uart_tx[2]),
|
||||||
|
.irq_o (uart2_irq),
|
||||||
|
.req_i (slave_req[Uart2]),
|
||||||
|
.we_i (slave_we[Uart2]),
|
||||||
|
.be_i (slave_be[Uart2]),
|
||||||
|
.addr_i (slave_addr[Uart2]),
|
||||||
|
.data_i (slave_wdata[Uart2]),
|
||||||
|
.gnt_o (slave_gnt[Uart2]),
|
||||||
|
.rvalid_o (slave_rvalid[Uart2]),
|
||||||
|
.data_o (slave_rdata[Uart2])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Rvic] = `RVIC_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Rvic] = `RVIC_ADDR_BASE;
|
||||||
|
// 10.中断控制器模块
|
||||||
|
rvic_top u_rvic(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.src_i (irq_src),
|
||||||
|
.irq_o (int_req),
|
||||||
|
.irq_id_o (int_id),
|
||||||
|
.req_i (slave_req[Rvic]),
|
||||||
|
.we_i (slave_we[Rvic]),
|
||||||
|
.be_i (slave_be[Rvic]),
|
||||||
|
.addr_i (slave_addr[Rvic]),
|
||||||
|
.data_i (slave_wdata[Rvic]),
|
||||||
|
.gnt_o (slave_gnt[Rvic]),
|
||||||
|
.rvalid_o (slave_rvalid[Rvic]),
|
||||||
|
.data_o (slave_rdata[Rvic])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[I2c0] = `I2C0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[I2c0] = `I2C0_ADDR_BASE;
|
||||||
|
// 11.I2C0模块
|
||||||
|
i2c_top i2c0(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.scl_o (i2c_scl_out[0]),
|
||||||
|
.scl_oe_o (i2c_scl_oe[0]),
|
||||||
|
.scl_i (i2c_scl_in[0]),
|
||||||
|
.sda_o (i2c_sda_out[0]),
|
||||||
|
.sda_oe_o (i2c_sda_oe[0]),
|
||||||
|
.sda_i (i2c_sda_in[0]),
|
||||||
|
.irq_o (i2c0_irq),
|
||||||
|
.req_i (slave_req[I2c0]),
|
||||||
|
.we_i (slave_we[I2c0]),
|
||||||
|
.be_i (slave_be[I2c0]),
|
||||||
|
.addr_i (slave_addr[I2c0]),
|
||||||
|
.data_i (slave_wdata[I2c0]),
|
||||||
|
.gnt_o (slave_gnt[I2c0]),
|
||||||
|
.rvalid_o (slave_rvalid[I2c0]),
|
||||||
|
.data_o (slave_rdata[I2c0])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[I2c1] = `I2C1_ADDR_MASK;
|
||||||
|
assign slave_addr_base[I2c1] = `I2C1_ADDR_BASE;
|
||||||
|
// 12.I2C1模块
|
||||||
|
i2c_top i2c1(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.scl_o (i2c_scl_out[1]),
|
||||||
|
.scl_oe_o (i2c_scl_oe[1]),
|
||||||
|
.scl_i (i2c_scl_in[1]),
|
||||||
|
.sda_o (i2c_sda_out[1]),
|
||||||
|
.sda_oe_o (i2c_sda_oe[1]),
|
||||||
|
.sda_i (i2c_sda_in[1]),
|
||||||
|
.irq_o (i2c1_irq),
|
||||||
|
.req_i (slave_req[I2c1]),
|
||||||
|
.we_i (slave_we[I2c1]),
|
||||||
|
.be_i (slave_be[I2c1]),
|
||||||
|
.addr_i (slave_addr[I2c1]),
|
||||||
|
.data_i (slave_wdata[I2c1]),
|
||||||
|
.gnt_o (slave_gnt[I2c1]),
|
||||||
|
.rvalid_o (slave_rvalid[I2c1]),
|
||||||
|
.data_o (slave_rdata[I2c1])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Spi0] = `SPI0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Spi0] = `SPI0_ADDR_BASE;
|
||||||
|
// 13.SPI0模块
|
||||||
|
spi_top spi0(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.spi_clk_i (spi_clk_in[0]),
|
||||||
|
.spi_clk_o (spi_clk_out[0]),
|
||||||
|
.spi_clk_oe_o(spi_clk_oe[0]),
|
||||||
|
.spi_ss_i (spi_ss_in[0]),
|
||||||
|
.spi_ss_o (spi_ss_out[0]),
|
||||||
|
.spi_ss_oe_o(spi_ss_oe[0]),
|
||||||
|
.spi_dq0_i (spi_dq_in[0][0]),
|
||||||
|
.spi_dq0_o (spi_dq_out[0][0]),
|
||||||
|
.spi_dq0_oe_o(spi_dq_oe[0][0]),
|
||||||
|
.spi_dq1_i (spi_dq_in[0][1]),
|
||||||
|
.spi_dq1_o (spi_dq_out[0][1]),
|
||||||
|
.spi_dq1_oe_o(spi_dq_oe[0][1]),
|
||||||
|
.spi_dq2_i (spi_dq_in[0][2]),
|
||||||
|
.spi_dq2_o (spi_dq_out[0][2]),
|
||||||
|
.spi_dq2_oe_o(spi_dq_oe[0][2]),
|
||||||
|
.spi_dq3_i (spi_dq_in[0][3]),
|
||||||
|
.spi_dq3_o (spi_dq_out[0][3]),
|
||||||
|
.spi_dq3_oe_o(spi_dq_oe[0][3]),
|
||||||
|
.irq_o (spi0_irq),
|
||||||
|
.req_i (slave_req[Spi0]),
|
||||||
|
.we_i (slave_we[Spi0]),
|
||||||
|
.be_i (slave_be[Spi0]),
|
||||||
|
.addr_i (slave_addr[Spi0]),
|
||||||
|
.data_i (slave_wdata[Spi0]),
|
||||||
|
.gnt_o (slave_gnt[Spi0]),
|
||||||
|
.rvalid_o (slave_rvalid[Spi0]),
|
||||||
|
.data_o (slave_rdata[Spi0])
|
||||||
|
);
|
||||||
|
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_io_data
|
||||||
|
assign io_pins[i] = io_oe[i] ? io_data_out[i] : 1'bz;
|
||||||
|
assign io_data_in[i] = io_pins[i];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign slave_addr_mask[Pinmux] = `PINMUX_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Pinmux] = `PINMUX_ADDR_BASE;
|
||||||
|
// 14.PINMUX模块
|
||||||
|
pinmux_top #(
|
||||||
|
.GPIO_NUM(GPIO_NUM),
|
||||||
|
.I2C_NUM(I2C_NUM),
|
||||||
|
.UART_NUM(UART_NUM),
|
||||||
|
.SPI_NUM(SPI_NUM)
|
||||||
|
) u_pinmux (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.gpio_oe_i (gpio_oe),
|
||||||
|
.gpio_val_i (gpio_data_out),
|
||||||
|
.gpio_val_o (gpio_data_in),
|
||||||
|
.i2c_sda_oe_i (i2c_sda_oe),
|
||||||
|
.i2c_sda_val_i (i2c_sda_out),
|
||||||
|
.i2c_sda_val_o (i2c_sda_in),
|
||||||
|
.i2c_scl_oe_i (i2c_scl_oe),
|
||||||
|
.i2c_scl_val_i (i2c_scl_out),
|
||||||
|
.i2c_scl_val_o (i2c_scl_in),
|
||||||
|
.uart_tx_oe_i ({UART_NUM{1'b1}}),
|
||||||
|
.uart_tx_val_i (uart_tx),
|
||||||
|
.uart_tx_val_o (),
|
||||||
|
.uart_rx_oe_i ({UART_NUM{1'b0}}),
|
||||||
|
.uart_rx_val_i (),
|
||||||
|
.uart_rx_val_o (uart_rx),
|
||||||
|
.spi_clk_oe_i (spi_clk_oe),
|
||||||
|
.spi_clk_val_i (spi_clk_out),
|
||||||
|
.spi_clk_val_o (spi_clk_in),
|
||||||
|
.spi_ss_oe_i (spi_ss_oe),
|
||||||
|
.spi_ss_val_i (spi_ss_out),
|
||||||
|
.spi_ss_val_o (spi_ss_in),
|
||||||
|
.spi_dq_oe_i (spi_dq_oe),
|
||||||
|
.spi_dq_val_i (spi_dq_out),
|
||||||
|
.spi_dq_val_o (spi_dq_in),
|
||||||
|
.io_val_i (io_data_in),
|
||||||
|
.io_val_o (io_data_out),
|
||||||
|
.io_oe_o (io_oe),
|
||||||
|
.req_i (slave_req[Pinmux]),
|
||||||
|
.we_i (slave_we[Pinmux]),
|
||||||
|
.be_i (slave_be[Pinmux]),
|
||||||
|
.addr_i (slave_addr[Pinmux]),
|
||||||
|
.data_i (slave_wdata[Pinmux]),
|
||||||
|
.gnt_o (slave_gnt[Pinmux]),
|
||||||
|
.rvalid_o (slave_rvalid[Pinmux]),
|
||||||
|
.data_o (slave_rdata[Pinmux])
|
||||||
|
);
|
||||||
|
|
||||||
|
for (genvar j = 0; j < 4; j = j + 1) begin : g_spi_pin_data
|
||||||
|
assign flash_spi_dq_pin[j] = flash_spi_dq_oe[j] ? flash_spi_dq_out[j] : 1'bz;
|
||||||
|
assign flash_spi_dq_in[j] = flash_spi_dq_pin[j];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign slave_addr_mask[Xip] = `XIP_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Xip] = `XIP_ADDR_BASE;
|
||||||
|
// 15.xip模块
|
||||||
|
xip_top xip (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.spi_clk_o (flash_spi_clk_pin),
|
||||||
|
.spi_clk_oe_o (),
|
||||||
|
.spi_ss_o (flash_spi_ss_pin),
|
||||||
|
.spi_ss_oe_o (),
|
||||||
|
.spi_dq0_i (flash_spi_dq_in[0]),
|
||||||
|
.spi_dq0_o (flash_spi_dq_out[0]),
|
||||||
|
.spi_dq0_oe_o (flash_spi_dq_oe[0]),
|
||||||
|
.spi_dq1_i (flash_spi_dq_in[1]),
|
||||||
|
.spi_dq1_o (flash_spi_dq_out[1]),
|
||||||
|
.spi_dq1_oe_o (flash_spi_dq_oe[1]),
|
||||||
|
.spi_dq2_i (flash_spi_dq_in[2]),
|
||||||
|
.spi_dq2_o (flash_spi_dq_out[2]),
|
||||||
|
.spi_dq2_oe_o (flash_spi_dq_oe[2]),
|
||||||
|
.spi_dq3_i (flash_spi_dq_in[3]),
|
||||||
|
.spi_dq3_o (flash_spi_dq_out[3]),
|
||||||
|
.spi_dq3_oe_o (flash_spi_dq_oe[3]),
|
||||||
|
.req_i (slave_req[Xip]),
|
||||||
|
.we_i (slave_we[Xip]),
|
||||||
|
.be_i (slave_be[Xip]),
|
||||||
|
.addr_i (slave_addr[Xip]),
|
||||||
|
.data_i (slave_wdata[Xip]),
|
||||||
|
.gnt_o (slave_gnt[Xip]),
|
||||||
|
.rvalid_o (slave_rvalid[Xip]),
|
||||||
|
.data_o (slave_rdata[Xip])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Bootrom] = `BOOTROM_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Bootrom] = `BOOTROM_ADDR_BASE;
|
||||||
|
// 16.bootrom模块
|
||||||
|
bootrom_top bootrom(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.req_i (slave_req[Bootrom]),
|
||||||
|
.we_i (slave_we[Bootrom]),
|
||||||
|
.be_i (slave_be[Bootrom]),
|
||||||
|
.addr_i (slave_addr[Bootrom]),
|
||||||
|
.data_i (slave_wdata[Bootrom]),
|
||||||
|
.gnt_o (slave_gnt[Bootrom]),
|
||||||
|
.rvalid_o(slave_rvalid[Bootrom]),
|
||||||
|
.data_o (slave_rdata[Bootrom])
|
||||||
|
);
|
||||||
|
|
||||||
|
// 内部总线
|
||||||
|
obi_interconnect #(
|
||||||
|
.MASTERS(MASTERS),
|
||||||
|
.SLAVES(SLAVES)
|
||||||
|
) bus (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.master_req_i (master_req),
|
||||||
|
.master_gnt_o (master_gnt),
|
||||||
|
.master_rvalid_o (master_rvalid),
|
||||||
|
.master_we_i (master_we),
|
||||||
|
.master_be_i (master_be),
|
||||||
|
.master_addr_i (master_addr),
|
||||||
|
.master_wdata_i (master_wdata),
|
||||||
|
.master_rdata_o (master_rdata),
|
||||||
|
.slave_addr_mask_i (slave_addr_mask),
|
||||||
|
.slave_addr_base_i (slave_addr_base),
|
||||||
|
.slave_req_o (slave_req),
|
||||||
|
.slave_gnt_i (slave_gnt),
|
||||||
|
.slave_rvalid_i (slave_rvalid),
|
||||||
|
.slave_we_o (slave_we),
|
||||||
|
.slave_be_o (slave_be),
|
||||||
|
.slave_addr_o (slave_addr),
|
||||||
|
.slave_wdata_o (slave_wdata),
|
||||||
|
.slave_rdata_i (slave_rdata)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign clk = clk_12m_i;
|
||||||
|
|
||||||
|
// 复位信号产生
|
||||||
|
rst_gen #(
|
||||||
|
.RESET_FIFO_DEPTH(5)
|
||||||
|
) u_rst (
|
||||||
|
.clk (clk),
|
||||||
|
.rst_ni (rst_ext_n & (~ndmreset)),
|
||||||
|
.rst_no (ndmreset_n)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[JtagDevice] = `DEBUG_ADDR_MASK;
|
||||||
|
assign slave_addr_base[JtagDevice] = `DEBUG_ADDR_BASE;
|
||||||
|
// JTAG模块
|
||||||
|
jtag_top #(
|
||||||
|
|
||||||
|
) u_jtag (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (rst_ext_n),
|
||||||
|
.debug_req_o (debug_req),
|
||||||
|
.ndmreset_o (ndmreset),
|
||||||
|
.halted_o (core_halted),
|
||||||
|
.jtag_tck_i (jtag_TCK_pin),
|
||||||
|
.jtag_tdi_i (jtag_TDI_pin),
|
||||||
|
.jtag_tms_i (jtag_TMS_pin),
|
||||||
|
.jtag_trst_ni (rst_ext_n),
|
||||||
|
.jtag_tdo_o (jtag_TDO_pin),
|
||||||
|
.master_req_o (master_req[JtagHost]),
|
||||||
|
.master_gnt_i (master_gnt[JtagHost]),
|
||||||
|
.master_rvalid_i (master_rvalid[JtagHost]),
|
||||||
|
.master_we_o (master_we[JtagHost]),
|
||||||
|
.master_be_o (master_be[JtagHost]),
|
||||||
|
.master_addr_o (master_addr[JtagHost]),
|
||||||
|
.master_wdata_o (master_wdata[JtagHost]),
|
||||||
|
.master_rdata_i (master_rdata[JtagHost]),
|
||||||
|
.master_err_i (1'b0),
|
||||||
|
.slave_req_i (slave_req[JtagDevice]),
|
||||||
|
.slave_we_i (slave_we[JtagDevice]),
|
||||||
|
.slave_addr_i (slave_addr[JtagDevice]),
|
||||||
|
.slave_be_i (slave_be[JtagDevice]),
|
||||||
|
.slave_wdata_i (slave_wdata[JtagDevice]),
|
||||||
|
.slave_gnt_o (slave_gnt[JtagDevice]),
|
||||||
|
.slave_rvalid_o (slave_rvalid[JtagDevice]),
|
||||||
|
.slave_rdata_o (slave_rdata[JtagDevice])
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,7 @@
|
||||||
|
out/
|
||||||
|
.Xil/
|
||||||
|
*.log
|
||||||
|
*.html
|
||||||
|
*.xml
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
VIVADO_BASE := /home/ubuntu/Xilinx/Vivado/2018.1/bin
|
||||||
|
VIVADO := $(VIVADO_BASE)/vivado
|
||||||
|
|
||||||
|
VIVADOFLAGS := \
|
||||||
|
-nojournal -mode batch \
|
||||||
|
-source scripts/init.tcl
|
||||||
|
|
||||||
|
.PHONY: synth
|
||||||
|
synth:
|
||||||
|
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl
|
||||||
|
|
||||||
|
.PHONY: impl
|
||||||
|
impl:
|
||||||
|
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl
|
||||||
|
|
||||||
|
.PHONY: bit
|
||||||
|
bit:
|
||||||
|
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl -source scripts/bit_stream.tcl -source scripts/report.tcl
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean::
|
||||||
|
rm -rf .Xil .ip_user_files *.log *.jou out usage_statistics_webtalk.xml usage_statistics_webtalk.html
|
|
@ -0,0 +1,16 @@
|
||||||
|
本目录包含FPGA约束文件,vivado tcl脚本和顶层文件。
|
||||||
|
|
||||||
|
```
|
||||||
|
constrs:包含FPGA约束文件
|
||||||
|
scripts:包含vivado tcl脚本
|
||||||
|
tinyriscv_soc_top.sv:整个SOC的顶层文件
|
||||||
|
```
|
||||||
|
|
||||||
|
根据vivado的安装路径,修改Makefile文件。
|
||||||
|
|
||||||
|
生成bit文件:
|
||||||
|
|
||||||
|
`make bit`
|
||||||
|
|
||||||
|
即可在out目录下生成bit文件。
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
|
||||||
|
# 时钟引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports clk_50m_i]
|
||||||
|
set_property PACKAGE_PIN N14 [get_ports clk_50m_i]
|
||||||
|
|
||||||
|
# 时钟约束50MHz
|
||||||
|
create_clock -add -name SYS_CLK -period 20.00 [get_ports clk_50m_i]
|
||||||
|
|
||||||
|
# 复位引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports rst_ext_ni]
|
||||||
|
set_property PACKAGE_PIN L13 [get_ports rst_ext_ni]
|
||||||
|
|
||||||
|
# CPU停住指示引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports halted_ind_pin]
|
||||||
|
set_property PACKAGE_PIN P15 [get_ports halted_ind_pin]
|
||||||
|
|
||||||
|
# 串口发送引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[0]}]
|
||||||
|
set_property PACKAGE_PIN M6 [get_ports {io_pins[0]}]
|
||||||
|
|
||||||
|
# 串口接收引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[3]}]
|
||||||
|
set_property PACKAGE_PIN N6 [get_ports {io_pins[3]}]
|
||||||
|
|
||||||
|
# I2C0 SCL引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[6]}]
|
||||||
|
set_property PACKAGE_PIN R10 [get_ports {io_pins[6]}]
|
||||||
|
|
||||||
|
# I2C0 SDA引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[8]}]
|
||||||
|
set_property PACKAGE_PIN R11 [get_ports {io_pins[8]}]
|
||||||
|
|
||||||
|
# SPI DQ3引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[15]}]
|
||||||
|
set_property PACKAGE_PIN T14 [get_ports {io_pins[15]}]
|
||||||
|
|
||||||
|
# SPI DQ2引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[14]}]
|
||||||
|
set_property PACKAGE_PIN R16 [get_ports {io_pins[14]}]
|
||||||
|
|
||||||
|
# SPI DQ1引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[13]}]
|
||||||
|
set_property PACKAGE_PIN R15 [get_ports {io_pins[13]}]
|
||||||
|
|
||||||
|
# SPI DQ0引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[12]}]
|
||||||
|
set_property PACKAGE_PIN K13 [get_ports {io_pins[12]}]
|
||||||
|
|
||||||
|
# SPI SS引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[11]}]
|
||||||
|
set_property PACKAGE_PIN L14 [get_ports {io_pins[11]}]
|
||||||
|
|
||||||
|
# SPI CLK引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[10]}]
|
||||||
|
set_property PACKAGE_PIN M14 [get_ports {io_pins[10]}]
|
||||||
|
|
||||||
|
# GPIO0引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[7]}]
|
||||||
|
set_property PACKAGE_PIN P16 [get_ports {io_pins[7]}]
|
||||||
|
|
||||||
|
# GPIO1引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[9]}]
|
||||||
|
set_property PACKAGE_PIN T15 [get_ports {io_pins[9]}]
|
||||||
|
|
||||||
|
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[2]}]
|
||||||
|
set_property PACKAGE_PIN T13 [get_ports {io_pins[2]}]
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[1]}]
|
||||||
|
set_property PACKAGE_PIN R13 [get_ports {io_pins[1]}]
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[4]}]
|
||||||
|
set_property PACKAGE_PIN R7 [get_ports {io_pins[4]}]
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[5]}]
|
||||||
|
set_property PACKAGE_PIN R6 [get_ports {io_pins[5]}]
|
||||||
|
|
||||||
|
|
||||||
|
# SPI Flash引脚
|
||||||
|
# CLK
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports flash_spi_clk_pin]
|
||||||
|
set_property PACKAGE_PIN N4 [get_ports flash_spi_clk_pin]
|
||||||
|
# SS
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports flash_spi_ss_pin]
|
||||||
|
set_property PACKAGE_PIN M5 [get_ports flash_spi_ss_pin]
|
||||||
|
# DQ0
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {flash_spi_dq_pin[0]}]
|
||||||
|
set_property PACKAGE_PIN N1 [get_ports {flash_spi_dq_pin[0]}]
|
||||||
|
# DQ1
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {flash_spi_dq_pin[1]}]
|
||||||
|
set_property PACKAGE_PIN P1 [get_ports {flash_spi_dq_pin[1]}]
|
||||||
|
# DQ2
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {flash_spi_dq_pin[2]}]
|
||||||
|
set_property PACKAGE_PIN P4 [get_ports {flash_spi_dq_pin[2]}]
|
||||||
|
# DQ3
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports {flash_spi_dq_pin[3]}]
|
||||||
|
set_property PACKAGE_PIN P3 [get_ports {flash_spi_dq_pin[3]}]
|
||||||
|
|
||||||
|
|
||||||
|
# JTAG TCK引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TCK_pin]
|
||||||
|
set_property PACKAGE_PIN N11 [get_ports jtag_TCK_pin]
|
||||||
|
|
||||||
|
# 1MHZ
|
||||||
|
#create_clock -name JTAG_CLK -period 1000 [get_ports jtag_TCK_pin]
|
||||||
|
|
||||||
|
# JTAG TMS引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TMS_pin]
|
||||||
|
set_property PACKAGE_PIN N3 [get_ports jtag_TMS_pin]
|
||||||
|
#set_input_delay -clock JTAG_CLK 500 [get_ports jtag_TMS_pin]
|
||||||
|
|
||||||
|
# JTAG TDI引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TDI_pin]
|
||||||
|
set_property PACKAGE_PIN N2 [get_ports jtag_TDI_pin]
|
||||||
|
#set_input_delay -clock JTAG_CLK 500 [get_ports jtag_TDI_pin]
|
||||||
|
|
||||||
|
# JTAG TDO引脚
|
||||||
|
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TDO_pin]
|
||||||
|
set_property PACKAGE_PIN M1 [get_ports jtag_TDO_pin]
|
||||||
|
#set_output_delay -clock JTAG_CLK 500 [get_ports jtag_TDO_pin]
|
||||||
|
|
||||||
|
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
|
||||||
|
set_property CONFIG_MODE SPIx4 [current_design]
|
||||||
|
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
write_bitstream -force [file join $outdir "${top_module}.bit"]
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
opt_design
|
||||||
|
|
||||||
|
place_design
|
||||||
|
|
||||||
|
phys_opt_design
|
||||||
|
power_opt_design
|
||||||
|
route_design
|
|
@ -0,0 +1,62 @@
|
||||||
|
set prj_name {tinyriscv}
|
||||||
|
set part_fpga {xc7a35tftg256-1}
|
||||||
|
set top_module {tinyriscv_soc_top}
|
||||||
|
|
||||||
|
set scriptsdir ./scripts
|
||||||
|
set constrsdir ./constrs
|
||||||
|
set outdir ./out
|
||||||
|
set ipdir [file join $outdir ip]
|
||||||
|
set srcdir ../../../rtl
|
||||||
|
|
||||||
|
# 在某目录下递归查找所有指定文件
|
||||||
|
proc rec_glob { basedir pattern } {
|
||||||
|
set dirlist [glob -nocomplain -directory $basedir -type d *]
|
||||||
|
set findlist [glob -nocomplain -directory $basedir $pattern]
|
||||||
|
foreach dir $dirlist {
|
||||||
|
set reclist [rec_glob $dir $pattern]
|
||||||
|
set findlist [concat $findlist $reclist]
|
||||||
|
}
|
||||||
|
return $findlist
|
||||||
|
}
|
||||||
|
|
||||||
|
# 创建工程(内存模式)
|
||||||
|
create_project -part $part_fpga -in_memory
|
||||||
|
|
||||||
|
# 创建sources_1
|
||||||
|
if {[get_filesets -quiet sources_1] eq ""} {
|
||||||
|
create_fileset -srcset sources_1
|
||||||
|
}
|
||||||
|
set src_pkg_files [rec_glob $srcdir "*pkg.sv"]
|
||||||
|
set src_verilog_files [rec_glob $srcdir "*.sv"]
|
||||||
|
set src_all_files [concat $src_pkg_files $src_verilog_files]
|
||||||
|
# 添加verilog文件
|
||||||
|
add_files -norecurse -fileset sources_1 $src_all_files
|
||||||
|
add_files -norecurse -fileset sources_1 ./tinyriscv_soc_top.sv
|
||||||
|
|
||||||
|
# 创建constrs_1
|
||||||
|
if {[get_filesets -quiet constrs_1] eq ""} {
|
||||||
|
create_fileset -constrset constrs_1
|
||||||
|
}
|
||||||
|
# 添加约束文件
|
||||||
|
add_files -norecurse -fileset constrs_1 [glob -directory $constrsdir {*.xdc}]
|
||||||
|
|
||||||
|
# 创建IP
|
||||||
|
file mkdir $ipdir
|
||||||
|
update_ip_catalog -rebuild
|
||||||
|
source [file join $scriptsdir ip.tcl]
|
||||||
|
set_property GENERATE_SYNTH_CHECKPOINT {false} [get_files -all {*.xci}]
|
||||||
|
set obj [get_ips]
|
||||||
|
generate_target all $obj
|
||||||
|
export_ip_user_files -of_objects $obj -no_script -force
|
||||||
|
read_ip [glob -directory $ipdir [file join * {*.xci}]]
|
||||||
|
|
||||||
|
# 综合
|
||||||
|
synth_design -top $top_module -include_dirs $ipdir
|
||||||
|
|
||||||
|
|
||||||
|
#set src_pkg_files [rec_glob $srcdir "*pkg.sv"]
|
||||||
|
#set src_verilog_files [rec_glob $srcdir "*.sv"]
|
||||||
|
#set src_all_files [concat $src_pkg_files $src_verilog_files]
|
||||||
|
#read_verilog -sv $src_all_files
|
||||||
|
|
||||||
|
#read_xdc ./constrs/tinyriscv.xdc
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
create_ip -name clk_wiz -vendor xilinx.com -library ip -module_name mmcm_main_clk -dir $ipdir -force
|
||||||
|
|
||||||
|
set_property -dict [list \
|
||||||
|
CONFIG.PRIM_IN_FREQ {50.000} \
|
||||||
|
CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {25.000} \
|
||||||
|
CONFIG.RESET_TYPE {ACTIVE_LOW} \
|
||||||
|
CONFIG.RESET_PORT {resetn}] \
|
||||||
|
[get_ips mmcm_main_clk]
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
set rptdir [file join $outdir report]
|
||||||
|
file mkdir $rptdir
|
||||||
|
set rptutil [file join $rptdir utilization.txt]
|
||||||
|
report_datasheet -file [file join $rptdir datasheet.txt]
|
||||||
|
report_utilization -hierarchical -file $rptutil
|
||||||
|
report_clock_utilization -file $rptutil -append
|
||||||
|
report_ram_utilization -file $rptutil -append -detail
|
||||||
|
report_timing_summary -file [file join $rptdir timing.txt] -max_paths 10
|
||||||
|
report_high_fanout_nets -file [file join $rptdir fanout.txt] -timing -load_types -max_nets 25
|
||||||
|
report_drc -file [file join $rptdir drc.txt]
|
||||||
|
report_io -file [file join $rptdir io.txt]
|
||||||
|
report_clocks -file [file join $rptdir clocks.txt]
|
|
@ -0,0 +1,52 @@
|
||||||
|
proc recglob { basedir pattern } {
|
||||||
|
set dirlist [glob -nocomplain -directory $basedir -type d *]
|
||||||
|
set findlist [glob -nocomplain -directory $basedir $pattern]
|
||||||
|
foreach dir $dirlist {
|
||||||
|
set reclist [recglob $dir $pattern]
|
||||||
|
set findlist [concat $findlist $reclist]
|
||||||
|
}
|
||||||
|
return $findlist
|
||||||
|
}
|
||||||
|
|
||||||
|
proc findincludedir { basedir pattern } {
|
||||||
|
#find all subdirectories containing ".vh" files
|
||||||
|
set vhfiles [recglob $basedir $pattern]
|
||||||
|
set vhdirs {}
|
||||||
|
foreach match $vhfiles {
|
||||||
|
lappend vhdirs [file dir $match]
|
||||||
|
}
|
||||||
|
set uniquevhdirs [lsort -unique $vhdirs]
|
||||||
|
return $uniquevhdirs
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
file mkdir $ipdir
|
||||||
|
|
||||||
|
source [file join $scriptsdir ip.tcl]
|
||||||
|
|
||||||
|
update_ip_catalog -rebuild
|
||||||
|
|
||||||
|
set obj [get_ips]
|
||||||
|
generate_target all $obj
|
||||||
|
|
||||||
|
read_ip [glob -directory $ipdir [file join * {*.xci}]]
|
||||||
|
|
||||||
|
|
||||||
|
# AR 58526 <http://www.xilinx.com/support/answers/58526.html>
|
||||||
|
set_property GENERATE_SYNTH_CHECKPOINT {false} [get_files -all {*.xci}]
|
||||||
|
set obj [get_ips]
|
||||||
|
generate_target all $obj
|
||||||
|
export_ip_user_files -of_objects $obj -no_script -force
|
||||||
|
|
||||||
|
set obj [current_fileset]
|
||||||
|
|
||||||
|
# Xilinx bug workaround
|
||||||
|
# scrape IP tree for directories containing .vh files
|
||||||
|
# [get_property include_dirs] misses all IP core subdirectory includes if user has specified -dir flag in create_ip
|
||||||
|
set property_include_dirs [get_property include_dirs $obj]
|
||||||
|
set ip_include_dirs [concat $property_include_dirs [findincludedir $ipdir "*.vh"]]
|
||||||
|
set ip_include_dirs [concat $ip_include_dirs [findincludedir $srcdir "*.h"]]
|
||||||
|
set ip_include_dirs [concat $ip_include_dirs [findincludedir $srcdir "*.vh"]]
|
||||||
|
|
||||||
|
|
||||||
|
synth_design -top $top_module -include_dirs $ipdir
|
|
@ -0,0 +1,674 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "../../../rtl/core/defines.sv"
|
||||||
|
`include "../../../rtl/debug/jtag_def.sv"
|
||||||
|
|
||||||
|
// tinyriscv soc顶层模块
|
||||||
|
module tinyriscv_soc_top #(
|
||||||
|
parameter bit TRACE_ENABLE = 1'b0,
|
||||||
|
parameter int GPIO_NUM = 16,
|
||||||
|
parameter int I2C_NUM = 2,
|
||||||
|
parameter int UART_NUM = 3,
|
||||||
|
parameter int SPI_NUM = 1
|
||||||
|
)(
|
||||||
|
input wire clk_50m_i, // 时钟引脚
|
||||||
|
input wire rst_ext_ni, // 复位引脚,低电平有效
|
||||||
|
|
||||||
|
output wire halted_ind_pin, // jtag是否已经halt住CPU,高电平有效
|
||||||
|
|
||||||
|
inout wire[GPIO_NUM-1:0] io_pins, // IO引脚,1bit代表一个IO
|
||||||
|
|
||||||
|
output wire flash_spi_clk_pin, // flash spi clk引脚
|
||||||
|
output wire flash_spi_ss_pin, // flash spi ss引脚
|
||||||
|
inout wire [3:0] flash_spi_dq_pin, // flash spi dq引脚
|
||||||
|
|
||||||
|
input wire jtag_TCK_pin, // JTAG TCK引脚
|
||||||
|
input wire jtag_TMS_pin, // JTAG TMS引脚
|
||||||
|
input wire jtag_TDI_pin, // JTAG TDI引脚
|
||||||
|
output wire jtag_TDO_pin // JTAG TDO引脚
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam int MASTERS = 3; // Number of master ports
|
||||||
|
localparam int SLAVES = 16; // Number of slave ports
|
||||||
|
|
||||||
|
// masters
|
||||||
|
localparam int JtagHost = 0;
|
||||||
|
localparam int CoreD = 1;
|
||||||
|
localparam int CoreI = 2;
|
||||||
|
|
||||||
|
// slaves
|
||||||
|
localparam int Rom = 0;
|
||||||
|
localparam int Ram = 1;
|
||||||
|
localparam int JtagDevice = 2;
|
||||||
|
localparam int Timer0 = 3;
|
||||||
|
localparam int Gpio = 4;
|
||||||
|
localparam int Uart0 = 5;
|
||||||
|
localparam int Rvic = 6;
|
||||||
|
localparam int I2c0 = 7;
|
||||||
|
localparam int Spi0 = 8;
|
||||||
|
localparam int Pinmux = 9;
|
||||||
|
localparam int Uart1 = 10;
|
||||||
|
localparam int Uart2 = 11;
|
||||||
|
localparam int I2c1 = 12;
|
||||||
|
localparam int Timer1 = 13;
|
||||||
|
localparam int Timer2 = 14;
|
||||||
|
localparam int FlashCtrl = 15;
|
||||||
|
|
||||||
|
wire master_req [MASTERS];
|
||||||
|
wire master_gnt [MASTERS];
|
||||||
|
wire master_rvalid [MASTERS];
|
||||||
|
wire [31:0] master_addr [MASTERS];
|
||||||
|
wire master_we [MASTERS];
|
||||||
|
wire [ 3:0] master_be [MASTERS];
|
||||||
|
wire [31:0] master_rdata [MASTERS];
|
||||||
|
wire [31:0] master_wdata [MASTERS];
|
||||||
|
|
||||||
|
wire slave_req [SLAVES];
|
||||||
|
wire slave_gnt [SLAVES];
|
||||||
|
wire slave_rvalid [SLAVES];
|
||||||
|
wire [31:0] slave_addr [SLAVES];
|
||||||
|
wire slave_we [SLAVES];
|
||||||
|
wire [ 3:0] slave_be [SLAVES];
|
||||||
|
wire [31:0] slave_rdata [SLAVES];
|
||||||
|
wire [31:0] slave_wdata [SLAVES];
|
||||||
|
|
||||||
|
wire [31:0] slave_addr_mask [SLAVES];
|
||||||
|
wire [31:0] slave_addr_base [SLAVES];
|
||||||
|
|
||||||
|
wire clk;
|
||||||
|
wire ndmreset;
|
||||||
|
wire ndmreset_n;
|
||||||
|
wire debug_req;
|
||||||
|
wire core_halted;
|
||||||
|
|
||||||
|
reg[31:0] irq_src;
|
||||||
|
wire int_req;
|
||||||
|
wire[7:0] int_id;
|
||||||
|
|
||||||
|
wire timer0_irq;
|
||||||
|
wire timer1_irq;
|
||||||
|
wire timer2_irq;
|
||||||
|
wire uart0_irq;
|
||||||
|
wire uart1_irq;
|
||||||
|
wire uart2_irq;
|
||||||
|
wire gpio0_irq;
|
||||||
|
wire gpio1_irq;
|
||||||
|
wire i2c0_irq;
|
||||||
|
wire i2c1_irq;
|
||||||
|
wire spi0_irq;
|
||||||
|
wire gpio2_4_irq;
|
||||||
|
wire gpio5_7_irq;
|
||||||
|
wire gpio8_irq;
|
||||||
|
wire gpio9_irq;
|
||||||
|
wire gpio10_12_irq;
|
||||||
|
wire gpio13_15_irq;
|
||||||
|
|
||||||
|
wire[GPIO_NUM-1:0] gpio_data_in;
|
||||||
|
wire[GPIO_NUM-1:0] gpio_oe;
|
||||||
|
wire[GPIO_NUM-1:0] gpio_data_out;
|
||||||
|
|
||||||
|
wire[GPIO_NUM-1:0] io_data_in;
|
||||||
|
wire[GPIO_NUM-1:0] io_oe;
|
||||||
|
wire[GPIO_NUM-1:0] io_data_out;
|
||||||
|
|
||||||
|
wire[I2C_NUM-1:0] i2c_scl_in;
|
||||||
|
wire[I2C_NUM-1:0] i2c_scl_oe;
|
||||||
|
wire[I2C_NUM-1:0] i2c_scl_out;
|
||||||
|
wire[I2C_NUM-1:0] i2c_sda_in;
|
||||||
|
wire[I2C_NUM-1:0] i2c_sda_oe;
|
||||||
|
wire[I2C_NUM-1:0] i2c_sda_out;
|
||||||
|
|
||||||
|
wire[UART_NUM-1:0] uart_tx;
|
||||||
|
wire[UART_NUM-1:0] uart_rx;
|
||||||
|
|
||||||
|
wire[SPI_NUM-1:0] spi_clk_in;
|
||||||
|
wire[SPI_NUM-1:0] spi_clk_oe;
|
||||||
|
wire[SPI_NUM-1:0] spi_clk_out;
|
||||||
|
wire[SPI_NUM-1:0] spi_ss_in;
|
||||||
|
wire[SPI_NUM-1:0] spi_ss_oe;
|
||||||
|
wire[SPI_NUM-1:0] spi_ss_out;
|
||||||
|
wire[3:0] spi_dq_in[SPI_NUM-1:0];
|
||||||
|
wire[3:0] spi_dq_oe[SPI_NUM-1:0];
|
||||||
|
wire[3:0] spi_dq_out[SPI_NUM-1:0];
|
||||||
|
|
||||||
|
wire[31:0] core_instr_addr;
|
||||||
|
wire[31:0] core_data_addr;
|
||||||
|
|
||||||
|
wire[3:0] flash_spi_dq_in;
|
||||||
|
wire[3:0] flash_spi_dq_oe;
|
||||||
|
wire[3:0] flash_spi_dq_out;
|
||||||
|
|
||||||
|
// 中断源
|
||||||
|
always @ (*) begin
|
||||||
|
irq_src = 32'h0;
|
||||||
|
irq_src[ 0] = timer0_irq;
|
||||||
|
irq_src[ 1] = uart0_irq;
|
||||||
|
irq_src[ 2] = gpio0_irq;
|
||||||
|
irq_src[ 3] = gpio1_irq;
|
||||||
|
irq_src[ 4] = i2c0_irq;
|
||||||
|
irq_src[ 5] = spi0_irq;
|
||||||
|
irq_src[ 6] = gpio2_4_irq;
|
||||||
|
irq_src[ 7] = gpio5_7_irq;
|
||||||
|
irq_src[ 8] = gpio8_irq;
|
||||||
|
irq_src[ 9] = gpio9_irq;
|
||||||
|
irq_src[10] = gpio10_12_irq;
|
||||||
|
irq_src[11] = gpio13_15_irq;
|
||||||
|
irq_src[12] = uart1_irq;
|
||||||
|
irq_src[13] = uart2_irq;
|
||||||
|
irq_src[14] = i2c1_irq;
|
||||||
|
irq_src[15] = timer1_irq;
|
||||||
|
irq_src[16] = timer2_irq;
|
||||||
|
end
|
||||||
|
|
||||||
|
// FPGA低电平点亮LED
|
||||||
|
assign halted_ind_pin = ~core_halted;
|
||||||
|
|
||||||
|
tinyriscv_core #(
|
||||||
|
.DEBUG_HALT_ADDR(`DEBUG_ADDR_BASE + `HaltAddress),
|
||||||
|
.DEBUG_EXCEPTION_ADDR(`DEBUG_ADDR_BASE + `ExceptionAddress),
|
||||||
|
.BranchPredictor(1'b1),
|
||||||
|
.TRACE_ENABLE(TRACE_ENABLE)
|
||||||
|
) u_tinyriscv_core (
|
||||||
|
.clk (clk),
|
||||||
|
.rst_n (ndmreset_n),
|
||||||
|
|
||||||
|
.instr_req_o (master_req[CoreI]),
|
||||||
|
.instr_gnt_i (master_gnt[CoreI]),
|
||||||
|
.instr_rvalid_i (master_rvalid[CoreI]),
|
||||||
|
.instr_addr_o (core_instr_addr),
|
||||||
|
.instr_rdata_i (master_rdata[CoreI]),
|
||||||
|
.instr_err_i (1'b0),
|
||||||
|
|
||||||
|
.data_req_o (master_req[CoreD]),
|
||||||
|
.data_gnt_i (master_gnt[CoreD]),
|
||||||
|
.data_rvalid_i (master_rvalid[CoreD]),
|
||||||
|
.data_we_o (master_we[CoreD]),
|
||||||
|
.data_be_o (master_be[CoreD]),
|
||||||
|
.data_addr_o (core_data_addr),
|
||||||
|
.data_wdata_o (master_wdata[CoreD]),
|
||||||
|
.data_rdata_i (master_rdata[CoreD]),
|
||||||
|
.data_err_i (1'b0),
|
||||||
|
|
||||||
|
.int_req_i (int_req),
|
||||||
|
.int_id_i (int_id),
|
||||||
|
|
||||||
|
.debug_req_i (debug_req)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 是否访问flash
|
||||||
|
wire instr_access_flash;
|
||||||
|
wire data_access_flash;
|
||||||
|
|
||||||
|
assign instr_access_flash = ((core_instr_addr & (`FLASH_ADDR_MASK)) == `FLASH_ADDR_BASE);
|
||||||
|
assign data_access_flash = ((core_data_addr & (`FLASH_ADDR_MASK)) == `FLASH_ADDR_BASE);
|
||||||
|
|
||||||
|
// 转换后的地址
|
||||||
|
wire [31:0] instr_tran_addr;
|
||||||
|
wire [31:0] data_tran_addr;
|
||||||
|
|
||||||
|
assign instr_tran_addr = (core_instr_addr & (~(`FLASH_CTRL_ADDR_MASK))) | `FLASH_CTRL_ADDR_BASE;
|
||||||
|
assign data_tran_addr = (core_data_addr & (~(`FLASH_CTRL_ADDR_MASK))) | `FLASH_CTRL_ADDR_BASE;
|
||||||
|
|
||||||
|
// 当访问flash空间时,转去访问flash ctrl模块
|
||||||
|
assign master_addr[CoreI] = instr_access_flash ? ({instr_tran_addr[31:24], 1'b1, instr_tran_addr[22:0]}) :
|
||||||
|
core_instr_addr;
|
||||||
|
assign master_addr[CoreD] = data_access_flash ? ({data_tran_addr[31:24], 1'b1, data_tran_addr[22:0]}) :
|
||||||
|
core_data_addr;
|
||||||
|
|
||||||
|
assign slave_addr_mask[Rom] = `ROM_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Rom] = `ROM_ADDR_BASE;
|
||||||
|
// 1.指令存储器
|
||||||
|
rom #(
|
||||||
|
.DP(`ROM_DEPTH)
|
||||||
|
) u_rom (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.req_i (slave_req[Rom]),
|
||||||
|
.addr_i (slave_addr[Rom]),
|
||||||
|
.data_i (slave_wdata[Rom]),
|
||||||
|
.be_i (slave_be[Rom]),
|
||||||
|
.we_i (slave_we[Rom]),
|
||||||
|
.gnt_o (slave_gnt[Rom]),
|
||||||
|
.rvalid_o (slave_rvalid[Rom]),
|
||||||
|
.data_o (slave_rdata[Rom])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Ram] = `RAM_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Ram] = `RAM_ADDR_BASE;
|
||||||
|
// 2.数据存储器
|
||||||
|
ram #(
|
||||||
|
.DP(`RAM_DEPTH)
|
||||||
|
) u_ram (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.req_i (slave_req[Ram]),
|
||||||
|
.addr_i (slave_addr[Ram]),
|
||||||
|
.data_i (slave_wdata[Ram]),
|
||||||
|
.be_i (slave_be[Ram]),
|
||||||
|
.we_i (slave_we[Ram]),
|
||||||
|
.gnt_o (slave_gnt[Ram]),
|
||||||
|
.rvalid_o (slave_rvalid[Ram]),
|
||||||
|
.data_o (slave_rdata[Ram])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Timer0] = `TIMER0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Timer0] = `TIMER0_ADDR_BASE;
|
||||||
|
// 3.定时器0模块
|
||||||
|
timer_top timer0(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.irq_o (timer0_irq),
|
||||||
|
.req_i (slave_req[Timer0]),
|
||||||
|
.we_i (slave_we[Timer0]),
|
||||||
|
.be_i (slave_be[Timer0]),
|
||||||
|
.addr_i (slave_addr[Timer0]),
|
||||||
|
.data_i (slave_wdata[Timer0]),
|
||||||
|
.gnt_o (slave_gnt[Timer0]),
|
||||||
|
.rvalid_o(slave_rvalid[Timer0]),
|
||||||
|
.data_o (slave_rdata[Timer0])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Timer1] = `TIMER1_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Timer1] = `TIMER1_ADDR_BASE;
|
||||||
|
// 4.定时器1模块
|
||||||
|
timer_top timer1(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.irq_o (timer1_irq),
|
||||||
|
.req_i (slave_req[Timer1]),
|
||||||
|
.we_i (slave_we[Timer1]),
|
||||||
|
.be_i (slave_be[Timer1]),
|
||||||
|
.addr_i (slave_addr[Timer1]),
|
||||||
|
.data_i (slave_wdata[Timer1]),
|
||||||
|
.gnt_o (slave_gnt[Timer1]),
|
||||||
|
.rvalid_o(slave_rvalid[Timer1]),
|
||||||
|
.data_o (slave_rdata[Timer1])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Timer2] = `TIMER2_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Timer2] = `TIMER2_ADDR_BASE;
|
||||||
|
// 5.定时器2模块
|
||||||
|
timer_top timer2(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.irq_o (timer2_irq),
|
||||||
|
.req_i (slave_req[Timer2]),
|
||||||
|
.we_i (slave_we[Timer2]),
|
||||||
|
.be_i (slave_be[Timer2]),
|
||||||
|
.addr_i (slave_addr[Timer2]),
|
||||||
|
.data_i (slave_wdata[Timer2]),
|
||||||
|
.gnt_o (slave_gnt[Timer2]),
|
||||||
|
.rvalid_o(slave_rvalid[Timer2]),
|
||||||
|
.data_o (slave_rdata[Timer2])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Gpio] = `GPIO_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Gpio] = `GPIO_ADDR_BASE;
|
||||||
|
// 6.GPIO模块
|
||||||
|
gpio_top #(
|
||||||
|
.GPIO_NUM(GPIO_NUM)
|
||||||
|
) u_gpio (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.gpio_oe_o (gpio_oe),
|
||||||
|
.gpio_data_o (gpio_data_out),
|
||||||
|
.gpio_data_i (gpio_data_in),
|
||||||
|
.irq_gpio0_o (gpio0_irq),
|
||||||
|
.irq_gpio1_o (gpio1_irq),
|
||||||
|
.irq_gpio2_4_o (gpio2_4_irq),
|
||||||
|
.irq_gpio5_7_o (gpio5_7_irq),
|
||||||
|
.irq_gpio8_o (gpio8_irq),
|
||||||
|
.irq_gpio9_o (gpio9_irq),
|
||||||
|
.irq_gpio10_12_o(gpio10_12_irq),
|
||||||
|
.irq_gpio13_15_o(gpio13_15_irq),
|
||||||
|
.req_i (slave_req[Gpio]),
|
||||||
|
.we_i (slave_we[Gpio]),
|
||||||
|
.be_i (slave_be[Gpio]),
|
||||||
|
.addr_i (slave_addr[Gpio]),
|
||||||
|
.data_i (slave_wdata[Gpio]),
|
||||||
|
.gnt_o (slave_gnt[Gpio]),
|
||||||
|
.rvalid_o (slave_rvalid[Gpio]),
|
||||||
|
.data_o (slave_rdata[Gpio])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Uart0] = `UART0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Uart0] = `UART0_ADDR_BASE;
|
||||||
|
// 7.串口0模块
|
||||||
|
uart_top uart0 (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.rx_i (uart_rx[0]),
|
||||||
|
.tx_o (uart_tx[0]),
|
||||||
|
.irq_o (uart0_irq),
|
||||||
|
.req_i (slave_req[Uart0]),
|
||||||
|
.we_i (slave_we[Uart0]),
|
||||||
|
.be_i (slave_be[Uart0]),
|
||||||
|
.addr_i (slave_addr[Uart0]),
|
||||||
|
.data_i (slave_wdata[Uart0]),
|
||||||
|
.gnt_o (slave_gnt[Uart0]),
|
||||||
|
.rvalid_o (slave_rvalid[Uart0]),
|
||||||
|
.data_o (slave_rdata[Uart0])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Uart1] = `UART1_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Uart1] = `UART1_ADDR_BASE;
|
||||||
|
// 8.串口1模块
|
||||||
|
uart_top uart1 (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.rx_i (uart_rx[1]),
|
||||||
|
.tx_o (uart_tx[1]),
|
||||||
|
.irq_o (uart1_irq),
|
||||||
|
.req_i (slave_req[Uart1]),
|
||||||
|
.we_i (slave_we[Uart1]),
|
||||||
|
.be_i (slave_be[Uart1]),
|
||||||
|
.addr_i (slave_addr[Uart1]),
|
||||||
|
.data_i (slave_wdata[Uart1]),
|
||||||
|
.gnt_o (slave_gnt[Uart1]),
|
||||||
|
.rvalid_o (slave_rvalid[Uart1]),
|
||||||
|
.data_o (slave_rdata[Uart1])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Uart2] = `UART2_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Uart2] = `UART2_ADDR_BASE;
|
||||||
|
// 9.串口2模块
|
||||||
|
uart_top uart2 (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.rx_i (uart_rx[2]),
|
||||||
|
.tx_o (uart_tx[2]),
|
||||||
|
.irq_o (uart2_irq),
|
||||||
|
.req_i (slave_req[Uart2]),
|
||||||
|
.we_i (slave_we[Uart2]),
|
||||||
|
.be_i (slave_be[Uart2]),
|
||||||
|
.addr_i (slave_addr[Uart2]),
|
||||||
|
.data_i (slave_wdata[Uart2]),
|
||||||
|
.gnt_o (slave_gnt[Uart2]),
|
||||||
|
.rvalid_o (slave_rvalid[Uart2]),
|
||||||
|
.data_o (slave_rdata[Uart2])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Rvic] = `RVIC_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Rvic] = `RVIC_ADDR_BASE;
|
||||||
|
// 10.中断控制器模块
|
||||||
|
rvic_top u_rvic(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.src_i (irq_src),
|
||||||
|
.irq_o (int_req),
|
||||||
|
.irq_id_o (int_id),
|
||||||
|
.req_i (slave_req[Rvic]),
|
||||||
|
.we_i (slave_we[Rvic]),
|
||||||
|
.be_i (slave_be[Rvic]),
|
||||||
|
.addr_i (slave_addr[Rvic]),
|
||||||
|
.data_i (slave_wdata[Rvic]),
|
||||||
|
.gnt_o (slave_gnt[Rvic]),
|
||||||
|
.rvalid_o (slave_rvalid[Rvic]),
|
||||||
|
.data_o (slave_rdata[Rvic])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[I2c0] = `I2C0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[I2c0] = `I2C0_ADDR_BASE;
|
||||||
|
// 11.I2C0模块
|
||||||
|
i2c_top i2c0(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.scl_o (i2c_scl_out[0]),
|
||||||
|
.scl_oe_o (i2c_scl_oe[0]),
|
||||||
|
.scl_i (i2c_scl_in[0]),
|
||||||
|
.sda_o (i2c_sda_out[0]),
|
||||||
|
.sda_oe_o (i2c_sda_oe[0]),
|
||||||
|
.sda_i (i2c_sda_in[0]),
|
||||||
|
.irq_o (i2c0_irq),
|
||||||
|
.req_i (slave_req[I2c0]),
|
||||||
|
.we_i (slave_we[I2c0]),
|
||||||
|
.be_i (slave_be[I2c0]),
|
||||||
|
.addr_i (slave_addr[I2c0]),
|
||||||
|
.data_i (slave_wdata[I2c0]),
|
||||||
|
.gnt_o (slave_gnt[I2c0]),
|
||||||
|
.rvalid_o (slave_rvalid[I2c0]),
|
||||||
|
.data_o (slave_rdata[I2c0])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[I2c1] = `I2C1_ADDR_MASK;
|
||||||
|
assign slave_addr_base[I2c1] = `I2C1_ADDR_BASE;
|
||||||
|
// 12.I2C1模块
|
||||||
|
i2c_top i2c1(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.scl_o (i2c_scl_out[1]),
|
||||||
|
.scl_oe_o (i2c_scl_oe[1]),
|
||||||
|
.scl_i (i2c_scl_in[1]),
|
||||||
|
.sda_o (i2c_sda_out[1]),
|
||||||
|
.sda_oe_o (i2c_sda_oe[1]),
|
||||||
|
.sda_i (i2c_sda_in[1]),
|
||||||
|
.irq_o (i2c1_irq),
|
||||||
|
.req_i (slave_req[I2c1]),
|
||||||
|
.we_i (slave_we[I2c1]),
|
||||||
|
.be_i (slave_be[I2c1]),
|
||||||
|
.addr_i (slave_addr[I2c1]),
|
||||||
|
.data_i (slave_wdata[I2c1]),
|
||||||
|
.gnt_o (slave_gnt[I2c1]),
|
||||||
|
.rvalid_o (slave_rvalid[I2c1]),
|
||||||
|
.data_o (slave_rdata[I2c1])
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[Spi0] = `SPI0_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Spi0] = `SPI0_ADDR_BASE;
|
||||||
|
// 13.SPI0模块
|
||||||
|
spi_top spi0(
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.spi_clk_i (spi_clk_in[0]),
|
||||||
|
.spi_clk_o (spi_clk_out[0]),
|
||||||
|
.spi_clk_oe_o(spi_clk_oe[0]),
|
||||||
|
.spi_ss_i (spi_ss_in[0]),
|
||||||
|
.spi_ss_o (spi_ss_out[0]),
|
||||||
|
.spi_ss_oe_o(spi_ss_oe[0]),
|
||||||
|
.spi_dq0_i (spi_dq_in[0][0]),
|
||||||
|
.spi_dq0_o (spi_dq_out[0][0]),
|
||||||
|
.spi_dq0_oe_o(spi_dq_oe[0][0]),
|
||||||
|
.spi_dq1_i (spi_dq_in[0][1]),
|
||||||
|
.spi_dq1_o (spi_dq_out[0][1]),
|
||||||
|
.spi_dq1_oe_o(spi_dq_oe[0][1]),
|
||||||
|
.spi_dq2_i (spi_dq_in[0][2]),
|
||||||
|
.spi_dq2_o (spi_dq_out[0][2]),
|
||||||
|
.spi_dq2_oe_o(spi_dq_oe[0][2]),
|
||||||
|
.spi_dq3_i (spi_dq_in[0][3]),
|
||||||
|
.spi_dq3_o (spi_dq_out[0][3]),
|
||||||
|
.spi_dq3_oe_o(spi_dq_oe[0][3]),
|
||||||
|
.irq_o (spi0_irq),
|
||||||
|
.req_i (slave_req[Spi0]),
|
||||||
|
.we_i (slave_we[Spi0]),
|
||||||
|
.be_i (slave_be[Spi0]),
|
||||||
|
.addr_i (slave_addr[Spi0]),
|
||||||
|
.data_i (slave_wdata[Spi0]),
|
||||||
|
.gnt_o (slave_gnt[Spi0]),
|
||||||
|
.rvalid_o (slave_rvalid[Spi0]),
|
||||||
|
.data_o (slave_rdata[Spi0])
|
||||||
|
);
|
||||||
|
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_io_data
|
||||||
|
assign io_pins[i] = io_oe[i] ? io_data_out[i] : 1'bz;
|
||||||
|
assign io_data_in[i] = io_pins[i];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign slave_addr_mask[Pinmux] = `PINMUX_ADDR_MASK;
|
||||||
|
assign slave_addr_base[Pinmux] = `PINMUX_ADDR_BASE;
|
||||||
|
// 14.PINMUX模块
|
||||||
|
pinmux_top #(
|
||||||
|
.GPIO_NUM(GPIO_NUM),
|
||||||
|
.I2C_NUM(I2C_NUM),
|
||||||
|
.UART_NUM(UART_NUM),
|
||||||
|
.SPI_NUM(SPI_NUM)
|
||||||
|
) u_pinmux (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.gpio_oe_i (gpio_oe),
|
||||||
|
.gpio_val_i (gpio_data_out),
|
||||||
|
.gpio_val_o (gpio_data_in),
|
||||||
|
.i2c_sda_oe_i (i2c_sda_oe),
|
||||||
|
.i2c_sda_val_i (i2c_sda_out),
|
||||||
|
.i2c_sda_val_o (i2c_sda_in),
|
||||||
|
.i2c_scl_oe_i (i2c_scl_oe),
|
||||||
|
.i2c_scl_val_i (i2c_scl_out),
|
||||||
|
.i2c_scl_val_o (i2c_scl_in),
|
||||||
|
.uart_tx_oe_i ({UART_NUM{1'b1}}),
|
||||||
|
.uart_tx_val_i (uart_tx),
|
||||||
|
.uart_tx_val_o (),
|
||||||
|
.uart_rx_oe_i ({UART_NUM{1'b0}}),
|
||||||
|
.uart_rx_val_i (),
|
||||||
|
.uart_rx_val_o (uart_rx),
|
||||||
|
.spi_clk_oe_i (spi_clk_oe),
|
||||||
|
.spi_clk_val_i (spi_clk_out),
|
||||||
|
.spi_clk_val_o (spi_clk_in),
|
||||||
|
.spi_ss_oe_i (spi_ss_oe),
|
||||||
|
.spi_ss_val_i (spi_ss_out),
|
||||||
|
.spi_ss_val_o (spi_ss_in),
|
||||||
|
.spi_dq_oe_i (spi_dq_oe),
|
||||||
|
.spi_dq_val_i (spi_dq_out),
|
||||||
|
.spi_dq_val_o (spi_dq_in),
|
||||||
|
.io_val_i (io_data_in),
|
||||||
|
.io_val_o (io_data_out),
|
||||||
|
.io_oe_o (io_oe),
|
||||||
|
.req_i (slave_req[Pinmux]),
|
||||||
|
.we_i (slave_we[Pinmux]),
|
||||||
|
.be_i (slave_be[Pinmux]),
|
||||||
|
.addr_i (slave_addr[Pinmux]),
|
||||||
|
.data_i (slave_wdata[Pinmux]),
|
||||||
|
.gnt_o (slave_gnt[Pinmux]),
|
||||||
|
.rvalid_o (slave_rvalid[Pinmux]),
|
||||||
|
.data_o (slave_rdata[Pinmux])
|
||||||
|
);
|
||||||
|
|
||||||
|
for (genvar j = 0; j < 4; j = j + 1) begin : g_spi_pin_data
|
||||||
|
assign flash_spi_dq_pin[j] = flash_spi_dq_oe[j] ? flash_spi_dq_out[j] : 1'bz;
|
||||||
|
assign flash_spi_dq_in[j] = flash_spi_dq_pin[j];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign slave_addr_mask[FlashCtrl] = `FLASH_CTRL_ADDR_MASK;
|
||||||
|
assign slave_addr_base[FlashCtrl] = `FLASH_CTRL_ADDR_BASE;
|
||||||
|
// 15.flash ctrl模块
|
||||||
|
flash_ctrl_top flash_ctrl (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.spi_clk_o (flash_spi_clk_pin),
|
||||||
|
.spi_clk_oe_o (),
|
||||||
|
.spi_ss_o (flash_spi_ss_pin),
|
||||||
|
.spi_ss_oe_o (),
|
||||||
|
.spi_dq0_i (flash_spi_dq_in[0]),
|
||||||
|
.spi_dq0_o (flash_spi_dq_out[0]),
|
||||||
|
.spi_dq0_oe_o (flash_spi_dq_oe[0]),
|
||||||
|
.spi_dq1_i (flash_spi_dq_in[1]),
|
||||||
|
.spi_dq1_o (flash_spi_dq_out[1]),
|
||||||
|
.spi_dq1_oe_o (flash_spi_dq_oe[1]),
|
||||||
|
.spi_dq2_i (flash_spi_dq_in[2]),
|
||||||
|
.spi_dq2_o (flash_spi_dq_out[2]),
|
||||||
|
.spi_dq2_oe_o (flash_spi_dq_oe[2]),
|
||||||
|
.spi_dq3_i (flash_spi_dq_in[3]),
|
||||||
|
.spi_dq3_o (flash_spi_dq_out[3]),
|
||||||
|
.spi_dq3_oe_o (flash_spi_dq_oe[3]),
|
||||||
|
.req_i (slave_req[FlashCtrl]),
|
||||||
|
.we_i (slave_we[FlashCtrl]),
|
||||||
|
.be_i (slave_be[FlashCtrl]),
|
||||||
|
.addr_i (slave_addr[FlashCtrl]),
|
||||||
|
.data_i (slave_wdata[FlashCtrl]),
|
||||||
|
.gnt_o (slave_gnt[FlashCtrl]),
|
||||||
|
.rvalid_o (slave_rvalid[FlashCtrl]),
|
||||||
|
.data_o (slave_rdata[FlashCtrl])
|
||||||
|
);
|
||||||
|
|
||||||
|
// 内部总线
|
||||||
|
obi_interconnect #(
|
||||||
|
.MASTERS(MASTERS),
|
||||||
|
.SLAVES(SLAVES)
|
||||||
|
) bus (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (ndmreset_n),
|
||||||
|
.master_req_i (master_req),
|
||||||
|
.master_gnt_o (master_gnt),
|
||||||
|
.master_rvalid_o (master_rvalid),
|
||||||
|
.master_we_i (master_we),
|
||||||
|
.master_be_i (master_be),
|
||||||
|
.master_addr_i (master_addr),
|
||||||
|
.master_wdata_i (master_wdata),
|
||||||
|
.master_rdata_o (master_rdata),
|
||||||
|
.slave_addr_mask_i (slave_addr_mask),
|
||||||
|
.slave_addr_base_i (slave_addr_base),
|
||||||
|
.slave_req_o (slave_req),
|
||||||
|
.slave_gnt_i (slave_gnt),
|
||||||
|
.slave_rvalid_i (slave_rvalid),
|
||||||
|
.slave_we_o (slave_we),
|
||||||
|
.slave_be_o (slave_be),
|
||||||
|
.slave_addr_o (slave_addr),
|
||||||
|
.slave_wdata_o (slave_wdata),
|
||||||
|
.slave_rdata_i (slave_rdata)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 使用xilinx vivado中的mmcm IP进行分频
|
||||||
|
// 输入为50MHZ,输出为25MHZ
|
||||||
|
mmcm_main_clk u_mmcm_main_clk(
|
||||||
|
.clk_out1(clk),
|
||||||
|
.resetn(rst_ext_ni),
|
||||||
|
.clk_in1(clk_50m_i)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 复位信号产生
|
||||||
|
rst_gen #(
|
||||||
|
.RESET_FIFO_DEPTH(5)
|
||||||
|
) u_rst (
|
||||||
|
.clk (clk),
|
||||||
|
.rst_ni (rst_ext_ni & (~ndmreset)),
|
||||||
|
.rst_no (ndmreset_n)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign slave_addr_mask[JtagDevice] = `DEBUG_ADDR_MASK;
|
||||||
|
assign slave_addr_base[JtagDevice] = `DEBUG_ADDR_BASE;
|
||||||
|
// JTAG模块
|
||||||
|
jtag_top #(
|
||||||
|
|
||||||
|
) u_jtag (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni (rst_ext_ni),
|
||||||
|
.debug_req_o (debug_req),
|
||||||
|
.ndmreset_o (ndmreset),
|
||||||
|
.halted_o (core_halted),
|
||||||
|
.jtag_tck_i (jtag_TCK_pin),
|
||||||
|
.jtag_tdi_i (jtag_TDI_pin),
|
||||||
|
.jtag_tms_i (jtag_TMS_pin),
|
||||||
|
.jtag_trst_ni (rst_ext_ni),
|
||||||
|
.jtag_tdo_o (jtag_TDO_pin),
|
||||||
|
.master_req_o (master_req[JtagHost]),
|
||||||
|
.master_gnt_i (master_gnt[JtagHost]),
|
||||||
|
.master_rvalid_i (master_rvalid[JtagHost]),
|
||||||
|
.master_we_o (master_we[JtagHost]),
|
||||||
|
.master_be_o (master_be[JtagHost]),
|
||||||
|
.master_addr_o (master_addr[JtagHost]),
|
||||||
|
.master_wdata_o (master_wdata[JtagHost]),
|
||||||
|
.master_rdata_i (master_rdata[JtagHost]),
|
||||||
|
.master_err_i (1'b0),
|
||||||
|
.slave_req_i (slave_req[JtagDevice]),
|
||||||
|
.slave_we_i (slave_we[JtagDevice]),
|
||||||
|
.slave_addr_i (slave_addr[JtagDevice]),
|
||||||
|
.slave_be_i (slave_be[JtagDevice]),
|
||||||
|
.slave_wdata_i (slave_wdata[JtagDevice]),
|
||||||
|
.slave_gnt_o (slave_gnt[JtagDevice]),
|
||||||
|
.slave_rvalid_o (slave_rvalid[JtagDevice]),
|
||||||
|
.slave_rdata_o (slave_rdata[JtagDevice])
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
Before Width: | Height: | Size: 19 KiB |
BIN
pic/arch.jpg
Before Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1,94 @@
|
||||||
|
+incdir+../rtl/core
|
||||||
|
+incdir+../rtl/debug
|
||||||
|
|
||||||
|
../rtl/core/csr_reg.sv
|
||||||
|
../rtl/core/csr.sv
|
||||||
|
../rtl/core/defines.sv
|
||||||
|
../rtl/core/divider.sv
|
||||||
|
../rtl/core/exception.sv
|
||||||
|
../rtl/core/exu.sv
|
||||||
|
../rtl/core/exu_alu_datapath.sv
|
||||||
|
../rtl/core/exu_commit.sv
|
||||||
|
../rtl/core/exu_dispatch.sv
|
||||||
|
../rtl/core/exu_mem.sv
|
||||||
|
../rtl/core/exu_muldiv.sv
|
||||||
|
../rtl/core/gpr_reg.sv
|
||||||
|
../rtl/core/idu.sv
|
||||||
|
../rtl/core/idu_exu.sv
|
||||||
|
../rtl/core/ifu.sv
|
||||||
|
../rtl/core/ifu_idu.sv
|
||||||
|
../rtl/core/pipe_ctrl.sv
|
||||||
|
../rtl/core/rst_gen.sv
|
||||||
|
../rtl/core/tinyriscv_core.sv
|
||||||
|
../rtl/core/tracer.sv
|
||||||
|
../rtl/core/bpu.sv
|
||||||
|
|
||||||
|
../rtl/debug/jtag_def.sv
|
||||||
|
../rtl/debug/jtag_tap.sv
|
||||||
|
../rtl/debug/jtag_dtm.sv
|
||||||
|
../rtl/debug/jtag_dmi.sv
|
||||||
|
../rtl/debug/jtag_dm.sv
|
||||||
|
../rtl/debug/jtag_mem.sv
|
||||||
|
../rtl/debug/jtag_sba.sv
|
||||||
|
../rtl/debug/jtag_top.sv
|
||||||
|
../rtl/debug/debug_rom.sv
|
||||||
|
|
||||||
|
../rtl/perips/ram.sv
|
||||||
|
../rtl/perips/rom.sv
|
||||||
|
../rtl/perips/uart/uart_reg_pkg.sv
|
||||||
|
../rtl/perips/uart/uart_reg_top.sv
|
||||||
|
../rtl/perips/uart/uart_core.sv
|
||||||
|
../rtl/perips/uart/uart_rx.sv
|
||||||
|
../rtl/perips/uart/uart_top.sv
|
||||||
|
../rtl/perips/uart/uart_tx.sv
|
||||||
|
../rtl/perips/timer/timer_reg_pkg.sv
|
||||||
|
../rtl/perips/timer/timer_reg_top.sv
|
||||||
|
../rtl/perips/timer/timer_core.sv
|
||||||
|
../rtl/perips/timer/timer_top.sv
|
||||||
|
../rtl/perips/gpio/gpio_reg_pkg.sv
|
||||||
|
../rtl/perips/gpio/gpio_reg_top.sv
|
||||||
|
../rtl/perips/gpio/gpio_core.sv
|
||||||
|
../rtl/perips/gpio/gpio_top.sv
|
||||||
|
../rtl/perips/rvic/rvic_reg_pkg.sv
|
||||||
|
../rtl/perips/rvic/rvic_reg_top.sv
|
||||||
|
../rtl/perips/rvic/rvic_core.sv
|
||||||
|
../rtl/perips/rvic/rvic_top.sv
|
||||||
|
../rtl/perips/i2c/i2c_reg_pkg.sv
|
||||||
|
../rtl/perips/i2c/i2c_reg_top.sv
|
||||||
|
../rtl/perips/i2c/i2c_core.sv
|
||||||
|
../rtl/perips/i2c/i2c_top.sv
|
||||||
|
../rtl/perips/i2c/i2c_master.sv
|
||||||
|
../rtl/perips/i2c/i2c_slave.sv
|
||||||
|
../rtl/perips/spi/spi_reg_pkg.sv
|
||||||
|
../rtl/perips/spi/spi_reg_top.sv
|
||||||
|
../rtl/perips/spi/spi_core.sv
|
||||||
|
../rtl/perips/spi/spi_top.sv
|
||||||
|
../rtl/perips/spi/spi_master.sv
|
||||||
|
../rtl/perips/spi/spi_transmit_byte.sv
|
||||||
|
../rtl/perips/pinmux/pinmux_reg_pkg.sv
|
||||||
|
../rtl/perips/pinmux/pinmux_reg_top.sv
|
||||||
|
../rtl/perips/pinmux/pinmux_core.sv
|
||||||
|
../rtl/perips/pinmux/pinmux_top.sv
|
||||||
|
../rtl/perips/xip/xip_top.sv
|
||||||
|
../rtl/perips/xip/xip_core.sv
|
||||||
|
../rtl/perips/xip/xip_w25q64_ctrl.sv
|
||||||
|
../rtl/perips/xip/spi_master_transmit.sv
|
||||||
|
../rtl/perips/bootrom/bootrom_top.sv
|
||||||
|
|
||||||
|
../rtl/sys_bus/obi_interconnect.sv
|
||||||
|
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
||||||
|
../rtl/sys_bus/obi_interconnect_slave_sel.sv
|
||||||
|
|
||||||
|
../rtl/utils/gen_buf.sv
|
||||||
|
../rtl/utils/gen_dff.sv
|
||||||
|
../rtl/utils/gen_ram.sv
|
||||||
|
../rtl/utils/cdc_2phase.sv
|
||||||
|
../rtl/utils/sync_fifo.sv
|
||||||
|
../rtl/utils/clk_div.sv
|
||||||
|
../rtl/utils/edge_detect.sv
|
||||||
|
../rtl/utils/prim_subreg.sv
|
||||||
|
../rtl/utils/prim_subreg_arb.sv
|
||||||
|
../rtl/utils/prim_subreg_ext.sv
|
||||||
|
../rtl/utils/prim_filter.sv
|
||||||
|
../rtl/utils/up_counter.sv
|
||||||
|
../rtl/utils/async_fifo.sv
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 静态分支预测模块
|
||||||
|
module bpu(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire[31:0] inst_i,
|
||||||
|
input wire inst_valid_i,
|
||||||
|
input wire[31:0] pc_i,
|
||||||
|
|
||||||
|
output wire prdt_taken_o,
|
||||||
|
output wire[31:0] prdt_addr_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
wire[6:0] opcode = inst_i[6:0];
|
||||||
|
|
||||||
|
wire opcode_1100011 = (opcode == 7'b1100011);
|
||||||
|
wire opcode_1101111 = (opcode == 7'b1101111);
|
||||||
|
|
||||||
|
wire inst_type_branch = opcode_1100011;
|
||||||
|
wire inst_jal = opcode_1101111;
|
||||||
|
|
||||||
|
wire[31:0] inst_b_type_imm = {{20{inst_i[31]}}, inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0};
|
||||||
|
wire[31:0] inst_j_type_imm = {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};
|
||||||
|
|
||||||
|
wire prdt_taken = (inst_type_branch & inst_b_type_imm[31]) | inst_jal;
|
||||||
|
|
||||||
|
reg[31:0] prdt_imm;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
prdt_imm = inst_b_type_imm;
|
||||||
|
|
||||||
|
case (1'b1)
|
||||||
|
inst_type_branch: prdt_imm = inst_b_type_imm;
|
||||||
|
inst_jal: prdt_imm = inst_j_type_imm;
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign prdt_taken_o = inst_valid_i ? prdt_taken : 1'b0;
|
||||||
|
assign prdt_addr_o = pc_i + prdt_imm;
|
||||||
|
|
||||||
|
endmodule
|
242
rtl/core/clint.v
|
@ -1,242 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
|
|
||||||
// core local interruptor module
|
|
||||||
// 核心中断管理、仲裁模块
|
|
||||||
module clint(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
// from core
|
|
||||||
input wire[`INT_BUS] int_flag_i, // 中断输入信号
|
|
||||||
|
|
||||||
// from id
|
|
||||||
input wire[`InstBus] inst_i, // 指令内容
|
|
||||||
input wire[`InstAddrBus] inst_addr_i, // 指令地址
|
|
||||||
|
|
||||||
// from ex
|
|
||||||
input wire jump_flag_i,
|
|
||||||
input wire[`InstAddrBus] jump_addr_i,
|
|
||||||
input wire div_started_i,
|
|
||||||
|
|
||||||
// from ctrl
|
|
||||||
input wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志
|
|
||||||
|
|
||||||
// from csr_reg
|
|
||||||
input wire[`RegBus] data_i, // CSR寄存器输入数据
|
|
||||||
input wire[`RegBus] csr_mtvec, // mtvec寄存器
|
|
||||||
input wire[`RegBus] csr_mepc, // mepc寄存器
|
|
||||||
input wire[`RegBus] csr_mstatus, // mstatus寄存器
|
|
||||||
|
|
||||||
input wire global_int_en_i, // 全局中断使能标志
|
|
||||||
|
|
||||||
// to ctrl
|
|
||||||
output wire hold_flag_o, // 流水线暂停标志
|
|
||||||
|
|
||||||
// to csr_reg
|
|
||||||
output reg we_o, // 写CSR寄存器标志
|
|
||||||
output reg[`MemAddrBus] waddr_o, // 写CSR寄存器地址
|
|
||||||
output reg[`MemAddrBus] raddr_o, // 读CSR寄存器地址
|
|
||||||
output reg[`RegBus] data_o, // 写CSR寄存器数据
|
|
||||||
|
|
||||||
// to ex
|
|
||||||
output reg[`InstAddrBus] int_addr_o, // 中断入口地址
|
|
||||||
output reg int_assert_o // 中断标志
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// 中断状态定义
|
|
||||||
localparam S_INT_IDLE = 4'b0001;
|
|
||||||
localparam S_INT_SYNC_ASSERT = 4'b0010;
|
|
||||||
localparam S_INT_ASYNC_ASSERT = 4'b0100;
|
|
||||||
localparam S_INT_MRET = 4'b1000;
|
|
||||||
|
|
||||||
// 写CSR寄存器状态定义
|
|
||||||
localparam S_CSR_IDLE = 5'b00001;
|
|
||||||
localparam S_CSR_MSTATUS = 5'b00010;
|
|
||||||
localparam S_CSR_MEPC = 5'b00100;
|
|
||||||
localparam S_CSR_MSTATUS_MRET = 5'b01000;
|
|
||||||
localparam S_CSR_MCAUSE = 5'b10000;
|
|
||||||
|
|
||||||
reg[3:0] int_state;
|
|
||||||
reg[4:0] csr_state;
|
|
||||||
reg[`InstAddrBus] inst_addr;
|
|
||||||
reg[31:0] cause;
|
|
||||||
|
|
||||||
|
|
||||||
assign hold_flag_o = ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? `HoldEnable: `HoldDisable;
|
|
||||||
|
|
||||||
|
|
||||||
// 中断仲裁逻辑
|
|
||||||
always @ (*) begin
|
|
||||||
if (rst == `RstEnable) begin
|
|
||||||
int_state = S_INT_IDLE;
|
|
||||||
end else begin
|
|
||||||
if (inst_i == `INST_ECALL || inst_i == `INST_EBREAK) begin
|
|
||||||
// 如果执行阶段的指令为除法指令,则先不处理同步中断,等除法指令执行完再处理
|
|
||||||
if (div_started_i == `DivStop) begin
|
|
||||||
int_state = S_INT_SYNC_ASSERT;
|
|
||||||
end else begin
|
|
||||||
int_state = S_INT_IDLE;
|
|
||||||
end
|
|
||||||
end else if (int_flag_i != `INT_NONE && global_int_en_i == `True) begin
|
|
||||||
int_state = S_INT_ASYNC_ASSERT;
|
|
||||||
end else if (inst_i == `INST_MRET) begin
|
|
||||||
int_state = S_INT_MRET;
|
|
||||||
end else begin
|
|
||||||
int_state = S_INT_IDLE;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 写CSR寄存器状态切换
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == `RstEnable) begin
|
|
||||||
csr_state <= S_CSR_IDLE;
|
|
||||||
cause <= `ZeroWord;
|
|
||||||
inst_addr <= `ZeroWord;
|
|
||||||
end else begin
|
|
||||||
case (csr_state)
|
|
||||||
S_CSR_IDLE: begin
|
|
||||||
// 同步中断
|
|
||||||
if (int_state == S_INT_SYNC_ASSERT) begin
|
|
||||||
csr_state <= S_CSR_MEPC;
|
|
||||||
// 在中断处理函数里会将中断返回地址加4
|
|
||||||
if (jump_flag_i == `JumpEnable) begin
|
|
||||||
inst_addr <= jump_addr_i - 4'h4;
|
|
||||||
end else begin
|
|
||||||
inst_addr <= inst_addr_i;
|
|
||||||
end
|
|
||||||
case (inst_i)
|
|
||||||
`INST_ECALL: begin
|
|
||||||
cause <= 32'd11;
|
|
||||||
end
|
|
||||||
`INST_EBREAK: begin
|
|
||||||
cause <= 32'd3;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
cause <= 32'd10;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
// 异步中断
|
|
||||||
end else if (int_state == S_INT_ASYNC_ASSERT) begin
|
|
||||||
// 定时器中断
|
|
||||||
cause <= 32'h80000004;
|
|
||||||
csr_state <= S_CSR_MEPC;
|
|
||||||
if (jump_flag_i == `JumpEnable) begin
|
|
||||||
inst_addr <= jump_addr_i;
|
|
||||||
// 异步中断可以中断除法指令的执行,中断处理完再重新执行除法指令
|
|
||||||
end else if (div_started_i == `DivStart) begin
|
|
||||||
inst_addr <= inst_addr_i - 4'h4;
|
|
||||||
end else begin
|
|
||||||
inst_addr <= inst_addr_i;
|
|
||||||
end
|
|
||||||
// 中断返回
|
|
||||||
end else if (int_state == S_INT_MRET) begin
|
|
||||||
csr_state <= S_CSR_MSTATUS_MRET;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S_CSR_MEPC: begin
|
|
||||||
csr_state <= S_CSR_MSTATUS;
|
|
||||||
end
|
|
||||||
S_CSR_MSTATUS: begin
|
|
||||||
csr_state <= S_CSR_MCAUSE;
|
|
||||||
end
|
|
||||||
S_CSR_MCAUSE: begin
|
|
||||||
csr_state <= S_CSR_IDLE;
|
|
||||||
end
|
|
||||||
S_CSR_MSTATUS_MRET: begin
|
|
||||||
csr_state <= S_CSR_IDLE;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
csr_state <= S_CSR_IDLE;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 发出中断信号前,先写几个CSR寄存器
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == `RstEnable) begin
|
|
||||||
we_o <= `WriteDisable;
|
|
||||||
waddr_o <= `ZeroWord;
|
|
||||||
data_o <= `ZeroWord;
|
|
||||||
end else begin
|
|
||||||
case (csr_state)
|
|
||||||
// 将mepc寄存器的值设为当前指令地址
|
|
||||||
S_CSR_MEPC: begin
|
|
||||||
we_o <= `WriteEnable;
|
|
||||||
waddr_o <= {20'h0, `CSR_MEPC};
|
|
||||||
data_o <= inst_addr;
|
|
||||||
end
|
|
||||||
// 写中断产生的原因
|
|
||||||
S_CSR_MCAUSE: begin
|
|
||||||
we_o <= `WriteEnable;
|
|
||||||
waddr_o <= {20'h0, `CSR_MCAUSE};
|
|
||||||
data_o <= cause;
|
|
||||||
end
|
|
||||||
// 关闭全局中断
|
|
||||||
S_CSR_MSTATUS: begin
|
|
||||||
we_o <= `WriteEnable;
|
|
||||||
waddr_o <= {20'h0, `CSR_MSTATUS};
|
|
||||||
data_o <= {csr_mstatus[31:4], 1'b0, csr_mstatus[2:0]};
|
|
||||||
end
|
|
||||||
// 中断返回
|
|
||||||
S_CSR_MSTATUS_MRET: begin
|
|
||||||
we_o <= `WriteEnable;
|
|
||||||
waddr_o <= {20'h0, `CSR_MSTATUS};
|
|
||||||
data_o <= {csr_mstatus[31:4], csr_mstatus[7], csr_mstatus[2:0]};
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
we_o <= `WriteDisable;
|
|
||||||
waddr_o <= `ZeroWord;
|
|
||||||
data_o <= `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 发出中断信号给ex模块
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == `RstEnable) begin
|
|
||||||
int_assert_o <= `INT_DEASSERT;
|
|
||||||
int_addr_o <= `ZeroWord;
|
|
||||||
end else begin
|
|
||||||
case (csr_state)
|
|
||||||
// 发出中断进入信号.写完mcause寄存器才能发
|
|
||||||
S_CSR_MCAUSE: begin
|
|
||||||
int_assert_o <= `INT_ASSERT;
|
|
||||||
int_addr_o <= csr_mtvec;
|
|
||||||
end
|
|
||||||
// 发出中断返回信号
|
|
||||||
S_CSR_MSTATUS_MRET: begin
|
|
||||||
int_assert_o <= `INT_ASSERT;
|
|
||||||
int_addr_o <= csr_mepc;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
int_assert_o <= `INT_DEASSERT;
|
|
||||||
int_addr_o <= `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -14,37 +14,30 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
`include "../core/defines.v"
|
module csr #(
|
||||||
|
parameter RESET_VAL = 32'h0,
|
||||||
|
parameter WIDTH = 32
|
||||||
|
)(
|
||||||
|
|
||||||
// ram module
|
input wire clk,
|
||||||
module ram(
|
input wire rst_n,
|
||||||
|
|
||||||
input wire clk,
|
input wire [WIDTH-1:0] wdata_i,
|
||||||
input wire rst,
|
input wire we_i,
|
||||||
|
output wire [WIDTH-1:0] rdata_o
|
||||||
input wire we_i, // write enable
|
|
||||||
input wire[`MemAddrBus] addr_i, // addr
|
|
||||||
input wire[`MemBus] data_i,
|
|
||||||
|
|
||||||
output reg[`MemBus] data_o // read data
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
reg[`MemBus] _ram[0:`MemNum - 1];
|
reg[WIDTH-1:0] rdata_q;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
always @ (posedge clk) begin
|
if (!rst_n) begin
|
||||||
if (we_i == `WriteEnable) begin
|
rdata_q <= RESET_VAL;
|
||||||
_ram[addr_i[31:2]] <= data_i;
|
end else if (we_i) begin
|
||||||
|
rdata_q <= wdata_i;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
always @ (*) begin
|
assign rdata_o = rdata_q;
|
||||||
if (rst == `RstEnable) begin
|
|
||||||
data_o = `ZeroWord;
|
|
||||||
end else begin
|
|
||||||
data_o = _ram[addr_i[31:2]];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
endmodule
|
|
@ -0,0 +1,517 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// CSR寄存器模块
|
||||||
|
module csr_reg(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
// from exu
|
||||||
|
input wire exu_we_i, // exu模块写寄存器标志
|
||||||
|
input wire[31:0] exu_waddr_i, // exu模块写寄存器地址
|
||||||
|
input wire[31:0] exu_wdata_i, // exu模块写寄存器数据
|
||||||
|
input wire[31:0] exu_raddr_i, // exu模块读寄存器地址
|
||||||
|
output wire[31:0] exu_rdata_o, // exu模块读寄存器数据
|
||||||
|
|
||||||
|
input wire[31:0] pc_if_i, // 取指地址
|
||||||
|
output wire trigger_match_o, // 断点
|
||||||
|
|
||||||
|
// form exception
|
||||||
|
input wire excep_we_i, // exception模块写寄存器标志
|
||||||
|
input wire[31:0] excep_waddr_i, // exception模块写寄存器地址
|
||||||
|
input wire[31:0] excep_wdata_i, // exception模块写寄存器数据
|
||||||
|
|
||||||
|
output wire[31:0] mtvec_o, // mtvec寄存器值
|
||||||
|
output wire[31:0] mepc_o, // mepc寄存器值
|
||||||
|
output wire[31:0] mstatus_o, // mstatus寄存器值
|
||||||
|
output wire[31:0] mie_o, // mie寄存器值
|
||||||
|
output wire[31:0] dpc_o, // dpc寄存器值
|
||||||
|
output wire[31:0] dcsr_o // dcsr寄存器值
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
// 硬件断点个数(必须大于等于1)
|
||||||
|
localparam HwBpNum = 3;
|
||||||
|
localparam DbgHwNumLen = HwBpNum > 1 ? $clog2(HwBpNum) : 1;
|
||||||
|
localparam MaxTselect = HwBpNum - 1;
|
||||||
|
|
||||||
|
wire[31:0] max_tselect = MaxTselect;
|
||||||
|
|
||||||
|
wire[31:0] misa = 32'h40001100; // 32bits, IM
|
||||||
|
|
||||||
|
// for verification result
|
||||||
|
reg[31:0] sstatus_d;
|
||||||
|
wire[31:0] sstatus_q;
|
||||||
|
reg sstatus_we;
|
||||||
|
|
||||||
|
reg[31:0] mtvec_d;
|
||||||
|
wire[31:0] mtvec_q;
|
||||||
|
reg mtvec_we;
|
||||||
|
reg[31:0] mcause_d;
|
||||||
|
wire[31:0] mcause_q;
|
||||||
|
reg mcause_we;
|
||||||
|
reg[31:0] mepc_d;
|
||||||
|
wire[31:0] mepc_q;
|
||||||
|
reg mepc_we;
|
||||||
|
reg[31:0] mie_d;
|
||||||
|
wire[31:0] mie_q;
|
||||||
|
reg mie_we;
|
||||||
|
reg[31:0] mstatus_d;
|
||||||
|
wire[31:0] mstatus_q;
|
||||||
|
reg mstatus_we;
|
||||||
|
reg[31:0] mscratch_d;
|
||||||
|
wire[31:0] mscratch_q;
|
||||||
|
reg mscratch_we;
|
||||||
|
reg[31:0] dscratch0_d;
|
||||||
|
wire[31:0] dscratch0_q;
|
||||||
|
reg dscratch0_we;
|
||||||
|
reg[31:0] dscratch1_d;
|
||||||
|
wire[31:0] dscratch1_q;
|
||||||
|
reg dscratch1_we;
|
||||||
|
reg[31:0] mhartid_d;
|
||||||
|
wire[31:0] mhartid_q;
|
||||||
|
reg mhartid_we;
|
||||||
|
reg[31:0] dpc_d;
|
||||||
|
wire[31:0] dpc_q;
|
||||||
|
reg dpc_we;
|
||||||
|
reg[31:0] dcsr_d;
|
||||||
|
wire[31:0] dcsr_q;
|
||||||
|
reg dcsr_we;
|
||||||
|
|
||||||
|
reg[31:0] tselect_d;
|
||||||
|
wire[31:0] tselect_q;
|
||||||
|
reg tselect_we;
|
||||||
|
wire tmatch_control_d;
|
||||||
|
wire[HwBpNum-1:0] tmatch_control_q;
|
||||||
|
wire[HwBpNum-1:0] tmatch_control_we;
|
||||||
|
wire[31:0] tmatch_value_d;
|
||||||
|
wire[31:0] tmatch_value_q[HwBpNum];
|
||||||
|
wire[HwBpNum-1:0] tmatch_value_we;
|
||||||
|
wire[HwBpNum-1:0] trigger_match;
|
||||||
|
wire[31:0] tmatch_control_rdata;
|
||||||
|
wire[31:0] tmatch_value_rdata;
|
||||||
|
wire selected_tmatch_control;
|
||||||
|
wire[31:0] selected_tmatch_value;
|
||||||
|
|
||||||
|
reg[63:0] cycle;
|
||||||
|
|
||||||
|
// cycle counter
|
||||||
|
// 复位撤销后就一直计数
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
cycle <= {32'h0, 32'h0};
|
||||||
|
end else begin
|
||||||
|
cycle <= cycle + 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign mtvec_o = mtvec_q;
|
||||||
|
assign mepc_o = mepc_q;
|
||||||
|
assign mstatus_o = mstatus_q;
|
||||||
|
assign mie_o = mie_q;
|
||||||
|
assign dpc_o = dpc_q;
|
||||||
|
assign dcsr_o = dcsr_q;
|
||||||
|
|
||||||
|
reg[31:0] exu_rdata;
|
||||||
|
|
||||||
|
// exu模块读CSR寄存器
|
||||||
|
always @ (*) begin
|
||||||
|
case (exu_raddr_i[11:0])
|
||||||
|
`CSR_CYCLE: begin
|
||||||
|
exu_rdata = cycle[31:0];
|
||||||
|
end
|
||||||
|
`CSR_CYCLEH: begin
|
||||||
|
exu_rdata = cycle[63:32];
|
||||||
|
end
|
||||||
|
`CSR_MTVEC: begin
|
||||||
|
exu_rdata = mtvec_q;
|
||||||
|
end
|
||||||
|
`CSR_MCAUSE: begin
|
||||||
|
exu_rdata = mcause_q;
|
||||||
|
end
|
||||||
|
`CSR_MEPC: begin
|
||||||
|
exu_rdata = mepc_q;
|
||||||
|
end
|
||||||
|
`CSR_MIE: begin
|
||||||
|
exu_rdata = mie_q;
|
||||||
|
end
|
||||||
|
`CSR_MSTATUS: begin
|
||||||
|
exu_rdata = mstatus_q;
|
||||||
|
end
|
||||||
|
`CSR_MSCRATCH: begin
|
||||||
|
exu_rdata = mscratch_q;
|
||||||
|
end
|
||||||
|
`CSR_DSCRATCH0: begin
|
||||||
|
exu_rdata = dscratch0_q;
|
||||||
|
end
|
||||||
|
`CSR_DSCRATCH1: begin
|
||||||
|
exu_rdata = dscratch1_q;
|
||||||
|
end
|
||||||
|
`CSR_MHARTID: begin
|
||||||
|
exu_rdata = mhartid_q;
|
||||||
|
end
|
||||||
|
`CSR_DPC: begin
|
||||||
|
exu_rdata = dpc_q;
|
||||||
|
end
|
||||||
|
`CSR_DCSR: begin
|
||||||
|
exu_rdata = dcsr_q;
|
||||||
|
end
|
||||||
|
`CSR_MISA: begin
|
||||||
|
exu_rdata = misa;
|
||||||
|
end
|
||||||
|
`CSR_TSELECT: begin
|
||||||
|
exu_rdata = tselect_q;
|
||||||
|
end
|
||||||
|
`CSR_TDATA1: begin
|
||||||
|
exu_rdata = tmatch_control_rdata;
|
||||||
|
end
|
||||||
|
`CSR_TDATA2: begin
|
||||||
|
exu_rdata = tmatch_value_rdata;
|
||||||
|
end
|
||||||
|
default: begin
|
||||||
|
exu_rdata = 32'h0;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign exu_rdata_o = exu_rdata;
|
||||||
|
|
||||||
|
// 写CSR寄存器
|
||||||
|
wire we = exu_we_i | excep_we_i;
|
||||||
|
wire[31:0] waddr = exu_we_i? exu_waddr_i: excep_waddr_i;
|
||||||
|
wire[31:0] wdata = exu_we_i? exu_wdata_i: excep_wdata_i;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
mtvec_d = mtvec_q;
|
||||||
|
mtvec_we = 1'b0;
|
||||||
|
mcause_d = mcause_q;
|
||||||
|
mcause_we = 1'b0;
|
||||||
|
mepc_d = mepc_q;
|
||||||
|
mepc_we = 1'b0;
|
||||||
|
mie_d = mie_q;
|
||||||
|
mie_we = 1'b0;
|
||||||
|
mstatus_d = mstatus_q;
|
||||||
|
mstatus_we = 1'b0;
|
||||||
|
mscratch_d = mscratch_q;
|
||||||
|
mscratch_we = 1'b0;
|
||||||
|
dscratch0_d = dscratch0_q;
|
||||||
|
dscratch0_we = 1'b0;
|
||||||
|
dscratch1_d = dscratch1_q;
|
||||||
|
dscratch1_we = 1'b0;
|
||||||
|
mhartid_d = mhartid_q;
|
||||||
|
mhartid_we = 1'b0;
|
||||||
|
dpc_d = dpc_q;
|
||||||
|
dpc_we = 1'b0;
|
||||||
|
dcsr_d = dcsr_q;
|
||||||
|
dcsr_we = 1'b0;
|
||||||
|
sstatus_d = sstatus_q;
|
||||||
|
sstatus_we = 1'b0;
|
||||||
|
|
||||||
|
if (we) begin
|
||||||
|
case (waddr[11:0])
|
||||||
|
`CSR_MTVEC: begin
|
||||||
|
mtvec_d = wdata;
|
||||||
|
mtvec_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_MCAUSE: begin
|
||||||
|
mcause_d = wdata;
|
||||||
|
mcause_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_MEPC: begin
|
||||||
|
mepc_d = wdata;
|
||||||
|
mepc_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_MIE: begin
|
||||||
|
mie_d = wdata;
|
||||||
|
mie_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_MSTATUS: begin
|
||||||
|
mstatus_d = wdata;
|
||||||
|
mstatus_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_MSCRATCH: begin
|
||||||
|
mscratch_d = wdata;
|
||||||
|
mscratch_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_DSCRATCH0: begin
|
||||||
|
dscratch0_d = wdata;
|
||||||
|
dscratch0_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_DSCRATCH1: begin
|
||||||
|
dscratch1_d = wdata;
|
||||||
|
dscratch1_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_MHARTID: begin
|
||||||
|
mhartid_d = wdata;
|
||||||
|
mhartid_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_SSTATUS: begin
|
||||||
|
sstatus_d = wdata;
|
||||||
|
sstatus_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_DPC: begin
|
||||||
|
dpc_d = wdata;
|
||||||
|
dpc_we = 1'b1;
|
||||||
|
end
|
||||||
|
`CSR_DCSR: begin
|
||||||
|
// Not all bits in DCSR are writable by exu
|
||||||
|
if (exu_we_i) begin
|
||||||
|
dcsr_d = {dcsr_q[31:28], wdata[27:9], dcsr_q[8:6], wdata[5:4], dcsr_q[3], wdata[2:0]};
|
||||||
|
end else begin
|
||||||
|
dcsr_d = wdata;
|
||||||
|
end
|
||||||
|
dcsr_we = 1'b1;
|
||||||
|
end
|
||||||
|
default:;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// trigger control
|
||||||
|
assign tselect_we = (exu_waddr_i[11:0] == `CSR_TSELECT) & exu_we_i;
|
||||||
|
|
||||||
|
for (genvar i = 0; i < HwBpNum; i = i + 1) begin : dbg_tmatch_we
|
||||||
|
assign tmatch_control_we[i] = (i == tselect_q) &
|
||||||
|
exu_we_i &
|
||||||
|
(exu_waddr_i[11:0] == `CSR_TDATA1);
|
||||||
|
assign tmatch_value_we[i] = (i == tselect_q) &
|
||||||
|
exu_we_i &
|
||||||
|
(exu_waddr_i[11:0] == `CSR_TDATA2);
|
||||||
|
end
|
||||||
|
|
||||||
|
assign tselect_d = (exu_wdata_i < HwBpNum) ? exu_wdata_i : max_tselect;
|
||||||
|
assign tmatch_control_d = exu_wdata_i[2];
|
||||||
|
assign tmatch_value_d = exu_wdata_i;
|
||||||
|
|
||||||
|
if (HwBpNum > 1) begin : dbg_tmatch_multiple_select
|
||||||
|
assign selected_tmatch_control = tmatch_control_q[tselect_q];
|
||||||
|
assign selected_tmatch_value = tmatch_value_q[tselect_q];
|
||||||
|
end else begin : dbg_tmatch_single_select
|
||||||
|
assign selected_tmatch_control = tmatch_control_q[0];
|
||||||
|
assign selected_tmatch_value = tmatch_value_q[0];
|
||||||
|
end
|
||||||
|
|
||||||
|
// TDATA0 - only support simple address matching
|
||||||
|
assign tmatch_control_rdata = {4'h2, // type : address/data match
|
||||||
|
1'b1, // dmode : access from D mode only
|
||||||
|
6'h00, // maskmax : exact match only
|
||||||
|
1'b0, // hit : not supported
|
||||||
|
1'b0, // select : address match only
|
||||||
|
1'b0, // timing : match before execution
|
||||||
|
2'b00, // sizelo : match any access
|
||||||
|
4'h1, // action : enter debug mode
|
||||||
|
1'b0, // chain : not supported
|
||||||
|
4'h0, // match : simple match
|
||||||
|
1'b1, // m : match in m-mode
|
||||||
|
1'b0, // 0 : zero
|
||||||
|
1'b0, // s : not supported
|
||||||
|
1'b1, // u : match in u-mode
|
||||||
|
selected_tmatch_control, // execute : match instruction address
|
||||||
|
1'b0, // store : not supported
|
||||||
|
1'b0}; // load : not supported
|
||||||
|
|
||||||
|
// TDATA1 - address match value only
|
||||||
|
assign tmatch_value_rdata = selected_tmatch_value;
|
||||||
|
|
||||||
|
// Breakpoint matching
|
||||||
|
// We match against the next address, as the breakpoint must be taken before execution
|
||||||
|
for (genvar i = 0; i < HwBpNum; i = i + 1) begin : dbg_trigger_match
|
||||||
|
assign trigger_match[i] = tmatch_control_q[i] & (pc_if_i == tmatch_value_q[i]);
|
||||||
|
end
|
||||||
|
|
||||||
|
assign trigger_match_o = |trigger_match;
|
||||||
|
|
||||||
|
|
||||||
|
// mtvec
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) mtvec_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(mtvec_d),
|
||||||
|
.we_i(mtvec_we),
|
||||||
|
.rdata_o(mtvec_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// mcause
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) mcause_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(mcause_d),
|
||||||
|
.we_i(mcause_we),
|
||||||
|
.rdata_o(mcause_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// mepc
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) mepc_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(mepc_d),
|
||||||
|
.we_i(mepc_we),
|
||||||
|
.rdata_o(mepc_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// mie
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) mie_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(mie_d),
|
||||||
|
.we_i(mie_we),
|
||||||
|
.rdata_o(mie_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// mstatus
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) mstatus_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(mstatus_d),
|
||||||
|
.we_i(mstatus_we),
|
||||||
|
.rdata_o(mstatus_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// mscratch
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) mscratch_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(mscratch_d),
|
||||||
|
.we_i(mscratch_we),
|
||||||
|
.rdata_o(mscratch_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// dscratch0
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) dscratch0_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(dscratch0_d),
|
||||||
|
.we_i(dscratch0_we),
|
||||||
|
.rdata_o(dscratch0_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// dscratch1
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) dscratch1_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(dscratch1_d),
|
||||||
|
.we_i(dscratch1_we),
|
||||||
|
.rdata_o(dscratch1_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// mhartid
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) mhartid_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(mhartid_d),
|
||||||
|
.we_i(mhartid_we),
|
||||||
|
.rdata_o(mhartid_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// dpc
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) dpc_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(dpc_d),
|
||||||
|
.we_i(dpc_we),
|
||||||
|
.rdata_o(dpc_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// dcsr
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h40000000)
|
||||||
|
) dcsr_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(dcsr_d),
|
||||||
|
.we_i(dcsr_we),
|
||||||
|
.rdata_o(dcsr_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// tselect
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) tselect_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(tselect_d),
|
||||||
|
.we_i(tselect_we),
|
||||||
|
.rdata_o(tselect_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
// sstatus
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) sstatus_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(sstatus_d),
|
||||||
|
.we_i(sstatus_we),
|
||||||
|
.rdata_o(sstatus_q)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (genvar i = 0; i < HwBpNum; i = i + 1) begin : dbg_tmatch_reg
|
||||||
|
// tdata1
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(1'b0),
|
||||||
|
.WIDTH(1)
|
||||||
|
) tmatch_control_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(tmatch_control_d),
|
||||||
|
.we_i(tmatch_control_we[i]),
|
||||||
|
.rdata_o(tmatch_control_q[i])
|
||||||
|
);
|
||||||
|
|
||||||
|
// tdata2
|
||||||
|
csr #(
|
||||||
|
.RESET_VAL(32'h0)
|
||||||
|
) tmatch_value_csr (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.wdata_i(tmatch_value_d),
|
||||||
|
.we_i(tmatch_value_we[i]),
|
||||||
|
.rdata_o(tmatch_value_q[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
// for debug
|
||||||
|
wire[31:0] mtvec = mtvec_q;
|
||||||
|
wire[31:0] mstatus = mstatus_q;
|
||||||
|
wire[31:0] mepc = mepc_q;
|
||||||
|
wire[31:0] mie = mie_q;
|
||||||
|
wire[31:0] dpc = dpc_q;
|
||||||
|
wire[31:0] dcsr = dcsr_q;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,215 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
// CSR寄存器模块
|
|
||||||
module csr_reg(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
// form ex
|
|
||||||
input wire we_i, // ex模块写寄存器标志
|
|
||||||
input wire[`MemAddrBus] raddr_i, // ex模块读寄存器地址
|
|
||||||
input wire[`MemAddrBus] waddr_i, // ex模块写寄存器地址
|
|
||||||
input wire[`RegBus] data_i, // ex模块写寄存器数据
|
|
||||||
|
|
||||||
// from clint
|
|
||||||
input wire clint_we_i, // clint模块写寄存器标志
|
|
||||||
input wire[`MemAddrBus] clint_raddr_i, // clint模块读寄存器地址
|
|
||||||
input wire[`MemAddrBus] clint_waddr_i, // clint模块写寄存器地址
|
|
||||||
input wire[`RegBus] clint_data_i, // clint模块写寄存器数据
|
|
||||||
|
|
||||||
output wire global_int_en_o, // 全局中断使能标志
|
|
||||||
|
|
||||||
// to clint
|
|
||||||
output reg[`RegBus] clint_data_o, // clint模块读寄存器数据
|
|
||||||
output wire[`RegBus] clint_csr_mtvec, // mtvec
|
|
||||||
output wire[`RegBus] clint_csr_mepc, // mepc
|
|
||||||
output wire[`RegBus] clint_csr_mstatus, // mstatus
|
|
||||||
|
|
||||||
// to ex
|
|
||||||
output reg[`RegBus] data_o // ex模块读寄存器数据
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
reg[`DoubleRegBus] cycle;
|
|
||||||
reg[`RegBus] mtvec;
|
|
||||||
reg[`RegBus] mcause;
|
|
||||||
reg[`RegBus] mepc;
|
|
||||||
reg[`RegBus] mie;
|
|
||||||
reg[`RegBus] mstatus;
|
|
||||||
reg[`RegBus] mscratch;
|
|
||||||
|
|
||||||
assign global_int_en_o = (mstatus[3] == 1'b1)? `True: `False;
|
|
||||||
|
|
||||||
assign clint_csr_mtvec = mtvec;
|
|
||||||
assign clint_csr_mepc = mepc;
|
|
||||||
assign clint_csr_mstatus = mstatus;
|
|
||||||
|
|
||||||
// cycle counter
|
|
||||||
// 复位撤销后就一直计数
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == `RstEnable) begin
|
|
||||||
cycle <= {`ZeroWord, `ZeroWord};
|
|
||||||
end else begin
|
|
||||||
cycle <= cycle + 1'b1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// write reg
|
|
||||||
// 写寄存器操作
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == `RstEnable) begin
|
|
||||||
mtvec <= `ZeroWord;
|
|
||||||
mcause <= `ZeroWord;
|
|
||||||
mepc <= `ZeroWord;
|
|
||||||
mie <= `ZeroWord;
|
|
||||||
mstatus <= `ZeroWord;
|
|
||||||
mscratch <= `ZeroWord;
|
|
||||||
end else begin
|
|
||||||
// 优先响应ex模块的写操作
|
|
||||||
if (we_i == `WriteEnable) begin
|
|
||||||
case (waddr_i[11:0])
|
|
||||||
`CSR_MTVEC: begin
|
|
||||||
mtvec <= data_i;
|
|
||||||
end
|
|
||||||
`CSR_MCAUSE: begin
|
|
||||||
mcause <= data_i;
|
|
||||||
end
|
|
||||||
`CSR_MEPC: begin
|
|
||||||
mepc <= data_i;
|
|
||||||
end
|
|
||||||
`CSR_MIE: begin
|
|
||||||
mie <= data_i;
|
|
||||||
end
|
|
||||||
`CSR_MSTATUS: begin
|
|
||||||
mstatus <= data_i;
|
|
||||||
end
|
|
||||||
`CSR_MSCRATCH: begin
|
|
||||||
mscratch <= data_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
// clint模块写操作
|
|
||||||
end else if (clint_we_i == `WriteEnable) begin
|
|
||||||
case (clint_waddr_i[11:0])
|
|
||||||
`CSR_MTVEC: begin
|
|
||||||
mtvec <= clint_data_i;
|
|
||||||
end
|
|
||||||
`CSR_MCAUSE: begin
|
|
||||||
mcause <= clint_data_i;
|
|
||||||
end
|
|
||||||
`CSR_MEPC: begin
|
|
||||||
mepc <= clint_data_i;
|
|
||||||
end
|
|
||||||
`CSR_MIE: begin
|
|
||||||
mie <= clint_data_i;
|
|
||||||
end
|
|
||||||
`CSR_MSTATUS: begin
|
|
||||||
mstatus <= clint_data_i;
|
|
||||||
end
|
|
||||||
`CSR_MSCRATCH: begin
|
|
||||||
mscratch <= clint_data_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// read reg
|
|
||||||
// ex模块读CSR寄存器
|
|
||||||
always @ (*) begin
|
|
||||||
if ((waddr_i[11:0] == raddr_i[11:0]) && (we_i == `WriteEnable)) begin
|
|
||||||
data_o = data_i;
|
|
||||||
end else begin
|
|
||||||
case (raddr_i[11:0])
|
|
||||||
`CSR_CYCLE: begin
|
|
||||||
data_o = cycle[31:0];
|
|
||||||
end
|
|
||||||
`CSR_CYCLEH: begin
|
|
||||||
data_o = cycle[63:32];
|
|
||||||
end
|
|
||||||
`CSR_MTVEC: begin
|
|
||||||
data_o = mtvec;
|
|
||||||
end
|
|
||||||
`CSR_MCAUSE: begin
|
|
||||||
data_o = mcause;
|
|
||||||
end
|
|
||||||
`CSR_MEPC: begin
|
|
||||||
data_o = mepc;
|
|
||||||
end
|
|
||||||
`CSR_MIE: begin
|
|
||||||
data_o = mie;
|
|
||||||
end
|
|
||||||
`CSR_MSTATUS: begin
|
|
||||||
data_o = mstatus;
|
|
||||||
end
|
|
||||||
`CSR_MSCRATCH: begin
|
|
||||||
data_o = mscratch;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
data_o = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// read reg
|
|
||||||
// clint模块读CSR寄存器
|
|
||||||
always @ (*) begin
|
|
||||||
if ((clint_waddr_i[11:0] == clint_raddr_i[11:0]) && (clint_we_i == `WriteEnable)) begin
|
|
||||||
clint_data_o = clint_data_i;
|
|
||||||
end else begin
|
|
||||||
case (clint_raddr_i[11:0])
|
|
||||||
`CSR_CYCLE: begin
|
|
||||||
clint_data_o = cycle[31:0];
|
|
||||||
end
|
|
||||||
`CSR_CYCLEH: begin
|
|
||||||
clint_data_o = cycle[63:32];
|
|
||||||
end
|
|
||||||
`CSR_MTVEC: begin
|
|
||||||
clint_data_o = mtvec;
|
|
||||||
end
|
|
||||||
`CSR_MCAUSE: begin
|
|
||||||
clint_data_o = mcause;
|
|
||||||
end
|
|
||||||
`CSR_MEPC: begin
|
|
||||||
clint_data_o = mepc;
|
|
||||||
end
|
|
||||||
`CSR_MIE: begin
|
|
||||||
clint_data_o = mie;
|
|
||||||
end
|
|
||||||
`CSR_MSTATUS: begin
|
|
||||||
clint_data_o = mstatus;
|
|
||||||
end
|
|
||||||
`CSR_MSCRATCH: begin
|
|
||||||
clint_data_o = mscratch;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
clint_data_o = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
// 控制模块
|
|
||||||
// 发出跳转、暂停流水线信号
|
|
||||||
module ctrl(
|
|
||||||
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
// from ex
|
|
||||||
input wire jump_flag_i,
|
|
||||||
input wire[`InstAddrBus] jump_addr_i,
|
|
||||||
input wire hold_flag_ex_i,
|
|
||||||
|
|
||||||
// from rib
|
|
||||||
input wire hold_flag_rib_i,
|
|
||||||
|
|
||||||
// from jtag
|
|
||||||
input wire jtag_halt_flag_i,
|
|
||||||
|
|
||||||
// from clint
|
|
||||||
input wire hold_flag_clint_i,
|
|
||||||
|
|
||||||
output reg[`Hold_Flag_Bus] hold_flag_o,
|
|
||||||
|
|
||||||
// to pc_reg
|
|
||||||
output reg jump_flag_o,
|
|
||||||
output reg[`InstAddrBus] jump_addr_o
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
always @ (*) begin
|
|
||||||
jump_addr_o = jump_addr_i;
|
|
||||||
jump_flag_o = jump_flag_i;
|
|
||||||
// 默认不暂停
|
|
||||||
hold_flag_o = `Hold_None;
|
|
||||||
// 按优先级处理不同模块的请求
|
|
||||||
if (jump_flag_i == `JumpEnable || hold_flag_ex_i == `HoldEnable || hold_flag_clint_i == `HoldEnable) begin
|
|
||||||
// 暂停整条流水线
|
|
||||||
hold_flag_o = `Hold_Id;
|
|
||||||
end else if (hold_flag_rib_i == `HoldEnable) begin
|
|
||||||
// 暂停PC,即取指地址不变
|
|
||||||
hold_flag_o = `Hold_Pc;
|
|
||||||
end else if (jtag_halt_flag_i == `HoldEnable) begin
|
|
||||||
// 暂停整条流水线
|
|
||||||
hold_flag_o = `Hold_Id;
|
|
||||||
end else begin
|
|
||||||
hold_flag_o = `Hold_None;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 从Flash启动时打开下面这个宏
|
||||||
|
//`define FLASH_BOOT
|
||||||
|
|
||||||
|
`ifdef FLASH_BOOT
|
||||||
|
`define CPU_RESET_ADDR 32'h01000000 // CPU复位地址
|
||||||
|
`else
|
||||||
|
`define CPU_RESET_ADDR 32'h00000000 // CPU复位地址
|
||||||
|
`endif
|
||||||
|
`define CPU_CLOCK_HZ 25000000 // CPU时钟(25MHZ)
|
||||||
|
`define JTAG_RESET_FF_LEVELS 5
|
||||||
|
|
||||||
|
`define ROM_DEPTH (32 * 256) // 32KB,指令存储器深度,单位为word(4字节)
|
||||||
|
`define RAM_DEPTH (16 * 256) // 16KB,数据存储器深度,单位为word(4字节)
|
||||||
|
|
||||||
|
// 外设地址、大小
|
||||||
|
// ROM
|
||||||
|
`define ROM_ADDR_MASK ~32'hfffff
|
||||||
|
`define ROM_ADDR_BASE 32'h00000000
|
||||||
|
// Bootrom
|
||||||
|
`define BOOTROM_ADDR_MASK ~32'hffffff
|
||||||
|
`define BOOTROM_ADDR_BASE 32'h01000000
|
||||||
|
// Xip
|
||||||
|
`define XIP_ADDR_MASK ~32'hffffff
|
||||||
|
`define XIP_ADDR_BASE 32'h02000000
|
||||||
|
// DEBUG
|
||||||
|
`define DEBUG_ADDR_MASK ~32'hfffff
|
||||||
|
`define DEBUG_ADDR_BASE 32'h10000000
|
||||||
|
// RAM
|
||||||
|
`define RAM_ADDR_MASK ~32'hfffff
|
||||||
|
`define RAM_ADDR_BASE 32'h20000000
|
||||||
|
// GPIO
|
||||||
|
`define GPIO_ADDR_MASK ~32'hffff
|
||||||
|
`define GPIO_ADDR_BASE 32'h03000000
|
||||||
|
// Timer0
|
||||||
|
`define TIMER0_ADDR_MASK ~32'hffff
|
||||||
|
`define TIMER0_ADDR_BASE 32'h04000000
|
||||||
|
// UART0
|
||||||
|
`define UART0_ADDR_MASK ~32'hffff
|
||||||
|
`define UART0_ADDR_BASE 32'h05000000
|
||||||
|
// I2C0
|
||||||
|
`define I2C0_ADDR_MASK ~32'hffff
|
||||||
|
`define I2C0_ADDR_BASE 32'h06000000
|
||||||
|
// SPI0
|
||||||
|
`define SPI0_ADDR_MASK ~32'hffff
|
||||||
|
`define SPI0_ADDR_BASE 32'h07000000
|
||||||
|
// PINMUX
|
||||||
|
`define PINMUX_ADDR_MASK ~32'hffff
|
||||||
|
`define PINMUX_ADDR_BASE 32'h08000000
|
||||||
|
// UART1
|
||||||
|
`define UART1_ADDR_MASK ~32'hffff
|
||||||
|
`define UART1_ADDR_BASE 32'h09000000
|
||||||
|
// UART2
|
||||||
|
`define UART2_ADDR_MASK ~32'hffff
|
||||||
|
`define UART2_ADDR_BASE 32'h0A000000
|
||||||
|
// Timer1
|
||||||
|
`define TIMER1_ADDR_MASK ~32'hffff
|
||||||
|
`define TIMER1_ADDR_BASE 32'h0C000000
|
||||||
|
// Timer2
|
||||||
|
`define TIMER2_ADDR_MASK ~32'hffff
|
||||||
|
`define TIMER2_ADDR_BASE 32'h0D000000
|
||||||
|
// I2C1
|
||||||
|
`define I2C1_ADDR_MASK ~32'hffff
|
||||||
|
`define I2C1_ADDR_BASE 32'h0B000000
|
||||||
|
// Interrupt controller
|
||||||
|
`define RVIC_ADDR_MASK ~32'hffff
|
||||||
|
`define RVIC_ADDR_BASE 32'hD0000000
|
||||||
|
// SIM CTRL
|
||||||
|
`define SIM_CTRL_ADDR_MASK ~32'hffff
|
||||||
|
`define SIM_CTRL_ADDR_BASE 32'hE0000000
|
||||||
|
|
||||||
|
`define STALL_WIDTH 4
|
||||||
|
`define STALL_PC 2'd0
|
||||||
|
`define STALL_IF 2'd1
|
||||||
|
`define STALL_ID 2'd2
|
||||||
|
`define STALL_EX 2'd3
|
||||||
|
|
||||||
|
`define INST_NOP 32'h00000013
|
||||||
|
`define INST_MRET 32'h30200073
|
||||||
|
`define INST_ECALL 32'h00000073
|
||||||
|
`define INST_EBREAK 32'h00100073
|
||||||
|
`define INST_DRET 32'h7b200073
|
||||||
|
|
||||||
|
// 指令译码信息
|
||||||
|
`define DECINFO_GRP_BUS 2:0
|
||||||
|
`define DECINFO_GRP_WIDTH 3
|
||||||
|
`define DECINFO_GRP_ALU `DECINFO_GRP_WIDTH'd1
|
||||||
|
`define DECINFO_GRP_BJP `DECINFO_GRP_WIDTH'd2
|
||||||
|
`define DECINFO_GRP_MULDIV `DECINFO_GRP_WIDTH'd3
|
||||||
|
`define DECINFO_GRP_CSR `DECINFO_GRP_WIDTH'd4
|
||||||
|
`define DECINFO_GRP_MEM `DECINFO_GRP_WIDTH'd5
|
||||||
|
`define DECINFO_GRP_SYS `DECINFO_GRP_WIDTH'd6
|
||||||
|
|
||||||
|
`define DECINFO_ALU_BUS_WIDTH (`DECINFO_GRP_WIDTH+14)
|
||||||
|
`define DECINFO_ALU_LUI (`DECINFO_GRP_WIDTH+0)
|
||||||
|
`define DECINFO_ALU_AUIPC (`DECINFO_GRP_WIDTH+1)
|
||||||
|
`define DECINFO_ALU_ADD (`DECINFO_GRP_WIDTH+2)
|
||||||
|
`define DECINFO_ALU_SUB (`DECINFO_GRP_WIDTH+3)
|
||||||
|
`define DECINFO_ALU_SLL (`DECINFO_GRP_WIDTH+4)
|
||||||
|
`define DECINFO_ALU_SLT (`DECINFO_GRP_WIDTH+5)
|
||||||
|
`define DECINFO_ALU_SLTU (`DECINFO_GRP_WIDTH+6)
|
||||||
|
`define DECINFO_ALU_XOR (`DECINFO_GRP_WIDTH+7)
|
||||||
|
`define DECINFO_ALU_SRL (`DECINFO_GRP_WIDTH+8)
|
||||||
|
`define DECINFO_ALU_SRA (`DECINFO_GRP_WIDTH+9)
|
||||||
|
`define DECINFO_ALU_OR (`DECINFO_GRP_WIDTH+10)
|
||||||
|
`define DECINFO_ALU_AND (`DECINFO_GRP_WIDTH+11)
|
||||||
|
`define DECINFO_ALU_OP2IMM (`DECINFO_GRP_WIDTH+12)
|
||||||
|
`define DECINFO_ALU_OP1PC (`DECINFO_GRP_WIDTH+13)
|
||||||
|
|
||||||
|
`define DECINFO_BJP_BUS_WIDTH (`DECINFO_GRP_WIDTH+8)
|
||||||
|
`define DECINFO_BJP_JUMP (`DECINFO_GRP_WIDTH+0)
|
||||||
|
`define DECINFO_BJP_BEQ (`DECINFO_GRP_WIDTH+1)
|
||||||
|
`define DECINFO_BJP_BNE (`DECINFO_GRP_WIDTH+2)
|
||||||
|
`define DECINFO_BJP_BLT (`DECINFO_GRP_WIDTH+3)
|
||||||
|
`define DECINFO_BJP_BGE (`DECINFO_GRP_WIDTH+4)
|
||||||
|
`define DECINFO_BJP_BLTU (`DECINFO_GRP_WIDTH+5)
|
||||||
|
`define DECINFO_BJP_BGEU (`DECINFO_GRP_WIDTH+6)
|
||||||
|
`define DECINFO_BJP_OP1RS1 (`DECINFO_GRP_WIDTH+7)
|
||||||
|
|
||||||
|
`define DECINFO_MULDIV_BUS_WIDTH (`DECINFO_GRP_WIDTH+8)
|
||||||
|
`define DECINFO_MULDIV_MUL (`DECINFO_GRP_WIDTH+0)
|
||||||
|
`define DECINFO_MULDIV_MULH (`DECINFO_GRP_WIDTH+1)
|
||||||
|
`define DECINFO_MULDIV_MULHSU (`DECINFO_GRP_WIDTH+2)
|
||||||
|
`define DECINFO_MULDIV_MULHU (`DECINFO_GRP_WIDTH+3)
|
||||||
|
`define DECINFO_MULDIV_DIV (`DECINFO_GRP_WIDTH+4)
|
||||||
|
`define DECINFO_MULDIV_DIVU (`DECINFO_GRP_WIDTH+5)
|
||||||
|
`define DECINFO_MULDIV_REM (`DECINFO_GRP_WIDTH+6)
|
||||||
|
`define DECINFO_MULDIV_REMU (`DECINFO_GRP_WIDTH+7)
|
||||||
|
|
||||||
|
`define DECINFO_CSR_BUS_WIDTH (`DECINFO_GRP_WIDTH+16)
|
||||||
|
`define DECINFO_CSR_CSRRW (`DECINFO_GRP_WIDTH+0)
|
||||||
|
`define DECINFO_CSR_CSRRS (`DECINFO_GRP_WIDTH+1)
|
||||||
|
`define DECINFO_CSR_CSRRC (`DECINFO_GRP_WIDTH+2)
|
||||||
|
`define DECINFO_CSR_RS1IMM (`DECINFO_GRP_WIDTH+3)
|
||||||
|
`define DECINFO_CSR_CSRADDR `DECINFO_GRP_WIDTH+4+12-1:`DECINFO_GRP_WIDTH+4
|
||||||
|
|
||||||
|
`define DECINFO_MEM_BUS_WIDTH (`DECINFO_GRP_WIDTH+8)
|
||||||
|
`define DECINFO_MEM_LB (`DECINFO_GRP_WIDTH+0)
|
||||||
|
`define DECINFO_MEM_LH (`DECINFO_GRP_WIDTH+1)
|
||||||
|
`define DECINFO_MEM_LW (`DECINFO_GRP_WIDTH+2)
|
||||||
|
`define DECINFO_MEM_LBU (`DECINFO_GRP_WIDTH+3)
|
||||||
|
`define DECINFO_MEM_LHU (`DECINFO_GRP_WIDTH+4)
|
||||||
|
`define DECINFO_MEM_SB (`DECINFO_GRP_WIDTH+5)
|
||||||
|
`define DECINFO_MEM_SH (`DECINFO_GRP_WIDTH+6)
|
||||||
|
`define DECINFO_MEM_SW (`DECINFO_GRP_WIDTH+7)
|
||||||
|
|
||||||
|
`define DECINFO_SYS_BUS_WIDTH (`DECINFO_GRP_WIDTH+6)
|
||||||
|
`define DECINFO_SYS_ECALL (`DECINFO_GRP_WIDTH+0)
|
||||||
|
`define DECINFO_SYS_EBREAK (`DECINFO_GRP_WIDTH+1)
|
||||||
|
`define DECINFO_SYS_NOP (`DECINFO_GRP_WIDTH+2)
|
||||||
|
`define DECINFO_SYS_MRET (`DECINFO_GRP_WIDTH+3)
|
||||||
|
`define DECINFO_SYS_FENCE (`DECINFO_GRP_WIDTH+4)
|
||||||
|
`define DECINFO_SYS_DRET (`DECINFO_GRP_WIDTH+5)
|
||||||
|
|
||||||
|
// 最长的那组
|
||||||
|
`define DECINFO_WIDTH `DECINFO_CSR_BUS_WIDTH
|
||||||
|
|
||||||
|
// CSR寄存器地址
|
||||||
|
`define CSR_CYCLE 12'hc00
|
||||||
|
`define CSR_CYCLEH 12'hc80
|
||||||
|
`define CSR_MTVEC 12'h305
|
||||||
|
`define CSR_MCAUSE 12'h342
|
||||||
|
`define CSR_MEPC 12'h341
|
||||||
|
`define CSR_MIE 12'h304
|
||||||
|
`define CSR_MSTATUS 12'h300
|
||||||
|
`define CSR_MSCRATCH 12'h340
|
||||||
|
`define CSR_MHARTID 12'hF14
|
||||||
|
`define CSR_MISA 12'h301
|
||||||
|
// only used for verification
|
||||||
|
`define CSR_SSTATUS 12'h100
|
||||||
|
// Debug
|
||||||
|
`define CSR_DCSR 12'h7b0
|
||||||
|
`define CSR_DPC 12'h7b1
|
||||||
|
`define CSR_DSCRATCH0 12'h7b2
|
||||||
|
`define CSR_DSCRATCH1 12'h7b3
|
||||||
|
`define CSR_TSELECT 12'h7A0
|
||||||
|
`define CSR_TDATA1 12'h7A1
|
||||||
|
`define CSR_TDATA2 12'h7A2
|
||||||
|
`define CSR_TDATA3 12'h7A3
|
||||||
|
`define CSR_MCONTEXT 12'h7A8
|
||||||
|
`define CSR_SCONTEXT 12'h7AA
|
|
@ -1,164 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`define CpuResetAddr 32'h0
|
|
||||||
|
|
||||||
`define RstEnable 1'b0
|
|
||||||
`define RstDisable 1'b1
|
|
||||||
`define ZeroWord 32'h0
|
|
||||||
`define ZeroReg 5'h0
|
|
||||||
`define WriteEnable 1'b1
|
|
||||||
`define WriteDisable 1'b0
|
|
||||||
`define ReadEnable 1'b1
|
|
||||||
`define ReadDisable 1'b0
|
|
||||||
`define True 1'b1
|
|
||||||
`define False 1'b0
|
|
||||||
`define ChipEnable 1'b1
|
|
||||||
`define ChipDisable 1'b0
|
|
||||||
`define JumpEnable 1'b1
|
|
||||||
`define JumpDisable 1'b0
|
|
||||||
`define DivResultNotReady 1'b0
|
|
||||||
`define DivResultReady 1'b1
|
|
||||||
`define DivStart 1'b1
|
|
||||||
`define DivStop 1'b0
|
|
||||||
`define HoldEnable 1'b1
|
|
||||||
`define HoldDisable 1'b0
|
|
||||||
`define Stop 1'b1
|
|
||||||
`define NoStop 1'b0
|
|
||||||
`define RIB_ACK 1'b1
|
|
||||||
`define RIB_NACK 1'b0
|
|
||||||
`define RIB_REQ 1'b1
|
|
||||||
`define RIB_NREQ 1'b0
|
|
||||||
`define INT_ASSERT 1'b1
|
|
||||||
`define INT_DEASSERT 1'b0
|
|
||||||
|
|
||||||
`define INT_BUS 7:0
|
|
||||||
`define INT_NONE 8'h0
|
|
||||||
`define INT_RET 8'hff
|
|
||||||
`define INT_TIMER0 8'b00000001
|
|
||||||
`define INT_TIMER0_ENTRY_ADDR 32'h4
|
|
||||||
|
|
||||||
`define Hold_Flag_Bus 2:0
|
|
||||||
`define Hold_None 3'b000
|
|
||||||
`define Hold_Pc 3'b001
|
|
||||||
`define Hold_If 3'b010
|
|
||||||
`define Hold_Id 3'b011
|
|
||||||
|
|
||||||
// I type inst
|
|
||||||
`define INST_TYPE_I 7'b0010011
|
|
||||||
`define INST_ADDI 3'b000
|
|
||||||
`define INST_SLTI 3'b010
|
|
||||||
`define INST_SLTIU 3'b011
|
|
||||||
`define INST_XORI 3'b100
|
|
||||||
`define INST_ORI 3'b110
|
|
||||||
`define INST_ANDI 3'b111
|
|
||||||
`define INST_SLLI 3'b001
|
|
||||||
`define INST_SRI 3'b101
|
|
||||||
|
|
||||||
// L type inst
|
|
||||||
`define INST_TYPE_L 7'b0000011
|
|
||||||
`define INST_LB 3'b000
|
|
||||||
`define INST_LH 3'b001
|
|
||||||
`define INST_LW 3'b010
|
|
||||||
`define INST_LBU 3'b100
|
|
||||||
`define INST_LHU 3'b101
|
|
||||||
|
|
||||||
// S type inst
|
|
||||||
`define INST_TYPE_S 7'b0100011
|
|
||||||
`define INST_SB 3'b000
|
|
||||||
`define INST_SH 3'b001
|
|
||||||
`define INST_SW 3'b010
|
|
||||||
|
|
||||||
// R and M type inst
|
|
||||||
`define INST_TYPE_R_M 7'b0110011
|
|
||||||
// R type inst
|
|
||||||
`define INST_ADD_SUB 3'b000
|
|
||||||
`define INST_SLL 3'b001
|
|
||||||
`define INST_SLT 3'b010
|
|
||||||
`define INST_SLTU 3'b011
|
|
||||||
`define INST_XOR 3'b100
|
|
||||||
`define INST_SR 3'b101
|
|
||||||
`define INST_OR 3'b110
|
|
||||||
`define INST_AND 3'b111
|
|
||||||
// M type inst
|
|
||||||
`define INST_MUL 3'b000
|
|
||||||
`define INST_MULH 3'b001
|
|
||||||
`define INST_MULHSU 3'b010
|
|
||||||
`define INST_MULHU 3'b011
|
|
||||||
`define INST_DIV 3'b100
|
|
||||||
`define INST_DIVU 3'b101
|
|
||||||
`define INST_REM 3'b110
|
|
||||||
`define INST_REMU 3'b111
|
|
||||||
|
|
||||||
// J type inst
|
|
||||||
`define INST_JAL 7'b1101111
|
|
||||||
`define INST_JALR 7'b1100111
|
|
||||||
|
|
||||||
`define INST_LUI 7'b0110111
|
|
||||||
`define INST_AUIPC 7'b0010111
|
|
||||||
`define INST_NOP 32'h00000001
|
|
||||||
`define INST_NOP_OP 7'b0000001
|
|
||||||
`define INST_MRET 32'h30200073
|
|
||||||
`define INST_RET 32'h00008067
|
|
||||||
|
|
||||||
`define INST_FENCE 7'b0001111
|
|
||||||
`define INST_ECALL 32'h73
|
|
||||||
`define INST_EBREAK 32'h00100073
|
|
||||||
|
|
||||||
// J type inst
|
|
||||||
`define INST_TYPE_B 7'b1100011
|
|
||||||
`define INST_BEQ 3'b000
|
|
||||||
`define INST_BNE 3'b001
|
|
||||||
`define INST_BLT 3'b100
|
|
||||||
`define INST_BGE 3'b101
|
|
||||||
`define INST_BLTU 3'b110
|
|
||||||
`define INST_BGEU 3'b111
|
|
||||||
|
|
||||||
// CSR inst
|
|
||||||
`define INST_CSR 7'b1110011
|
|
||||||
`define INST_CSRRW 3'b001
|
|
||||||
`define INST_CSRRS 3'b010
|
|
||||||
`define INST_CSRRC 3'b011
|
|
||||||
`define INST_CSRRWI 3'b101
|
|
||||||
`define INST_CSRRSI 3'b110
|
|
||||||
`define INST_CSRRCI 3'b111
|
|
||||||
|
|
||||||
// CSR reg addr
|
|
||||||
`define CSR_CYCLE 12'hc00
|
|
||||||
`define CSR_CYCLEH 12'hc80
|
|
||||||
`define CSR_MTVEC 12'h305
|
|
||||||
`define CSR_MCAUSE 12'h342
|
|
||||||
`define CSR_MEPC 12'h341
|
|
||||||
`define CSR_MIE 12'h304
|
|
||||||
`define CSR_MSTATUS 12'h300
|
|
||||||
`define CSR_MSCRATCH 12'h340
|
|
||||||
|
|
||||||
`define RomNum 4096 // rom depth(how many words)
|
|
||||||
|
|
||||||
`define MemNum 4096 // memory depth(how many words)
|
|
||||||
`define MemBus 31:0
|
|
||||||
`define MemAddrBus 31:0
|
|
||||||
|
|
||||||
`define InstBus 31:0
|
|
||||||
`define InstAddrBus 31:0
|
|
||||||
|
|
||||||
// common regs
|
|
||||||
`define RegAddrBus 4:0
|
|
||||||
`define RegBus 31:0
|
|
||||||
`define DoubleRegBus 63:0
|
|
||||||
`define RegWidth 32
|
|
||||||
`define RegNum 32 // reg num
|
|
||||||
`define RegNumLog2 5
|
|
|
@ -14,28 +14,23 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
`include "defines.v"
|
`include "defines.sv"
|
||||||
|
|
||||||
// 除法模块
|
// 除法模块
|
||||||
// 试商法实现32位整数除法
|
// 试商法实现32位整数除法
|
||||||
// 每次除法运算至少需要33个时钟周期才能完成
|
// 每次除法运算至少需要33个时钟周期才能完成
|
||||||
module div(
|
module divider(
|
||||||
|
|
||||||
input wire clk,
|
input wire clk,
|
||||||
input wire rst,
|
input wire rst_n,
|
||||||
|
|
||||||
// from ex
|
input wire[31:0] dividend_i, // 被除数
|
||||||
input wire[`RegBus] dividend_i, // 被除数
|
input wire[31:0] divisor_i, // 除数
|
||||||
input wire[`RegBus] divisor_i, // 除数
|
input wire start_i, // 开始信号,运算期间这个信号需要一直保持有效
|
||||||
input wire start_i, // 开始信号,运算期间这个信号需要一直保持有效
|
input wire[3:0] op_i, // 具体是哪一条指令
|
||||||
input wire[2:0] op_i, // 具体是哪一条指令
|
|
||||||
input wire[`RegAddrBus] reg_waddr_i, // 运算结束后需要写的寄存器
|
|
||||||
|
|
||||||
// to ex
|
output reg[31:0] result_o, // 除法结果
|
||||||
output reg[`RegBus] result_o, // 除法结果,高32位是余数,低32位是商
|
output reg ready_o // 运算结束信号
|
||||||
output reg ready_o, // 运算结束信号
|
|
||||||
output reg busy_o, // 正在运算信号
|
|
||||||
output reg[`RegAddrBus] reg_waddr_o // 运算结束后需要写的寄存器
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -45,20 +40,20 @@ module div(
|
||||||
localparam STATE_CALC = 4'b0100;
|
localparam STATE_CALC = 4'b0100;
|
||||||
localparam STATE_END = 4'b1000;
|
localparam STATE_END = 4'b1000;
|
||||||
|
|
||||||
reg[`RegBus] dividend_r;
|
reg[31:0] dividend_r;
|
||||||
reg[`RegBus] divisor_r;
|
reg[31:0] divisor_r;
|
||||||
reg[2:0] op_r;
|
reg[3:0] op_r;
|
||||||
reg[3:0] state;
|
reg[3:0] state;
|
||||||
reg[31:0] count;
|
reg[31:0] count;
|
||||||
reg[`RegBus] div_result;
|
reg[31:0] div_result;
|
||||||
reg[`RegBus] div_remain;
|
reg[31:0] div_remain;
|
||||||
reg[`RegBus] minuend;
|
reg[31:0] minuend;
|
||||||
reg invert_result;
|
reg invert_result;
|
||||||
|
|
||||||
wire op_div = (op_r == `INST_DIV);
|
wire op_div = op_r[3];
|
||||||
wire op_divu = (op_r == `INST_DIVU);
|
wire op_divu = op_r[2];
|
||||||
wire op_rem = (op_r == `INST_REM);
|
wire op_rem = op_r[1];
|
||||||
wire op_remu = (op_r == `INST_REMU);
|
wire op_remu = op_r[0];
|
||||||
|
|
||||||
wire[31:0] dividend_invert = (-dividend_r);
|
wire[31:0] dividend_invert = (-dividend_r);
|
||||||
wire[31:0] divisor_invert = (-divisor_r);
|
wire[31:0] divisor_invert = (-divisor_r);
|
||||||
|
@ -68,61 +63,53 @@ module div(
|
||||||
wire[31:0] minuend_tmp = minuend_ge_divisor? minuend_sub_res[30:0]: minuend[30:0];
|
wire[31:0] minuend_tmp = minuend_ge_divisor? minuend_sub_res[30:0]: minuend[30:0];
|
||||||
|
|
||||||
// 状态机实现
|
// 状态机实现
|
||||||
always @ (posedge clk) begin
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
if (rst == `RstEnable) begin
|
if (!rst_n) begin
|
||||||
state <= STATE_IDLE;
|
state <= STATE_IDLE;
|
||||||
ready_o <= `DivResultNotReady;
|
ready_o <= 1'b0;
|
||||||
result_o <= `ZeroWord;
|
result_o <= 32'h0;
|
||||||
div_result <= `ZeroWord;
|
div_result <= 32'h0;
|
||||||
div_remain <= `ZeroWord;
|
div_remain <= 32'h0;
|
||||||
op_r <= 3'h0;
|
op_r <= 3'h0;
|
||||||
reg_waddr_o <= `ZeroWord;
|
dividend_r <= 32'h0;
|
||||||
dividend_r <= `ZeroWord;
|
divisor_r <= 32'h0;
|
||||||
divisor_r <= `ZeroWord;
|
minuend <= 32'h0;
|
||||||
minuend <= `ZeroWord;
|
|
||||||
invert_result <= 1'b0;
|
invert_result <= 1'b0;
|
||||||
busy_o <= `False;
|
count <= 32'h0;
|
||||||
count <= `ZeroWord;
|
|
||||||
end else begin
|
end else begin
|
||||||
case (state)
|
case (state)
|
||||||
STATE_IDLE: begin
|
STATE_IDLE: begin
|
||||||
if (start_i == `DivStart) begin
|
if (start_i) begin
|
||||||
op_r <= op_i;
|
op_r <= op_i;
|
||||||
dividend_r <= dividend_i;
|
dividend_r <= dividend_i;
|
||||||
divisor_r <= divisor_i;
|
divisor_r <= divisor_i;
|
||||||
reg_waddr_o <= reg_waddr_i;
|
|
||||||
state <= STATE_START;
|
state <= STATE_START;
|
||||||
busy_o <= `True;
|
|
||||||
end else begin
|
end else begin
|
||||||
op_r <= 3'h0;
|
op_r <= 3'h0;
|
||||||
reg_waddr_o <= `ZeroWord;
|
dividend_r <= 32'h0;
|
||||||
dividend_r <= `ZeroWord;
|
divisor_r <= 32'h0;
|
||||||
divisor_r <= `ZeroWord;
|
ready_o <= 1'b0;
|
||||||
ready_o <= `DivResultNotReady;
|
result_o <= 32'h0;
|
||||||
result_o <= `ZeroWord;
|
|
||||||
busy_o <= `False;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
STATE_START: begin
|
STATE_START: begin
|
||||||
if (start_i == `DivStart) begin
|
if (start_i) begin
|
||||||
// 除数为0
|
// 除数为0
|
||||||
if (divisor_r == `ZeroWord) begin
|
if (divisor_r == 32'h0) begin
|
||||||
if (op_div | op_divu) begin
|
if (op_div | op_divu) begin
|
||||||
result_o <= 32'hffffffff;
|
result_o <= 32'hffffffff;
|
||||||
end else begin
|
end else begin
|
||||||
result_o <= dividend_r;
|
result_o <= dividend_r;
|
||||||
end
|
end
|
||||||
ready_o <= `DivResultReady;
|
ready_o <= 1'b1;
|
||||||
state <= STATE_IDLE;
|
state <= STATE_IDLE;
|
||||||
busy_o <= `False;
|
|
||||||
// 除数不为0
|
// 除数不为0
|
||||||
end else begin
|
end else begin
|
||||||
busy_o <= `True;
|
|
||||||
count <= 32'h40000000;
|
count <= 32'h40000000;
|
||||||
state <= STATE_CALC;
|
state <= STATE_CALC;
|
||||||
div_result <= `ZeroWord;
|
div_result <= 32'h0;
|
||||||
div_remain <= `ZeroWord;
|
div_remain <= 32'h0;
|
||||||
|
|
||||||
// DIV和REM这两条指令是有符号数运算指令
|
// DIV和REM这两条指令是有符号数运算指令
|
||||||
if (op_div | op_rem) begin
|
if (op_div | op_rem) begin
|
||||||
|
@ -151,14 +138,13 @@ module div(
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
state <= STATE_IDLE;
|
state <= STATE_IDLE;
|
||||||
result_o <= `ZeroWord;
|
result_o <= 32'h0;
|
||||||
ready_o <= `DivResultNotReady;
|
ready_o <= 1'b0;
|
||||||
busy_o <= `False;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
STATE_CALC: begin
|
STATE_CALC: begin
|
||||||
if (start_i == `DivStart) begin
|
if (start_i) begin
|
||||||
dividend_r <= {dividend_r[30:0], 1'b0};
|
dividend_r <= {dividend_r[30:0], 1'b0};
|
||||||
div_result <= div_result_tmp;
|
div_result <= div_result_tmp;
|
||||||
count <= {1'b0, count[31:1]};
|
count <= {1'b0, count[31:1]};
|
||||||
|
@ -174,17 +160,15 @@ module div(
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
state <= STATE_IDLE;
|
state <= STATE_IDLE;
|
||||||
result_o <= `ZeroWord;
|
result_o <= 32'h0;
|
||||||
ready_o <= `DivResultNotReady;
|
ready_o <= 1'b0;
|
||||||
busy_o <= `False;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
STATE_END: begin
|
STATE_END: begin
|
||||||
if (start_i == `DivStart) begin
|
if (start_i) begin
|
||||||
ready_o <= `DivResultReady;
|
ready_o <= 1'b1;
|
||||||
state <= STATE_IDLE;
|
state <= STATE_IDLE;
|
||||||
busy_o <= `False;
|
|
||||||
if (op_div | op_divu) begin
|
if (op_div | op_divu) begin
|
||||||
if (invert_result) begin
|
if (invert_result) begin
|
||||||
result_o <= (-div_result);
|
result_o <= (-div_result);
|
||||||
|
@ -200,9 +184,8 @@ module div(
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
state <= STATE_IDLE;
|
state <= STATE_IDLE;
|
||||||
result_o <= `ZeroWord;
|
result_o <= 32'h0;
|
||||||
ready_o <= `DivResultNotReady;
|
ready_o <= 1'b0;
|
||||||
busy_o <= `False;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
875
rtl/core/ex.v
|
@ -1,875 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
// 执行模块
|
|
||||||
// 纯组合逻辑电路
|
|
||||||
module ex(
|
|
||||||
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
// from id
|
|
||||||
input wire[`InstBus] inst_i, // 指令内容
|
|
||||||
input wire[`InstAddrBus] inst_addr_i, // 指令地址
|
|
||||||
input wire reg_we_i, // 是否写通用寄存器
|
|
||||||
input wire[`RegAddrBus] reg_waddr_i, // 写通用寄存器地址
|
|
||||||
input wire[`RegBus] reg1_rdata_i, // 通用寄存器1输入数据
|
|
||||||
input wire[`RegBus] reg2_rdata_i, // 通用寄存器2输入数据
|
|
||||||
input wire csr_we_i, // 是否写CSR寄存器
|
|
||||||
input wire[`MemAddrBus] csr_waddr_i, // 写CSR寄存器地址
|
|
||||||
input wire[`RegBus] csr_rdata_i, // CSR寄存器输入数据
|
|
||||||
input wire int_assert_i, // 中断发生标志
|
|
||||||
input wire[`InstAddrBus] int_addr_i, // 中断跳转地址
|
|
||||||
input wire[`MemAddrBus] op1_i,
|
|
||||||
input wire[`MemAddrBus] op2_i,
|
|
||||||
input wire[`MemAddrBus] op1_jump_i,
|
|
||||||
input wire[`MemAddrBus] op2_jump_i,
|
|
||||||
|
|
||||||
// from mem
|
|
||||||
input wire[`MemBus] mem_rdata_i, // 内存输入数据
|
|
||||||
|
|
||||||
// from div
|
|
||||||
input wire div_ready_i, // 除法运算完成标志
|
|
||||||
input wire[`RegBus] div_result_i, // 除法运算结果
|
|
||||||
input wire div_busy_i, // 除法运算忙标志
|
|
||||||
input wire[`RegAddrBus] div_reg_waddr_i,// 除法运算结束后要写的寄存器地址
|
|
||||||
|
|
||||||
// to mem
|
|
||||||
output reg[`MemBus] mem_wdata_o, // 写内存数据
|
|
||||||
output reg[`MemAddrBus] mem_raddr_o, // 读内存地址
|
|
||||||
output reg[`MemAddrBus] mem_waddr_o, // 写内存地址
|
|
||||||
output wire mem_we_o, // 是否要写内存
|
|
||||||
output wire mem_req_o, // 请求访问内存标志
|
|
||||||
|
|
||||||
// to regs
|
|
||||||
output wire[`RegBus] reg_wdata_o, // 写寄存器数据
|
|
||||||
output wire reg_we_o, // 是否要写通用寄存器
|
|
||||||
output wire[`RegAddrBus] reg_waddr_o, // 写通用寄存器地址
|
|
||||||
|
|
||||||
// to csr reg
|
|
||||||
output reg[`RegBus] csr_wdata_o, // 写CSR寄存器数据
|
|
||||||
output wire csr_we_o, // 是否要写CSR寄存器
|
|
||||||
output wire[`MemAddrBus] csr_waddr_o, // 写CSR寄存器地址
|
|
||||||
|
|
||||||
// to div
|
|
||||||
output wire div_start_o, // 开始除法运算标志
|
|
||||||
output reg[`RegBus] div_dividend_o, // 被除数
|
|
||||||
output reg[`RegBus] div_divisor_o, // 除数
|
|
||||||
output reg[2:0] div_op_o, // 具体是哪一条除法指令
|
|
||||||
output reg[`RegAddrBus] div_reg_waddr_o,// 除法运算结束后要写的寄存器地址
|
|
||||||
|
|
||||||
// to ctrl
|
|
||||||
output wire hold_flag_o, // 是否暂停标志
|
|
||||||
output wire jump_flag_o, // 是否跳转标志
|
|
||||||
output wire[`InstAddrBus] jump_addr_o // 跳转目的地址
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
wire[1:0] mem_raddr_index;
|
|
||||||
wire[1:0] mem_waddr_index;
|
|
||||||
wire[`DoubleRegBus] mul_temp;
|
|
||||||
wire[`DoubleRegBus] mul_temp_invert;
|
|
||||||
wire[31:0] sr_shift;
|
|
||||||
wire[31:0] sri_shift;
|
|
||||||
wire[31:0] sr_shift_mask;
|
|
||||||
wire[31:0] sri_shift_mask;
|
|
||||||
wire[31:0] op1_add_op2_res;
|
|
||||||
wire[31:0] op1_jump_add_op2_jump_res;
|
|
||||||
wire[31:0] reg1_data_invert;
|
|
||||||
wire[31:0] reg2_data_invert;
|
|
||||||
wire op1_ge_op2_signed;
|
|
||||||
wire op1_ge_op2_unsigned;
|
|
||||||
wire op1_eq_op2;
|
|
||||||
reg[`RegBus] mul_op1;
|
|
||||||
reg[`RegBus] mul_op2;
|
|
||||||
wire[6:0] opcode;
|
|
||||||
wire[2:0] funct3;
|
|
||||||
wire[6:0] funct7;
|
|
||||||
wire[4:0] rd;
|
|
||||||
wire[4:0] uimm;
|
|
||||||
reg[`RegBus] reg_wdata;
|
|
||||||
reg reg_we;
|
|
||||||
reg[`RegAddrBus] reg_waddr;
|
|
||||||
reg[`RegBus] div_wdata;
|
|
||||||
reg div_we;
|
|
||||||
reg[`RegAddrBus] div_waddr;
|
|
||||||
reg div_hold_flag;
|
|
||||||
reg div_jump_flag;
|
|
||||||
reg[`InstAddrBus] div_jump_addr;
|
|
||||||
reg hold_flag;
|
|
||||||
reg jump_flag;
|
|
||||||
reg[`InstAddrBus] jump_addr;
|
|
||||||
reg mem_we;
|
|
||||||
reg mem_req;
|
|
||||||
reg div_start;
|
|
||||||
|
|
||||||
assign opcode = inst_i[6:0];
|
|
||||||
assign funct3 = inst_i[14:12];
|
|
||||||
assign funct7 = inst_i[31:25];
|
|
||||||
assign rd = inst_i[11:7];
|
|
||||||
assign uimm = inst_i[19:15];
|
|
||||||
|
|
||||||
assign sr_shift = reg1_rdata_i >> reg2_rdata_i[4:0];
|
|
||||||
assign sri_shift = reg1_rdata_i >> inst_i[24:20];
|
|
||||||
assign sr_shift_mask = 32'hffffffff >> reg2_rdata_i[4:0];
|
|
||||||
assign sri_shift_mask = 32'hffffffff >> inst_i[24:20];
|
|
||||||
|
|
||||||
assign op1_add_op2_res = op1_i + op2_i;
|
|
||||||
assign op1_jump_add_op2_jump_res = op1_jump_i + op2_jump_i;
|
|
||||||
|
|
||||||
assign reg1_data_invert = ~reg1_rdata_i + 1;
|
|
||||||
assign reg2_data_invert = ~reg2_rdata_i + 1;
|
|
||||||
|
|
||||||
// 有符号数比较
|
|
||||||
assign op1_ge_op2_signed = $signed(op1_i) >= $signed(op2_i);
|
|
||||||
// 无符号数比较
|
|
||||||
assign op1_ge_op2_unsigned = op1_i >= op2_i;
|
|
||||||
assign op1_eq_op2 = (op1_i == op2_i);
|
|
||||||
|
|
||||||
assign mul_temp = mul_op1 * mul_op2;
|
|
||||||
assign mul_temp_invert = ~mul_temp + 1;
|
|
||||||
|
|
||||||
assign mem_raddr_index = (reg1_rdata_i + {{20{inst_i[31]}}, inst_i[31:20]}) & 2'b11;
|
|
||||||
assign mem_waddr_index = (reg1_rdata_i + {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]}) & 2'b11;
|
|
||||||
|
|
||||||
assign div_start_o = (int_assert_i == `INT_ASSERT)? `DivStop: div_start;
|
|
||||||
|
|
||||||
assign reg_wdata_o = reg_wdata | div_wdata;
|
|
||||||
// 响应中断时不写通用寄存器
|
|
||||||
assign reg_we_o = (int_assert_i == `INT_ASSERT)? `WriteDisable: (reg_we || div_we);
|
|
||||||
assign reg_waddr_o = reg_waddr | div_waddr;
|
|
||||||
|
|
||||||
// 响应中断时不写内存
|
|
||||||
assign mem_we_o = (int_assert_i == `INT_ASSERT)? `WriteDisable: mem_we;
|
|
||||||
|
|
||||||
// 响应中断时不向总线请求访问内存
|
|
||||||
assign mem_req_o = (int_assert_i == `INT_ASSERT)? `RIB_NREQ: mem_req;
|
|
||||||
|
|
||||||
assign hold_flag_o = hold_flag || div_hold_flag;
|
|
||||||
assign jump_flag_o = jump_flag || div_jump_flag || ((int_assert_i == `INT_ASSERT)? `JumpEnable: `JumpDisable);
|
|
||||||
assign jump_addr_o = (int_assert_i == `INT_ASSERT)? int_addr_i: (jump_addr | div_jump_addr);
|
|
||||||
|
|
||||||
// 响应中断时不写CSR寄存器
|
|
||||||
assign csr_we_o = (int_assert_i == `INT_ASSERT)? `WriteDisable: csr_we_i;
|
|
||||||
assign csr_waddr_o = csr_waddr_i;
|
|
||||||
|
|
||||||
|
|
||||||
// 处理乘法指令
|
|
||||||
always @ (*) begin
|
|
||||||
if ((opcode == `INST_TYPE_R_M) && (funct7 == 7'b0000001)) begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_MUL, `INST_MULHU: begin
|
|
||||||
mul_op1 = reg1_rdata_i;
|
|
||||||
mul_op2 = reg2_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_MULHSU: begin
|
|
||||||
mul_op1 = (reg1_rdata_i[31] == 1'b1)? (reg1_data_invert): reg1_rdata_i;
|
|
||||||
mul_op2 = reg2_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_MULH: begin
|
|
||||||
mul_op1 = (reg1_rdata_i[31] == 1'b1)? (reg1_data_invert): reg1_rdata_i;
|
|
||||||
mul_op2 = (reg2_rdata_i[31] == 1'b1)? (reg2_data_invert): reg2_rdata_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
mul_op1 = reg1_rdata_i;
|
|
||||||
mul_op2 = reg2_rdata_i;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end else begin
|
|
||||||
mul_op1 = reg1_rdata_i;
|
|
||||||
mul_op2 = reg2_rdata_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 处理除法指令
|
|
||||||
always @ (*) begin
|
|
||||||
div_dividend_o = reg1_rdata_i;
|
|
||||||
div_divisor_o = reg2_rdata_i;
|
|
||||||
div_op_o = funct3;
|
|
||||||
div_reg_waddr_o = reg_waddr_i;
|
|
||||||
if ((opcode == `INST_TYPE_R_M) && (funct7 == 7'b0000001)) begin
|
|
||||||
div_we = `WriteDisable;
|
|
||||||
div_wdata = `ZeroWord;
|
|
||||||
div_waddr = `ZeroWord;
|
|
||||||
case (funct3)
|
|
||||||
`INST_DIV, `INST_DIVU, `INST_REM, `INST_REMU: begin
|
|
||||||
div_start = `DivStart;
|
|
||||||
div_jump_flag = `JumpEnable;
|
|
||||||
div_hold_flag = `HoldEnable;
|
|
||||||
div_jump_addr = op1_jump_add_op2_jump_res;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
div_start = `DivStop;
|
|
||||||
div_jump_flag = `JumpDisable;
|
|
||||||
div_hold_flag = `HoldDisable;
|
|
||||||
div_jump_addr = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end else begin
|
|
||||||
div_jump_flag = `JumpDisable;
|
|
||||||
div_jump_addr = `ZeroWord;
|
|
||||||
if (div_busy_i == `True) begin
|
|
||||||
div_start = `DivStart;
|
|
||||||
div_we = `WriteDisable;
|
|
||||||
div_wdata = `ZeroWord;
|
|
||||||
div_waddr = `ZeroWord;
|
|
||||||
div_hold_flag = `HoldEnable;
|
|
||||||
end else begin
|
|
||||||
div_start = `DivStop;
|
|
||||||
div_hold_flag = `HoldDisable;
|
|
||||||
if (div_ready_i == `DivResultReady) begin
|
|
||||||
div_wdata = div_result_i;
|
|
||||||
div_waddr = div_reg_waddr_i;
|
|
||||||
div_we = `WriteEnable;
|
|
||||||
end else begin
|
|
||||||
div_we = `WriteDisable;
|
|
||||||
div_wdata = `ZeroWord;
|
|
||||||
div_waddr = `ZeroWord;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 执行
|
|
||||||
always @ (*) begin
|
|
||||||
reg_we = reg_we_i;
|
|
||||||
reg_waddr = reg_waddr_i;
|
|
||||||
mem_req = `RIB_NREQ;
|
|
||||||
csr_wdata_o = `ZeroWord;
|
|
||||||
|
|
||||||
case (opcode)
|
|
||||||
`INST_TYPE_I: begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_ADDI: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = op1_add_op2_res;
|
|
||||||
end
|
|
||||||
`INST_SLTI: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = {32{(~op1_ge_op2_signed)}} & 32'h1;
|
|
||||||
end
|
|
||||||
`INST_SLTIU: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = {32{(~op1_ge_op2_unsigned)}} & 32'h1;
|
|
||||||
end
|
|
||||||
`INST_XORI: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = op1_i ^ op2_i;
|
|
||||||
end
|
|
||||||
`INST_ORI: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = op1_i | op2_i;
|
|
||||||
end
|
|
||||||
`INST_ANDI: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = op1_i & op2_i;
|
|
||||||
end
|
|
||||||
`INST_SLLI: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = reg1_rdata_i << inst_i[24:20];
|
|
||||||
end
|
|
||||||
`INST_SRI: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
if (inst_i[30] == 1'b1) begin
|
|
||||||
reg_wdata = (sri_shift & sri_shift_mask) | ({32{reg1_rdata_i[31]}} & (~sri_shift_mask));
|
|
||||||
end else begin
|
|
||||||
reg_wdata = reg1_rdata_i >> inst_i[24:20];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_TYPE_R_M: begin
|
|
||||||
if ((funct7 == 7'b0000000) || (funct7 == 7'b0100000)) begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_ADD_SUB: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
if (inst_i[30] == 1'b0) begin
|
|
||||||
reg_wdata = op1_add_op2_res;
|
|
||||||
end else begin
|
|
||||||
reg_wdata = op1_i - op2_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
`INST_SLL: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = op1_i << op2_i[4:0];
|
|
||||||
end
|
|
||||||
`INST_SLT: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = {32{(~op1_ge_op2_signed)}} & 32'h1;
|
|
||||||
end
|
|
||||||
`INST_SLTU: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = {32{(~op1_ge_op2_unsigned)}} & 32'h1;
|
|
||||||
end
|
|
||||||
`INST_XOR: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = op1_i ^ op2_i;
|
|
||||||
end
|
|
||||||
`INST_SR: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
if (inst_i[30] == 1'b1) begin
|
|
||||||
reg_wdata = (sr_shift & sr_shift_mask) | ({32{reg1_rdata_i[31]}} & (~sr_shift_mask));
|
|
||||||
end else begin
|
|
||||||
reg_wdata = reg1_rdata_i >> reg2_rdata_i[4:0];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
`INST_OR: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = op1_i | op2_i;
|
|
||||||
end
|
|
||||||
`INST_AND: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = op1_i & op2_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end else if (funct7 == 7'b0000001) begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_MUL: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = mul_temp[31:0];
|
|
||||||
end
|
|
||||||
`INST_MULHU: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = mul_temp[63:32];
|
|
||||||
end
|
|
||||||
`INST_MULH: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
case ({reg1_rdata_i[31], reg2_rdata_i[31]})
|
|
||||||
2'b00: begin
|
|
||||||
reg_wdata = mul_temp[63:32];
|
|
||||||
end
|
|
||||||
2'b11: begin
|
|
||||||
reg_wdata = mul_temp[63:32];
|
|
||||||
end
|
|
||||||
2'b10: begin
|
|
||||||
reg_wdata = mul_temp_invert[63:32];
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg_wdata = mul_temp_invert[63:32];
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_MULHSU: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
if (reg1_rdata_i[31] == 1'b1) begin
|
|
||||||
reg_wdata = mul_temp_invert[63:32];
|
|
||||||
end else begin
|
|
||||||
reg_wdata = mul_temp[63:32];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end else begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
`INST_TYPE_L: begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_LB: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
mem_req = `RIB_REQ;
|
|
||||||
mem_raddr_o = op1_add_op2_res;
|
|
||||||
case (mem_raddr_index)
|
|
||||||
2'b00: begin
|
|
||||||
reg_wdata = {{24{mem_rdata_i[7]}}, mem_rdata_i[7:0]};
|
|
||||||
end
|
|
||||||
2'b01: begin
|
|
||||||
reg_wdata = {{24{mem_rdata_i[15]}}, mem_rdata_i[15:8]};
|
|
||||||
end
|
|
||||||
2'b10: begin
|
|
||||||
reg_wdata = {{24{mem_rdata_i[23]}}, mem_rdata_i[23:16]};
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg_wdata = {{24{mem_rdata_i[31]}}, mem_rdata_i[31:24]};
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_LH: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
mem_req = `RIB_REQ;
|
|
||||||
mem_raddr_o = op1_add_op2_res;
|
|
||||||
if (mem_raddr_index == 2'b0) begin
|
|
||||||
reg_wdata = {{16{mem_rdata_i[15]}}, mem_rdata_i[15:0]};
|
|
||||||
end else begin
|
|
||||||
reg_wdata = {{16{mem_rdata_i[31]}}, mem_rdata_i[31:16]};
|
|
||||||
end
|
|
||||||
end
|
|
||||||
`INST_LW: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
mem_req = `RIB_REQ;
|
|
||||||
mem_raddr_o = op1_add_op2_res;
|
|
||||||
reg_wdata = mem_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_LBU: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
mem_req = `RIB_REQ;
|
|
||||||
mem_raddr_o = op1_add_op2_res;
|
|
||||||
case (mem_raddr_index)
|
|
||||||
2'b00: begin
|
|
||||||
reg_wdata = {24'h0, mem_rdata_i[7:0]};
|
|
||||||
end
|
|
||||||
2'b01: begin
|
|
||||||
reg_wdata = {24'h0, mem_rdata_i[15:8]};
|
|
||||||
end
|
|
||||||
2'b10: begin
|
|
||||||
reg_wdata = {24'h0, mem_rdata_i[23:16]};
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg_wdata = {24'h0, mem_rdata_i[31:24]};
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_LHU: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
mem_req = `RIB_REQ;
|
|
||||||
mem_raddr_o = op1_add_op2_res;
|
|
||||||
if (mem_raddr_index == 2'b0) begin
|
|
||||||
reg_wdata = {16'h0, mem_rdata_i[15:0]};
|
|
||||||
end else begin
|
|
||||||
reg_wdata = {16'h0, mem_rdata_i[31:16]};
|
|
||||||
end
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_TYPE_S: begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_SB: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
mem_we = `WriteEnable;
|
|
||||||
mem_req = `RIB_REQ;
|
|
||||||
mem_waddr_o = op1_add_op2_res;
|
|
||||||
mem_raddr_o = op1_add_op2_res;
|
|
||||||
case (mem_waddr_index)
|
|
||||||
2'b00: begin
|
|
||||||
mem_wdata_o = {mem_rdata_i[31:8], reg2_rdata_i[7:0]};
|
|
||||||
end
|
|
||||||
2'b01: begin
|
|
||||||
mem_wdata_o = {mem_rdata_i[31:16], reg2_rdata_i[7:0], mem_rdata_i[7:0]};
|
|
||||||
end
|
|
||||||
2'b10: begin
|
|
||||||
mem_wdata_o = {mem_rdata_i[31:24], reg2_rdata_i[7:0], mem_rdata_i[15:0]};
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
mem_wdata_o = {reg2_rdata_i[7:0], mem_rdata_i[23:0]};
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_SH: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
mem_we = `WriteEnable;
|
|
||||||
mem_req = `RIB_REQ;
|
|
||||||
mem_waddr_o = op1_add_op2_res;
|
|
||||||
mem_raddr_o = op1_add_op2_res;
|
|
||||||
if (mem_waddr_index == 2'b00) begin
|
|
||||||
mem_wdata_o = {mem_rdata_i[31:16], reg2_rdata_i[15:0]};
|
|
||||||
end else begin
|
|
||||||
mem_wdata_o = {reg2_rdata_i[15:0], mem_rdata_i[15:0]};
|
|
||||||
end
|
|
||||||
end
|
|
||||||
`INST_SW: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
mem_we = `WriteEnable;
|
|
||||||
mem_req = `RIB_REQ;
|
|
||||||
mem_waddr_o = op1_add_op2_res;
|
|
||||||
mem_raddr_o = op1_add_op2_res;
|
|
||||||
mem_wdata_o = reg2_rdata_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_TYPE_B: begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_BEQ: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
jump_flag = op1_eq_op2 & `JumpEnable;
|
|
||||||
jump_addr = {32{op1_eq_op2}} & op1_jump_add_op2_jump_res;
|
|
||||||
end
|
|
||||||
`INST_BNE: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
jump_flag = (~op1_eq_op2) & `JumpEnable;
|
|
||||||
jump_addr = {32{(~op1_eq_op2)}} & op1_jump_add_op2_jump_res;
|
|
||||||
end
|
|
||||||
`INST_BLT: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
jump_flag = (~op1_ge_op2_signed) & `JumpEnable;
|
|
||||||
jump_addr = {32{(~op1_ge_op2_signed)}} & op1_jump_add_op2_jump_res;
|
|
||||||
end
|
|
||||||
`INST_BGE: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
jump_flag = (op1_ge_op2_signed) & `JumpEnable;
|
|
||||||
jump_addr = {32{(op1_ge_op2_signed)}} & op1_jump_add_op2_jump_res;
|
|
||||||
end
|
|
||||||
`INST_BLTU: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
jump_flag = (~op1_ge_op2_unsigned) & `JumpEnable;
|
|
||||||
jump_addr = {32{(~op1_ge_op2_unsigned)}} & op1_jump_add_op2_jump_res;
|
|
||||||
end
|
|
||||||
`INST_BGEU: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
jump_flag = (op1_ge_op2_unsigned) & `JumpEnable;
|
|
||||||
jump_addr = {32{(op1_ge_op2_unsigned)}} & op1_jump_add_op2_jump_res;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_JAL, `INST_JALR: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
jump_flag = `JumpEnable;
|
|
||||||
jump_addr = op1_jump_add_op2_jump_res;
|
|
||||||
reg_wdata = op1_add_op2_res;
|
|
||||||
end
|
|
||||||
`INST_LUI, `INST_AUIPC: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
reg_wdata = op1_add_op2_res;
|
|
||||||
end
|
|
||||||
`INST_NOP_OP: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
`INST_FENCE: begin
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
jump_flag = `JumpEnable;
|
|
||||||
jump_addr = op1_jump_add_op2_jump_res;
|
|
||||||
end
|
|
||||||
`INST_CSR: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
case (funct3)
|
|
||||||
`INST_CSRRW: begin
|
|
||||||
csr_wdata_o = reg1_rdata_i;
|
|
||||||
reg_wdata = csr_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_CSRRS: begin
|
|
||||||
csr_wdata_o = reg1_rdata_i | csr_rdata_i;
|
|
||||||
reg_wdata = csr_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_CSRRC: begin
|
|
||||||
csr_wdata_o = csr_rdata_i & (~reg1_rdata_i);
|
|
||||||
reg_wdata = csr_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_CSRRWI: begin
|
|
||||||
csr_wdata_o = {27'h0, uimm};
|
|
||||||
reg_wdata = csr_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_CSRRSI: begin
|
|
||||||
csr_wdata_o = {27'h0, uimm} | csr_rdata_i;
|
|
||||||
reg_wdata = csr_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_CSRRCI: begin
|
|
||||||
csr_wdata_o = (~{27'h0, uimm}) & csr_rdata_i;
|
|
||||||
reg_wdata = csr_rdata_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
jump_flag = `JumpDisable;
|
|
||||||
hold_flag = `HoldDisable;
|
|
||||||
jump_addr = `ZeroWord;
|
|
||||||
mem_wdata_o = `ZeroWord;
|
|
||||||
mem_raddr_o = `ZeroWord;
|
|
||||||
mem_waddr_o = `ZeroWord;
|
|
||||||
mem_we = `WriteDisable;
|
|
||||||
reg_wdata = `ZeroWord;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,308 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
`define DCSR_CAUSE_NONE 3'h0
|
||||||
|
`define DCSR_CAUSE_STEP 3'h4
|
||||||
|
`define DCSR_CAUSE_DBGREQ 3'h3
|
||||||
|
`define DCSR_CAUSE_EBREAK 3'h1
|
||||||
|
`define DCSR_CAUSE_HALT 3'h5
|
||||||
|
`define DCSR_CAUSE_TRIGGER 3'h2
|
||||||
|
|
||||||
|
|
||||||
|
module exception (
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire inst_valid_i,
|
||||||
|
input wire inst_executed_i,
|
||||||
|
input wire inst_ecall_i, // ecall指令
|
||||||
|
input wire inst_ebreak_i, // ebreak指令
|
||||||
|
input wire inst_mret_i, // mret指令
|
||||||
|
input wire inst_dret_i, // dret指令
|
||||||
|
input wire[31:0] inst_addr_i, // 指令地址
|
||||||
|
|
||||||
|
input wire illegal_inst_i, // 非法指令
|
||||||
|
|
||||||
|
input wire[31:0] mtvec_i, // mtvec寄存器
|
||||||
|
input wire[31:0] mepc_i, // mepc寄存器
|
||||||
|
input wire[31:0] mstatus_i, // mstatus寄存器
|
||||||
|
input wire[31:0] mie_i, // mie寄存器
|
||||||
|
input wire[31:0] dpc_i, // dpc寄存器
|
||||||
|
input wire[31:0] dcsr_i, // dcsr寄存器
|
||||||
|
|
||||||
|
input wire int_req_i,
|
||||||
|
input wire[7:0] int_id_i,
|
||||||
|
|
||||||
|
input wire trigger_match_i,
|
||||||
|
|
||||||
|
input wire[31:0] debug_halt_addr_i,
|
||||||
|
input wire debug_req_i,
|
||||||
|
|
||||||
|
output wire csr_we_o, // 写CSR寄存器标志
|
||||||
|
output wire[31:0] csr_waddr_o, // 写CSR寄存器地址
|
||||||
|
output wire[31:0] csr_wdata_o, // 写CSR寄存器数据
|
||||||
|
|
||||||
|
output wire stall_flag_o, // 流水线暂停标志
|
||||||
|
output wire[31:0] int_addr_o, // 中断入口地址
|
||||||
|
output wire int_assert_o // 中断标志
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
// 异常偏移
|
||||||
|
localparam ILLEGAL_INSTR_OFFSET = 0;
|
||||||
|
localparam INSTR_ADDR_MISA_OFFSET = 4;
|
||||||
|
localparam ECALL_OFFSET = 8;
|
||||||
|
localparam EBREAK_OFFSET = 12;
|
||||||
|
localparam LOAD_MISA_OFFSET = 16;
|
||||||
|
localparam STORE_MISA_OFFSET = 20;
|
||||||
|
localparam RESERVED1_EXCEPTION_OFFSET = 24;
|
||||||
|
localparam RESERVED2_EXCEPTION_OFFSET = 28;
|
||||||
|
// 中断偏移
|
||||||
|
localparam INT_OFFSET = 32;
|
||||||
|
|
||||||
|
localparam S_IDLE = 5'b00001;
|
||||||
|
localparam S_W_MEPC = 5'b00010;
|
||||||
|
localparam S_W_DCSR = 5'b00100;
|
||||||
|
localparam S_ASSERT = 5'b01000;
|
||||||
|
localparam S_W_MSTATUS = 5'b10000;
|
||||||
|
|
||||||
|
reg debug_mode_d, debug_mode_q;
|
||||||
|
reg[4:0] state_d, state_q;
|
||||||
|
reg[31:0] assert_addr_d, assert_addr_q;
|
||||||
|
reg[31:0] return_addr_d, return_addr_q;
|
||||||
|
reg trigger_match_d, trigger_match_q;
|
||||||
|
reg csr_we;
|
||||||
|
reg[31:0] csr_waddr;
|
||||||
|
reg[31:0] csr_wdata;
|
||||||
|
|
||||||
|
reg[7:0] int_id_d, int_id_q;
|
||||||
|
reg in_irq_context_d, in_irq_context_q;
|
||||||
|
wire global_int_en;
|
||||||
|
wire interrupt_req_valid;
|
||||||
|
|
||||||
|
assign global_int_en = mstatus_i[3];
|
||||||
|
|
||||||
|
assign interrupt_req_valid = inst_valid_i &
|
||||||
|
int_req_i &
|
||||||
|
((int_id_i != int_id_q) | (~in_irq_context_q));
|
||||||
|
|
||||||
|
reg exception_req;
|
||||||
|
reg[31:0] exception_cause;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
if (illegal_inst_i) begin
|
||||||
|
exception_req = 1'b1;
|
||||||
|
exception_cause = 32'h0;
|
||||||
|
end else if (inst_ecall_i & inst_valid_i) begin
|
||||||
|
exception_req = 1'b1;
|
||||||
|
exception_cause = 32'h2;
|
||||||
|
end else begin
|
||||||
|
exception_req = 1'b0;
|
||||||
|
exception_cause = 32'h0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
wire int_or_exception_req;
|
||||||
|
wire[31:0] int_or_exception_cause;
|
||||||
|
|
||||||
|
assign int_or_exception_req = (interrupt_req_valid & global_int_en & (~debug_mode_q)) | exception_req;
|
||||||
|
assign int_or_exception_cause = exception_req ? exception_cause : (32'h8 + {24'h0, int_id_i});
|
||||||
|
|
||||||
|
wire trigger_matching;
|
||||||
|
|
||||||
|
gen_ticks_sync #(
|
||||||
|
.DP(5),
|
||||||
|
.DW(1)
|
||||||
|
) gen_trigger_sync (
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.clk(clk),
|
||||||
|
.din(trigger_match_q),
|
||||||
|
.dout(trigger_matching)
|
||||||
|
);
|
||||||
|
|
||||||
|
reg enter_debug_cause_debugger_req;
|
||||||
|
reg enter_debug_cause_single_step;
|
||||||
|
reg enter_debug_cause_ebreak;
|
||||||
|
reg enter_debug_cause_reset_halt;
|
||||||
|
reg enter_debug_cause_trigger;
|
||||||
|
reg[2:0] dcsr_cause_d, dcsr_cause_q;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
enter_debug_cause_debugger_req = 1'b0;
|
||||||
|
enter_debug_cause_single_step = 1'b0;
|
||||||
|
enter_debug_cause_ebreak = 1'b0;
|
||||||
|
enter_debug_cause_reset_halt = 1'b0;
|
||||||
|
enter_debug_cause_trigger = 1'b0;
|
||||||
|
dcsr_cause_d = `DCSR_CAUSE_NONE;
|
||||||
|
|
||||||
|
if (trigger_match_i & inst_valid_i & (~trigger_matching)) begin
|
||||||
|
enter_debug_cause_trigger = 1'b1;
|
||||||
|
dcsr_cause_d = `DCSR_CAUSE_TRIGGER;
|
||||||
|
end else if (inst_ebreak_i & inst_valid_i) begin
|
||||||
|
enter_debug_cause_ebreak = 1'b1;
|
||||||
|
dcsr_cause_d = `DCSR_CAUSE_EBREAK;
|
||||||
|
end else if ((inst_addr_i == `CPU_RESET_ADDR) & inst_valid_i & debug_req_i) begin
|
||||||
|
enter_debug_cause_reset_halt = 1'b1;
|
||||||
|
dcsr_cause_d = `DCSR_CAUSE_HALT;
|
||||||
|
end else if ((~debug_mode_q) & debug_req_i & inst_valid_i) begin
|
||||||
|
enter_debug_cause_debugger_req = 1'b1;
|
||||||
|
dcsr_cause_d = `DCSR_CAUSE_DBGREQ;
|
||||||
|
end else if ((~debug_mode_q) & dcsr_i[2] & inst_valid_i & inst_executed_i) begin
|
||||||
|
enter_debug_cause_single_step = 1'b1;
|
||||||
|
dcsr_cause_d = `DCSR_CAUSE_STEP;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
wire debug_mode_req = enter_debug_cause_debugger_req |
|
||||||
|
enter_debug_cause_single_step |
|
||||||
|
enter_debug_cause_reset_halt |
|
||||||
|
enter_debug_cause_trigger |
|
||||||
|
enter_debug_cause_ebreak;
|
||||||
|
|
||||||
|
assign stall_flag_o = ((state_q != S_IDLE) & (state_q != S_ASSERT)) |
|
||||||
|
int_or_exception_req |
|
||||||
|
debug_mode_req |
|
||||||
|
inst_mret_i |
|
||||||
|
inst_dret_i;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
state_d = state_q;
|
||||||
|
assert_addr_d = assert_addr_q;
|
||||||
|
debug_mode_d = debug_mode_q;
|
||||||
|
return_addr_d = return_addr_q;
|
||||||
|
csr_we = 1'b0;
|
||||||
|
csr_waddr = 32'h0;
|
||||||
|
csr_wdata = 32'h0;
|
||||||
|
trigger_match_d = trigger_match_q;
|
||||||
|
int_id_d = int_id_q;
|
||||||
|
in_irq_context_d = in_irq_context_q;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
if (int_or_exception_req & (!debug_mode_q)) begin
|
||||||
|
csr_we = 1'b1;
|
||||||
|
csr_waddr = {20'h0, `CSR_MCAUSE};
|
||||||
|
csr_wdata = int_or_exception_cause;
|
||||||
|
assert_addr_d = mtvec_i;
|
||||||
|
return_addr_d = inst_addr_i;
|
||||||
|
state_d = S_W_MSTATUS;
|
||||||
|
int_id_d = int_id_i;
|
||||||
|
in_irq_context_d = 1'b1;
|
||||||
|
end else if (debug_mode_req) begin
|
||||||
|
debug_mode_d = 1'b1;
|
||||||
|
if (enter_debug_cause_debugger_req |
|
||||||
|
enter_debug_cause_single_step |
|
||||||
|
enter_debug_cause_trigger |
|
||||||
|
enter_debug_cause_reset_halt) begin
|
||||||
|
csr_we = 1'b1;
|
||||||
|
csr_waddr = {20'h0, `CSR_DPC};
|
||||||
|
csr_wdata = enter_debug_cause_reset_halt ? (`CPU_RESET_ADDR) : inst_addr_i;
|
||||||
|
// when run openocd compliance test, use it.
|
||||||
|
// openocd compliance test bug: It report test fail when the reset address is 0x0:
|
||||||
|
// "NDMRESET should move DPC to reset value."
|
||||||
|
//csr_wdata = enter_debug_cause_reset_halt ? (`CPU_RESET_ADDR + 4'h4) : inst_addr_i;
|
||||||
|
end
|
||||||
|
if (enter_debug_cause_trigger) begin
|
||||||
|
trigger_match_d = 1'b1;
|
||||||
|
end
|
||||||
|
assert_addr_d = debug_halt_addr_i;
|
||||||
|
// ebreak do not change dpc and dcsr value
|
||||||
|
if (enter_debug_cause_ebreak) begin
|
||||||
|
state_d = S_ASSERT;
|
||||||
|
end else begin
|
||||||
|
state_d = S_W_DCSR;
|
||||||
|
end
|
||||||
|
end else if (inst_mret_i) begin
|
||||||
|
in_irq_context_d = 1'b0;
|
||||||
|
assert_addr_d = mepc_i;
|
||||||
|
csr_we = 1'b1;
|
||||||
|
csr_waddr = {20'h0, `CSR_MSTATUS};
|
||||||
|
// 开全局中断
|
||||||
|
csr_wdata = {mstatus_i[31:4], 1'b1, mstatus_i[2:0]};
|
||||||
|
state_d = S_ASSERT;
|
||||||
|
end else if (inst_dret_i) begin
|
||||||
|
assert_addr_d = dpc_i;
|
||||||
|
state_d = S_ASSERT;
|
||||||
|
debug_mode_d = 1'b0;
|
||||||
|
trigger_match_d = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_W_MSTATUS: begin
|
||||||
|
csr_we = 1'b1;
|
||||||
|
csr_waddr = {20'h0, `CSR_MSTATUS};
|
||||||
|
// 关全局中断
|
||||||
|
csr_wdata = {mstatus_i[31:4], 1'b0, mstatus_i[2:0]};
|
||||||
|
state_d = S_W_MEPC;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_W_MEPC: begin
|
||||||
|
csr_we = 1'b1;
|
||||||
|
csr_waddr = {20'h0, `CSR_MEPC};
|
||||||
|
csr_wdata = return_addr_q;
|
||||||
|
state_d = S_ASSERT;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_W_DCSR: begin
|
||||||
|
csr_we = 1'b1;
|
||||||
|
csr_waddr = {20'h0, `CSR_DCSR};
|
||||||
|
csr_wdata = {dcsr_i[31:9], dcsr_cause_q, dcsr_i[5:0]};
|
||||||
|
state_d = S_ASSERT;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_ASSERT: begin
|
||||||
|
csr_we = 1'b0;
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
|
||||||
|
default:;
|
||||||
|
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign csr_we_o = csr_we;
|
||||||
|
assign csr_waddr_o = csr_waddr;
|
||||||
|
assign csr_wdata_o = csr_wdata;
|
||||||
|
|
||||||
|
assign int_assert_o = (state_q == S_ASSERT);
|
||||||
|
assign int_addr_o = assert_addr_q;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
assert_addr_q <= 32'h0;
|
||||||
|
debug_mode_q <= 1'b0;
|
||||||
|
return_addr_q <= 32'h0;
|
||||||
|
dcsr_cause_q <= `DCSR_CAUSE_NONE;
|
||||||
|
trigger_match_q <= 1'b0;
|
||||||
|
int_id_q <= 8'h0;
|
||||||
|
in_irq_context_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
assert_addr_q <= assert_addr_d;
|
||||||
|
debug_mode_q <= debug_mode_d;
|
||||||
|
return_addr_q <= return_addr_d;
|
||||||
|
dcsr_cause_q <= dcsr_cause_d;
|
||||||
|
trigger_match_q <= trigger_match_d;
|
||||||
|
int_id_q <= int_id_d;
|
||||||
|
in_irq_context_q <= in_irq_context_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,428 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 执行模块
|
||||||
|
module exu #(
|
||||||
|
parameter bit BranchPredictor = 1'b1
|
||||||
|
)(
|
||||||
|
input wire clk, // 时钟
|
||||||
|
input wire rst_n, // 复位
|
||||||
|
|
||||||
|
// exception
|
||||||
|
input wire int_assert_i, // 中断发生标志
|
||||||
|
input wire[31:0] int_addr_i, // 中断跳转地址
|
||||||
|
input wire int_stall_i, // 暂停标志
|
||||||
|
output wire inst_ecall_o, // ecall指令
|
||||||
|
output wire inst_ebreak_o, // ebreak指令
|
||||||
|
output wire inst_mret_o, // mret指令
|
||||||
|
output wire inst_dret_o, // dret指令
|
||||||
|
|
||||||
|
// mem
|
||||||
|
input wire[31:0] mem_rdata_i, // 内存输入数据
|
||||||
|
input wire mem_gnt_i, // 总线授权
|
||||||
|
input wire mem_rvalid_i, // 总线响应
|
||||||
|
output wire[31:0] mem_wdata_o, // 写内存数据
|
||||||
|
output wire[31:0] mem_addr_o, // 读、写内存地址
|
||||||
|
output wire mem_we_o, // 是否要写内存
|
||||||
|
output wire[3:0] mem_be_o, // 字节位
|
||||||
|
output wire mem_req_o, // 访存请求
|
||||||
|
output wire mem_access_misaligned_o, // 访存不对齐
|
||||||
|
|
||||||
|
// to gpr_reg
|
||||||
|
output wire[31:0] reg_wdata_o, // 写寄存器数据
|
||||||
|
output wire reg_we_o, // 是否要写通用寄存器
|
||||||
|
output wire[4:0] reg_waddr_o, // 写通用寄存器地址
|
||||||
|
|
||||||
|
// csr_reg
|
||||||
|
input wire[31:0] csr_rdata_i, // CSR寄存器数据
|
||||||
|
output wire[31:0] csr_raddr_o, // 读CSR寄存器地址
|
||||||
|
output wire[31:0] csr_wdata_o, // 写CSR寄存器数据
|
||||||
|
output wire csr_we_o, // 是否要写CSR寄存器
|
||||||
|
output wire[31:0] csr_waddr_o, // 写CSR寄存器地址
|
||||||
|
|
||||||
|
// to pipe_ctrl
|
||||||
|
output wire hold_flag_o, // 是否暂停标志
|
||||||
|
output wire jump_flag_o, // 是否跳转标志
|
||||||
|
output wire[31:0] jump_addr_o, // 跳转目的地址
|
||||||
|
|
||||||
|
//
|
||||||
|
output wire inst_valid_o, // 指令有效
|
||||||
|
output wire inst_executed_o, // 指令已经执行完毕
|
||||||
|
|
||||||
|
// from idu_exu
|
||||||
|
input wire inst_valid_i,
|
||||||
|
input wire[31:0] inst_i,
|
||||||
|
input wire[`DECINFO_WIDTH-1:0] dec_info_bus_i,
|
||||||
|
input wire[31:0] dec_imm_i,
|
||||||
|
input wire[31:0] dec_pc_i,
|
||||||
|
input wire[31:0] next_pc_i,
|
||||||
|
input wire[4:0] rd_waddr_i,
|
||||||
|
input wire[31:0] reg1_rdata_i, // 通用寄存器1输入数据
|
||||||
|
input wire[31:0] reg2_rdata_i, // 通用寄存器2输入数据
|
||||||
|
input wire rd_we_i
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
wire[31:0] next_pc = dec_pc_i + 4'h4;
|
||||||
|
|
||||||
|
// dispatch to ALU
|
||||||
|
wire[31:0] alu_op1_o;
|
||||||
|
wire[31:0] alu_op2_o;
|
||||||
|
wire req_alu_o;
|
||||||
|
wire alu_op_lui_o;
|
||||||
|
wire alu_op_auipc_o;
|
||||||
|
wire alu_op_add_o;
|
||||||
|
wire alu_op_sub_o;
|
||||||
|
wire alu_op_sll_o;
|
||||||
|
wire alu_op_slt_o;
|
||||||
|
wire alu_op_sltu_o;
|
||||||
|
wire alu_op_xor_o;
|
||||||
|
wire alu_op_srl_o;
|
||||||
|
wire alu_op_sra_o;
|
||||||
|
wire alu_op_or_o;
|
||||||
|
wire alu_op_and_o;
|
||||||
|
// dispatch to BJP
|
||||||
|
wire[31:0] bjp_op1_o;
|
||||||
|
wire[31:0] bjp_op2_o;
|
||||||
|
wire[31:0] bjp_jump_op1_o;
|
||||||
|
wire[31:0] bjp_jump_op2_o;
|
||||||
|
wire req_bjp_o;
|
||||||
|
wire bjp_op_jump_o;
|
||||||
|
wire bjp_op_beq_o;
|
||||||
|
wire bjp_op_bne_o;
|
||||||
|
wire bjp_op_blt_o;
|
||||||
|
wire bjp_op_bltu_o;
|
||||||
|
wire bjp_op_bge_o;
|
||||||
|
wire bjp_op_bgeu_o;
|
||||||
|
wire bjp_op_jalr_o;
|
||||||
|
// dispatch to MULDIV
|
||||||
|
wire req_muldiv_o;
|
||||||
|
wire[31:0] muldiv_op1_o;
|
||||||
|
wire[31:0] muldiv_op2_o;
|
||||||
|
wire muldiv_op_mul_o;
|
||||||
|
wire muldiv_op_mulh_o;
|
||||||
|
wire muldiv_op_mulhsu_o;
|
||||||
|
wire muldiv_op_mulhu_o;
|
||||||
|
wire muldiv_op_div_o;
|
||||||
|
wire muldiv_op_divu_o;
|
||||||
|
wire muldiv_op_rem_o;
|
||||||
|
wire muldiv_op_remu_o;
|
||||||
|
// dispatch to CSR
|
||||||
|
wire req_csr_o;
|
||||||
|
wire[31:0] csr_op1_o;
|
||||||
|
wire[31:0] csr_addr_o;
|
||||||
|
wire csr_csrrw_o;
|
||||||
|
wire csr_csrrs_o;
|
||||||
|
wire csr_csrrc_o;
|
||||||
|
// dispatch to MEM
|
||||||
|
wire req_mem_o;
|
||||||
|
wire[31:0] mem_op1_o;
|
||||||
|
wire[31:0] mem_op2_o;
|
||||||
|
wire[31:0] mem_rs2_data_o;
|
||||||
|
wire mem_op_lb_o;
|
||||||
|
wire mem_op_lh_o;
|
||||||
|
wire mem_op_lw_o;
|
||||||
|
wire mem_op_lbu_o;
|
||||||
|
wire mem_op_lhu_o;
|
||||||
|
wire mem_op_sb_o;
|
||||||
|
wire mem_op_sh_o;
|
||||||
|
wire mem_op_sw_o;
|
||||||
|
// dispatch to SYS
|
||||||
|
wire sys_op_nop_o;
|
||||||
|
wire sys_op_mret_o;
|
||||||
|
wire sys_op_ecall_o;
|
||||||
|
wire sys_op_ebreak_o;
|
||||||
|
wire sys_op_fence_o;
|
||||||
|
wire sys_op_dret_o;
|
||||||
|
|
||||||
|
exu_dispatch u_exu_dispatch(
|
||||||
|
// input
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.dec_info_bus_i(dec_info_bus_i),
|
||||||
|
.dec_imm_i(dec_imm_i),
|
||||||
|
.dec_pc_i(dec_pc_i),
|
||||||
|
.rs1_rdata_i(reg1_rdata_i),
|
||||||
|
.rs2_rdata_i(reg2_rdata_i),
|
||||||
|
// dispatch to ALU
|
||||||
|
.alu_op1_o(alu_op1_o),
|
||||||
|
.alu_op2_o(alu_op2_o),
|
||||||
|
.req_alu_o(req_alu_o),
|
||||||
|
.alu_op_lui_o(alu_op_lui_o),
|
||||||
|
.alu_op_auipc_o(alu_op_auipc_o),
|
||||||
|
.alu_op_add_o(alu_op_add_o),
|
||||||
|
.alu_op_sub_o(alu_op_sub_o),
|
||||||
|
.alu_op_sll_o(alu_op_sll_o),
|
||||||
|
.alu_op_slt_o(alu_op_slt_o),
|
||||||
|
.alu_op_sltu_o(alu_op_sltu_o),
|
||||||
|
.alu_op_xor_o(alu_op_xor_o),
|
||||||
|
.alu_op_srl_o(alu_op_srl_o),
|
||||||
|
.alu_op_sra_o(alu_op_sra_o),
|
||||||
|
.alu_op_or_o(alu_op_or_o),
|
||||||
|
.alu_op_and_o(alu_op_and_o),
|
||||||
|
// dispatch to BJP
|
||||||
|
.bjp_op1_o(bjp_op1_o),
|
||||||
|
.bjp_op2_o(bjp_op2_o),
|
||||||
|
.bjp_jump_op1_o(bjp_jump_op1_o),
|
||||||
|
.bjp_jump_op2_o(bjp_jump_op2_o),
|
||||||
|
.req_bjp_o(req_bjp_o),
|
||||||
|
.bjp_op_jump_o(bjp_op_jump_o),
|
||||||
|
.bjp_op_beq_o(bjp_op_beq_o),
|
||||||
|
.bjp_op_bne_o(bjp_op_bne_o),
|
||||||
|
.bjp_op_blt_o(bjp_op_blt_o),
|
||||||
|
.bjp_op_bltu_o(bjp_op_bltu_o),
|
||||||
|
.bjp_op_bge_o(bjp_op_bge_o),
|
||||||
|
.bjp_op_bgeu_o(bjp_op_bgeu_o),
|
||||||
|
.bjp_op_jalr_o(bjp_op_jalr_o),
|
||||||
|
// dispatch to MULDIV
|
||||||
|
.req_muldiv_o(req_muldiv_o),
|
||||||
|
.muldiv_op1_o(muldiv_op1_o),
|
||||||
|
.muldiv_op2_o(muldiv_op2_o),
|
||||||
|
.muldiv_op_mul_o(muldiv_op_mul_o),
|
||||||
|
.muldiv_op_mulh_o(muldiv_op_mulh_o),
|
||||||
|
.muldiv_op_mulhsu_o(muldiv_op_mulhsu_o),
|
||||||
|
.muldiv_op_mulhu_o(muldiv_op_mulhu_o),
|
||||||
|
.muldiv_op_div_o(muldiv_op_div_o),
|
||||||
|
.muldiv_op_divu_o(muldiv_op_divu_o),
|
||||||
|
.muldiv_op_rem_o(muldiv_op_rem_o),
|
||||||
|
.muldiv_op_remu_o(muldiv_op_remu_o),
|
||||||
|
// dispatch to CSR
|
||||||
|
.req_csr_o(req_csr_o),
|
||||||
|
.csr_op1_o(csr_op1_o),
|
||||||
|
.csr_addr_o(csr_addr_o),
|
||||||
|
.csr_csrrw_o(csr_csrrw_o),
|
||||||
|
.csr_csrrs_o(csr_csrrs_o),
|
||||||
|
.csr_csrrc_o(csr_csrrc_o),
|
||||||
|
// dispatch to MEM
|
||||||
|
.req_mem_o(req_mem_o),
|
||||||
|
.mem_op1_o(mem_op1_o),
|
||||||
|
.mem_op2_o(mem_op2_o),
|
||||||
|
.mem_rs2_data_o(mem_rs2_data_o),
|
||||||
|
.mem_op_lb_o(mem_op_lb_o),
|
||||||
|
.mem_op_lh_o(mem_op_lh_o),
|
||||||
|
.mem_op_lw_o(mem_op_lw_o),
|
||||||
|
.mem_op_lbu_o(mem_op_lbu_o),
|
||||||
|
.mem_op_lhu_o(mem_op_lhu_o),
|
||||||
|
.mem_op_sb_o(mem_op_sb_o),
|
||||||
|
.mem_op_sh_o(mem_op_sh_o),
|
||||||
|
.mem_op_sw_o(mem_op_sw_o),
|
||||||
|
// dispatch to SYS
|
||||||
|
.sys_op_nop_o(sys_op_nop_o),
|
||||||
|
.sys_op_mret_o(sys_op_mret_o),
|
||||||
|
.sys_op_ecall_o(sys_op_ecall_o),
|
||||||
|
.sys_op_ebreak_o(sys_op_ebreak_o),
|
||||||
|
.sys_op_fence_o(sys_op_fence_o),
|
||||||
|
.sys_op_dret_o(sys_op_dret_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign inst_ecall_o = sys_op_ecall_o;
|
||||||
|
assign inst_ebreak_o = sys_op_ebreak_o;
|
||||||
|
assign inst_mret_o = sys_op_mret_o;
|
||||||
|
assign inst_dret_o = sys_op_dret_o;
|
||||||
|
|
||||||
|
wire[31:0] alu_res_o;
|
||||||
|
wire[31:0] bjp_res_o;
|
||||||
|
wire bjp_cmp_res_o;
|
||||||
|
wire[31:0] csr_op1 = csr_csrrc_o? (~csr_op1_o): csr_op1_o;
|
||||||
|
wire[31:0] csr_op2 = csr_csrrw_o? (32'h0): csr_rdata_i;
|
||||||
|
|
||||||
|
exu_alu_datapath u_exu_alu_datapath(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
// ALU
|
||||||
|
.req_alu_i(req_alu_o),
|
||||||
|
.alu_op1_i(alu_op1_o),
|
||||||
|
.alu_op2_i(alu_op2_o),
|
||||||
|
.alu_op_add_i(alu_op_add_o | alu_op_lui_o | alu_op_auipc_o),
|
||||||
|
.alu_op_sub_i(alu_op_sub_o),
|
||||||
|
.alu_op_sll_i(alu_op_sll_o),
|
||||||
|
.alu_op_slt_i(alu_op_slt_o),
|
||||||
|
.alu_op_sltu_i(alu_op_sltu_o),
|
||||||
|
.alu_op_xor_i(alu_op_xor_o),
|
||||||
|
.alu_op_srl_i(alu_op_srl_o),
|
||||||
|
.alu_op_sra_i(alu_op_sra_o),
|
||||||
|
.alu_op_or_i(alu_op_or_o),
|
||||||
|
.alu_op_and_i(alu_op_and_o),
|
||||||
|
// BJP
|
||||||
|
.req_bjp_i(req_bjp_o),
|
||||||
|
.bjp_op1_i(bjp_op1_o),
|
||||||
|
.bjp_op2_i(bjp_op2_o),
|
||||||
|
.bjp_op_beq_i(bjp_op_beq_o),
|
||||||
|
.bjp_op_bne_i(bjp_op_bne_o),
|
||||||
|
.bjp_op_blt_i(bjp_op_blt_o),
|
||||||
|
.bjp_op_bltu_i(bjp_op_bltu_o),
|
||||||
|
.bjp_op_bge_i(bjp_op_bge_o),
|
||||||
|
.bjp_op_bgeu_i(bjp_op_bgeu_o),
|
||||||
|
.bjp_op_jump_i(bjp_op_jump_o),
|
||||||
|
.bjp_jump_op1_i(bjp_jump_op1_o),
|
||||||
|
.bjp_jump_op2_i(bjp_jump_op2_o),
|
||||||
|
// MEM
|
||||||
|
.req_mem_i(req_mem_o),
|
||||||
|
.mem_op1_i(mem_op1_o),
|
||||||
|
.mem_op2_i(mem_op2_o),
|
||||||
|
// CSR
|
||||||
|
.req_csr_i(req_csr_o),
|
||||||
|
.csr_op1_i(csr_op1),
|
||||||
|
.csr_op2_i(csr_op2),
|
||||||
|
.csr_csrrw_i(csr_csrrw_o),
|
||||||
|
.csr_csrrs_i(csr_csrrs_o),
|
||||||
|
.csr_csrrc_i(csr_csrrc_o),
|
||||||
|
|
||||||
|
.alu_res_o(alu_res_o),
|
||||||
|
.bjp_res_o(bjp_res_o),
|
||||||
|
.bjp_cmp_res_o(bjp_cmp_res_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
wire mem_reg_we_o;
|
||||||
|
wire mem_mem_we_o;
|
||||||
|
wire[31:0] mem_wdata;
|
||||||
|
wire mem_stall_o;
|
||||||
|
|
||||||
|
exu_mem u_exu_mem(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.req_mem_i(req_mem_o),
|
||||||
|
.mem_addr_i(alu_res_o),
|
||||||
|
.mem_rs2_data_i(mem_rs2_data_o),
|
||||||
|
.mem_gnt_i(mem_gnt_i),
|
||||||
|
.mem_rvalid_i(mem_rvalid_i),
|
||||||
|
.mem_rdata_i(mem_rdata_i),
|
||||||
|
.mem_op_lb_i(mem_op_lb_o),
|
||||||
|
.mem_op_lh_i(mem_op_lh_o),
|
||||||
|
.mem_op_lw_i(mem_op_lw_o),
|
||||||
|
.mem_op_lbu_i(mem_op_lbu_o),
|
||||||
|
.mem_op_lhu_i(mem_op_lhu_o),
|
||||||
|
.mem_op_sb_i(mem_op_sb_o),
|
||||||
|
.mem_op_sh_i(mem_op_sh_o),
|
||||||
|
.mem_op_sw_i(mem_op_sw_o),
|
||||||
|
.mem_access_misaligned_o(mem_access_misaligned_o),
|
||||||
|
.mem_stall_o(mem_stall_o),
|
||||||
|
.mem_addr_o(mem_addr_o),
|
||||||
|
.mem_wdata_o(mem_wdata),
|
||||||
|
.mem_reg_we_o(mem_reg_we_o),
|
||||||
|
.mem_mem_we_o(mem_mem_we_o),
|
||||||
|
.mem_be_o(mem_be_o),
|
||||||
|
.mem_req_o(mem_req_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
wire[31:0] muldiv_reg_wdata_o;
|
||||||
|
wire muldiv_reg_we_o;
|
||||||
|
wire muldiv_stall_o;
|
||||||
|
|
||||||
|
exu_muldiv u_exu_muldiv(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.muldiv_op1_i(muldiv_op1_o),
|
||||||
|
.muldiv_op2_i(muldiv_op2_o),
|
||||||
|
.muldiv_op_mul_i(muldiv_op_mul_o),
|
||||||
|
.muldiv_op_mulh_i(muldiv_op_mulh_o),
|
||||||
|
.muldiv_op_mulhsu_i(muldiv_op_mulhsu_o),
|
||||||
|
.muldiv_op_mulhu_i(muldiv_op_mulhu_o),
|
||||||
|
.muldiv_op_div_i(muldiv_op_div_o),
|
||||||
|
.muldiv_op_divu_i(muldiv_op_divu_o),
|
||||||
|
.muldiv_op_rem_i(muldiv_op_rem_o),
|
||||||
|
.muldiv_op_remu_i(muldiv_op_remu_o),
|
||||||
|
.int_stall_i(int_stall_i),
|
||||||
|
.muldiv_reg_wdata_o(muldiv_reg_wdata_o),
|
||||||
|
.muldiv_reg_we_o(muldiv_reg_we_o),
|
||||||
|
.muldiv_stall_o(muldiv_stall_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
wire commit_reg_we_o;
|
||||||
|
|
||||||
|
exu_commit u_exu_commit(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.req_muldiv_i(req_muldiv_o),
|
||||||
|
.muldiv_reg_we_i(muldiv_reg_we_o),
|
||||||
|
.muldiv_reg_waddr_i(rd_waddr_i),
|
||||||
|
.muldiv_reg_wdata_i(muldiv_reg_wdata_o),
|
||||||
|
.req_mem_i(req_mem_o),
|
||||||
|
.mem_reg_we_i(mem_reg_we_o),
|
||||||
|
.mem_reg_waddr_i(rd_waddr_i),
|
||||||
|
.mem_reg_wdata_i(mem_wdata),
|
||||||
|
.req_csr_i(req_csr_o),
|
||||||
|
.csr_reg_we_i(req_csr_o),
|
||||||
|
.csr_reg_waddr_i(rd_waddr_i),
|
||||||
|
.csr_reg_wdata_i(csr_rdata_i),
|
||||||
|
.req_bjp_i(req_bjp_o),
|
||||||
|
.bjp_reg_we_i(bjp_op_jump_o),
|
||||||
|
.bjp_reg_wdata_i(next_pc),
|
||||||
|
.bjp_reg_waddr_i(rd_waddr_i),
|
||||||
|
.rd_we_i(rd_we_i),
|
||||||
|
.rd_waddr_i(rd_waddr_i),
|
||||||
|
.alu_reg_wdata_i(alu_res_o),
|
||||||
|
.reg_we_o(commit_reg_we_o),
|
||||||
|
.reg_waddr_o(reg_waddr_o),
|
||||||
|
.reg_wdata_o(reg_wdata_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign reg_we_o = commit_reg_we_o & (~int_stall_i);
|
||||||
|
|
||||||
|
wire prdt_taken;
|
||||||
|
|
||||||
|
if (BranchPredictor) begin: g_branch_predictor
|
||||||
|
// jal
|
||||||
|
assign prdt_taken = ((~bjp_op_jalr_o) & bjp_op_jump_o) |
|
||||||
|
// bxx & imm[31]
|
||||||
|
(req_bjp_o & (~bjp_op_jump_o) & dec_imm_i[31]);
|
||||||
|
end else begin: g_no_branch_predictor
|
||||||
|
assign prdt_taken = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// bxx分支预测错误
|
||||||
|
wire prdt_taken_error = prdt_taken & (~bjp_cmp_res_o) & req_bjp_o & (~bjp_op_jump_o);
|
||||||
|
|
||||||
|
wire inst_jump = (bjp_cmp_res_o & (~prdt_taken)) |
|
||||||
|
(bjp_op_jump_o & (~prdt_taken)) |
|
||||||
|
sys_op_fence_o;
|
||||||
|
assign jump_flag_o = ((inst_jump | prdt_taken_error) & (~int_stall_i)) | int_assert_i;
|
||||||
|
assign jump_addr_o = int_assert_i? int_addr_i:
|
||||||
|
sys_op_fence_o? next_pc:
|
||||||
|
prdt_taken_error? next_pc:
|
||||||
|
bjp_res_o;
|
||||||
|
assign hold_flag_o = muldiv_stall_o | mem_stall_o;
|
||||||
|
|
||||||
|
assign csr_raddr_o = csr_addr_o;
|
||||||
|
assign csr_waddr_o = csr_addr_o;
|
||||||
|
assign csr_we_o = req_csr_o & (~int_stall_i);
|
||||||
|
assign csr_wdata_o = alu_res_o;
|
||||||
|
|
||||||
|
assign mem_we_o = mem_mem_we_o & (~int_stall_i);
|
||||||
|
assign mem_wdata_o = mem_wdata;
|
||||||
|
|
||||||
|
assign inst_valid_o = hold_flag_o? 1'b0: inst_valid_i;
|
||||||
|
|
||||||
|
reg inst_executed_q;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
inst_executed_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
if (inst_valid_i) begin
|
||||||
|
inst_executed_q <= (inst_jump & (~int_stall_i)) |
|
||||||
|
reg_we_o |
|
||||||
|
csr_we_o |
|
||||||
|
mem_we_o;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign inst_executed_o = inst_executed_q;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
|
||||||
|
`define DATAPATH_MUX_WIDTH (32+32+16)
|
||||||
|
|
||||||
|
|
||||||
|
module exu_alu_datapath(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
// ALU
|
||||||
|
input wire req_alu_i,
|
||||||
|
input wire[31:0] alu_op1_i,
|
||||||
|
input wire[31:0] alu_op2_i,
|
||||||
|
input wire alu_op_add_i,
|
||||||
|
input wire alu_op_sub_i,
|
||||||
|
input wire alu_op_sll_i,
|
||||||
|
input wire alu_op_slt_i,
|
||||||
|
input wire alu_op_sltu_i,
|
||||||
|
input wire alu_op_xor_i,
|
||||||
|
input wire alu_op_srl_i,
|
||||||
|
input wire alu_op_sra_i,
|
||||||
|
input wire alu_op_or_i,
|
||||||
|
input wire alu_op_and_i,
|
||||||
|
|
||||||
|
// BJP
|
||||||
|
input wire req_bjp_i,
|
||||||
|
input wire[31:0] bjp_op1_i,
|
||||||
|
input wire[31:0] bjp_op2_i,
|
||||||
|
input wire bjp_op_beq_i,
|
||||||
|
input wire bjp_op_bne_i,
|
||||||
|
input wire bjp_op_blt_i,
|
||||||
|
input wire bjp_op_bltu_i,
|
||||||
|
input wire bjp_op_bge_i,
|
||||||
|
input wire bjp_op_bgeu_i,
|
||||||
|
input wire bjp_op_jump_i,
|
||||||
|
input wire[31:0] bjp_jump_op1_i,
|
||||||
|
input wire[31:0] bjp_jump_op2_i,
|
||||||
|
|
||||||
|
// MEM
|
||||||
|
input wire req_mem_i,
|
||||||
|
input wire[31:0] mem_op1_i,
|
||||||
|
input wire[31:0] mem_op2_i,
|
||||||
|
|
||||||
|
// CSR
|
||||||
|
input wire req_csr_i,
|
||||||
|
input wire[31:0] csr_op1_i,
|
||||||
|
input wire[31:0] csr_op2_i,
|
||||||
|
input wire csr_csrrw_i,
|
||||||
|
input wire csr_csrrs_i,
|
||||||
|
input wire csr_csrrc_i,
|
||||||
|
|
||||||
|
output wire[31:0] alu_res_o,
|
||||||
|
output wire[31:0] bjp_res_o,
|
||||||
|
output wire bjp_cmp_res_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
wire[31:0] mux_op1;
|
||||||
|
wire[31:0] mux_op2;
|
||||||
|
wire op_add;
|
||||||
|
wire op_sub;
|
||||||
|
wire op_sll;
|
||||||
|
wire op_slt;
|
||||||
|
wire op_sltu;
|
||||||
|
wire op_xor;
|
||||||
|
wire op_srl;
|
||||||
|
wire op_sra;
|
||||||
|
wire op_or;
|
||||||
|
wire op_and;
|
||||||
|
wire op_beq;
|
||||||
|
wire op_bne;
|
||||||
|
wire op_blt;
|
||||||
|
wire op_bltu;
|
||||||
|
wire op_bge;
|
||||||
|
wire op_bgeu;
|
||||||
|
|
||||||
|
// 异或
|
||||||
|
wire[31:0] xor_res = mux_op1 ^ mux_op2;
|
||||||
|
// 或
|
||||||
|
wire[31:0] or_res = mux_op1 | mux_op2;
|
||||||
|
// 与
|
||||||
|
wire[31:0] and_res = mux_op1 & mux_op2;
|
||||||
|
// 加、减
|
||||||
|
wire[31:0] add_op1 = req_bjp_i? bjp_jump_op1_i: mux_op1;
|
||||||
|
wire[31:0] add_op2 = req_bjp_i? bjp_jump_op2_i: mux_op2;
|
||||||
|
wire[31:0] add_sub_res = add_op1 + (op_sub? (-add_op2): add_op2);
|
||||||
|
// 左移
|
||||||
|
wire[31:0] sll_res = mux_op1 << mux_op2[4:0];
|
||||||
|
// 逻辑右移
|
||||||
|
wire[31:0] srl_res = mux_op1 >> mux_op2[4:0];
|
||||||
|
// 算数右移
|
||||||
|
wire[31:0] sr_shift_mask = 32'hffffffff >> mux_op2[4:0];
|
||||||
|
wire[31:0] sra_res = (srl_res & sr_shift_mask) | ({32{mux_op1[31]}} & (~sr_shift_mask));
|
||||||
|
|
||||||
|
// 有符号数比较
|
||||||
|
wire op1_ge_op2_signed = ($signed(mux_op1) >= $signed(mux_op2));
|
||||||
|
// 无符号数比较
|
||||||
|
wire op1_ge_op2_unsigned = (mux_op1 >= mux_op2);
|
||||||
|
|
||||||
|
wire op1_neq_op2 = (|xor_res);
|
||||||
|
wire op1_eq_op2 = (~op1_neq_op2);
|
||||||
|
|
||||||
|
wire cmp_res_eq = op_beq & op1_eq_op2;
|
||||||
|
wire cmp_res_neq = op_bne & op1_neq_op2;
|
||||||
|
wire cmp_res_lt = op_blt & (~op1_ge_op2_signed);
|
||||||
|
wire cmp_res_ltu = op_bltu & (~op1_ge_op2_unsigned);
|
||||||
|
wire cmp_res_gt = op_bge & op1_ge_op2_signed;
|
||||||
|
wire cmp_res_gtu = op_bgeu & op1_ge_op2_unsigned;
|
||||||
|
|
||||||
|
wire[31:0] slt_res = (~op1_ge_op2_signed)? 32'h1: 32'h0;
|
||||||
|
wire[31:0] sltu_res = (~op1_ge_op2_unsigned)? 32'h1: 32'h0;
|
||||||
|
|
||||||
|
reg[31:0] alu_datapath_res;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
alu_datapath_res = 32'h0;
|
||||||
|
case (1'b1)
|
||||||
|
op_xor: alu_datapath_res = xor_res;
|
||||||
|
op_or: alu_datapath_res = or_res;
|
||||||
|
op_and: alu_datapath_res = and_res;
|
||||||
|
op_add: alu_datapath_res = add_sub_res;
|
||||||
|
op_sub: alu_datapath_res = add_sub_res;
|
||||||
|
op_sll: alu_datapath_res = sll_res;
|
||||||
|
op_srl: alu_datapath_res = srl_res;
|
||||||
|
op_sra: alu_datapath_res = sra_res;
|
||||||
|
op_slt: alu_datapath_res = slt_res;
|
||||||
|
op_sltu: alu_datapath_res = sltu_res;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign alu_res_o = alu_datapath_res;
|
||||||
|
|
||||||
|
assign bjp_res_o = alu_datapath_res;
|
||||||
|
|
||||||
|
assign bjp_cmp_res_o = cmp_res_eq | cmp_res_neq | cmp_res_lt | cmp_res_ltu | cmp_res_gt | cmp_res_gtu;
|
||||||
|
|
||||||
|
assign {mux_op1,
|
||||||
|
mux_op2,
|
||||||
|
op_add,
|
||||||
|
op_sub,
|
||||||
|
op_sll,
|
||||||
|
op_slt,
|
||||||
|
op_sltu,
|
||||||
|
op_xor,
|
||||||
|
op_srl,
|
||||||
|
op_sra,
|
||||||
|
op_or,
|
||||||
|
op_and,
|
||||||
|
op_beq,
|
||||||
|
op_bne,
|
||||||
|
op_blt,
|
||||||
|
op_bltu,
|
||||||
|
op_bge,
|
||||||
|
op_bgeu
|
||||||
|
} = ({`DATAPATH_MUX_WIDTH{req_alu_i}} & {
|
||||||
|
alu_op1_i,
|
||||||
|
alu_op2_i,
|
||||||
|
alu_op_add_i,
|
||||||
|
alu_op_sub_i,
|
||||||
|
alu_op_sll_i,
|
||||||
|
alu_op_slt_i,
|
||||||
|
alu_op_sltu_i,
|
||||||
|
alu_op_xor_i,
|
||||||
|
alu_op_srl_i,
|
||||||
|
alu_op_sra_i,
|
||||||
|
alu_op_or_i,
|
||||||
|
alu_op_and_i,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0
|
||||||
|
}) |
|
||||||
|
({`DATAPATH_MUX_WIDTH{req_bjp_i}} & {
|
||||||
|
bjp_op1_i,
|
||||||
|
bjp_op2_i,
|
||||||
|
1'b1,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
bjp_op_beq_i,
|
||||||
|
bjp_op_bne_i,
|
||||||
|
bjp_op_blt_i,
|
||||||
|
bjp_op_bltu_i,
|
||||||
|
bjp_op_bge_i,
|
||||||
|
bjp_op_bgeu_i
|
||||||
|
}) |
|
||||||
|
({`DATAPATH_MUX_WIDTH{req_mem_i}} & {
|
||||||
|
mem_op1_i,
|
||||||
|
mem_op2_i,
|
||||||
|
1'b1,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0
|
||||||
|
}) |
|
||||||
|
({`DATAPATH_MUX_WIDTH{req_csr_i}} & {
|
||||||
|
csr_op1_i,
|
||||||
|
csr_op2_i,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
csr_csrrw_i | csr_csrrs_i,
|
||||||
|
csr_csrrc_i,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0,
|
||||||
|
1'b0
|
||||||
|
});
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
|
||||||
|
module exu_commit(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire req_muldiv_i,
|
||||||
|
input wire muldiv_reg_we_i,
|
||||||
|
input wire[4:0] muldiv_reg_waddr_i,
|
||||||
|
input wire[31:0] muldiv_reg_wdata_i,
|
||||||
|
|
||||||
|
input wire req_mem_i,
|
||||||
|
input wire mem_reg_we_i,
|
||||||
|
input wire[4:0] mem_reg_waddr_i,
|
||||||
|
input wire[31:0] mem_reg_wdata_i,
|
||||||
|
|
||||||
|
input wire req_csr_i,
|
||||||
|
input wire csr_reg_we_i,
|
||||||
|
input wire[4:0] csr_reg_waddr_i,
|
||||||
|
input wire[31:0] csr_reg_wdata_i,
|
||||||
|
|
||||||
|
input wire req_bjp_i,
|
||||||
|
input wire bjp_reg_we_i,
|
||||||
|
input wire[31:0] bjp_reg_wdata_i,
|
||||||
|
input wire[4:0] bjp_reg_waddr_i,
|
||||||
|
|
||||||
|
input wire rd_we_i,
|
||||||
|
input wire[4:0] rd_waddr_i,
|
||||||
|
input wire[31:0] alu_reg_wdata_i,
|
||||||
|
|
||||||
|
output wire reg_we_o,
|
||||||
|
output wire[4:0] reg_waddr_o,
|
||||||
|
output wire[31:0] reg_wdata_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
wire use_alu_res = (~req_muldiv_i) &
|
||||||
|
(~req_mem_i) &
|
||||||
|
(~req_csr_i) &
|
||||||
|
(~req_bjp_i);
|
||||||
|
|
||||||
|
assign reg_we_o = muldiv_reg_we_i | mem_reg_we_i | csr_reg_we_i | use_alu_res | bjp_reg_we_i;
|
||||||
|
|
||||||
|
reg[4:0] reg_waddr;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
reg_waddr = 5'h0;
|
||||||
|
case (1'b1)
|
||||||
|
muldiv_reg_we_i: reg_waddr = muldiv_reg_waddr_i;
|
||||||
|
mem_reg_we_i: reg_waddr = mem_reg_waddr_i;
|
||||||
|
csr_reg_we_i: reg_waddr = csr_reg_waddr_i;
|
||||||
|
bjp_reg_we_i: reg_waddr = bjp_reg_waddr_i;
|
||||||
|
rd_we_i: reg_waddr = rd_waddr_i;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign reg_waddr_o = reg_waddr;
|
||||||
|
|
||||||
|
reg[31:0] reg_wdata;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
reg_wdata = 32'h0;
|
||||||
|
case (1'b1)
|
||||||
|
muldiv_reg_we_i: reg_wdata = muldiv_reg_wdata_i;
|
||||||
|
mem_reg_we_i: reg_wdata = mem_reg_wdata_i;
|
||||||
|
csr_reg_we_i: reg_wdata = csr_reg_wdata_i;
|
||||||
|
bjp_reg_we_i: reg_wdata = bjp_reg_wdata_i;
|
||||||
|
use_alu_res: reg_wdata = alu_reg_wdata_i;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign reg_wdata_o = reg_wdata;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,214 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
|
||||||
|
module exu_dispatch(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire[`DECINFO_WIDTH-1:0] dec_info_bus_i,
|
||||||
|
input wire[31:0] dec_imm_i,
|
||||||
|
input wire[31:0] dec_pc_i,
|
||||||
|
input wire[31:0] rs1_rdata_i,
|
||||||
|
input wire[31:0] rs2_rdata_i,
|
||||||
|
|
||||||
|
// dispatch to ALU
|
||||||
|
output wire req_alu_o,
|
||||||
|
output wire[31:0] alu_op1_o,
|
||||||
|
output wire[31:0] alu_op2_o,
|
||||||
|
output wire alu_op_lui_o,
|
||||||
|
output wire alu_op_auipc_o,
|
||||||
|
output wire alu_op_add_o,
|
||||||
|
output wire alu_op_sub_o,
|
||||||
|
output wire alu_op_sll_o,
|
||||||
|
output wire alu_op_slt_o,
|
||||||
|
output wire alu_op_sltu_o,
|
||||||
|
output wire alu_op_xor_o,
|
||||||
|
output wire alu_op_srl_o,
|
||||||
|
output wire alu_op_sra_o,
|
||||||
|
output wire alu_op_or_o,
|
||||||
|
output wire alu_op_and_o,
|
||||||
|
|
||||||
|
// dispatch to BJP
|
||||||
|
output wire req_bjp_o,
|
||||||
|
output wire[31:0] bjp_op1_o,
|
||||||
|
output wire[31:0] bjp_op2_o,
|
||||||
|
output wire[31:0] bjp_jump_op1_o,
|
||||||
|
output wire[31:0] bjp_jump_op2_o,
|
||||||
|
output wire bjp_op_jump_o,
|
||||||
|
output wire bjp_op_beq_o,
|
||||||
|
output wire bjp_op_bne_o,
|
||||||
|
output wire bjp_op_blt_o,
|
||||||
|
output wire bjp_op_bltu_o,
|
||||||
|
output wire bjp_op_bge_o,
|
||||||
|
output wire bjp_op_bgeu_o,
|
||||||
|
output wire bjp_op_jalr_o,
|
||||||
|
|
||||||
|
// dispatch to MULDIV
|
||||||
|
output wire req_muldiv_o,
|
||||||
|
output wire[31:0] muldiv_op1_o,
|
||||||
|
output wire[31:0] muldiv_op2_o,
|
||||||
|
output wire muldiv_op_mul_o,
|
||||||
|
output wire muldiv_op_mulh_o,
|
||||||
|
output wire muldiv_op_mulhsu_o,
|
||||||
|
output wire muldiv_op_mulhu_o,
|
||||||
|
output wire muldiv_op_div_o,
|
||||||
|
output wire muldiv_op_divu_o,
|
||||||
|
output wire muldiv_op_rem_o,
|
||||||
|
output wire muldiv_op_remu_o,
|
||||||
|
|
||||||
|
// dispatch to CSR
|
||||||
|
output wire req_csr_o,
|
||||||
|
output wire[31:0] csr_op1_o,
|
||||||
|
output wire[31:0] csr_addr_o,
|
||||||
|
output wire csr_csrrw_o,
|
||||||
|
output wire csr_csrrs_o,
|
||||||
|
output wire csr_csrrc_o,
|
||||||
|
|
||||||
|
// dispatch to MEM
|
||||||
|
output wire req_mem_o,
|
||||||
|
output wire[31:0] mem_op1_o,
|
||||||
|
output wire[31:0] mem_op2_o,
|
||||||
|
output wire[31:0] mem_rs2_data_o,
|
||||||
|
output wire mem_op_lb_o,
|
||||||
|
output wire mem_op_lh_o,
|
||||||
|
output wire mem_op_lw_o,
|
||||||
|
output wire mem_op_lbu_o,
|
||||||
|
output wire mem_op_lhu_o,
|
||||||
|
output wire mem_op_sb_o,
|
||||||
|
output wire mem_op_sh_o,
|
||||||
|
output wire mem_op_sw_o,
|
||||||
|
|
||||||
|
// dispatch to SYS
|
||||||
|
output wire sys_op_nop_o,
|
||||||
|
output wire sys_op_mret_o,
|
||||||
|
output wire sys_op_ecall_o,
|
||||||
|
output wire sys_op_ebreak_o,
|
||||||
|
output wire sys_op_fence_o,
|
||||||
|
output wire sys_op_dret_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
wire[`DECINFO_GRP_WIDTH-1:0] disp_info_grp = dec_info_bus_i[`DECINFO_GRP_BUS];
|
||||||
|
|
||||||
|
// ALU info
|
||||||
|
wire op_alu = (disp_info_grp == `DECINFO_GRP_ALU);
|
||||||
|
wire[`DECINFO_WIDTH-1:0] alu_info = {`DECINFO_WIDTH{op_alu}} & dec_info_bus_i;
|
||||||
|
// ALU op1
|
||||||
|
wire alu_op1_pc = alu_info[`DECINFO_ALU_OP1PC];
|
||||||
|
wire alu_op1_zero = alu_info[`DECINFO_ALU_LUI];
|
||||||
|
wire[31:0] alu_op1 = alu_op1_pc? dec_pc_i: alu_op1_zero? 32'h0: rs1_rdata_i;
|
||||||
|
assign alu_op1_o = op_alu? alu_op1: 32'h0;
|
||||||
|
// ALU op2
|
||||||
|
wire alu_op2_imm = alu_info[`DECINFO_ALU_OP2IMM];
|
||||||
|
wire[31:0] alu_op2 = alu_op2_imm? dec_imm_i: rs2_rdata_i;
|
||||||
|
assign alu_op2_o = op_alu? alu_op2: 32'h0;
|
||||||
|
assign alu_op_lui_o = alu_info[`DECINFO_ALU_LUI];
|
||||||
|
assign alu_op_auipc_o = alu_info[`DECINFO_ALU_AUIPC];
|
||||||
|
assign alu_op_add_o = alu_info[`DECINFO_ALU_ADD];
|
||||||
|
assign alu_op_sub_o = alu_info[`DECINFO_ALU_SUB];
|
||||||
|
assign alu_op_sll_o = alu_info[`DECINFO_ALU_SLL];
|
||||||
|
assign alu_op_slt_o = alu_info[`DECINFO_ALU_SLT];
|
||||||
|
assign alu_op_sltu_o = alu_info[`DECINFO_ALU_SLTU];
|
||||||
|
assign alu_op_xor_o = alu_info[`DECINFO_ALU_XOR];
|
||||||
|
assign alu_op_srl_o = alu_info[`DECINFO_ALU_SRL];
|
||||||
|
assign alu_op_sra_o = alu_info[`DECINFO_ALU_SRA];
|
||||||
|
assign alu_op_or_o = alu_info[`DECINFO_ALU_OR];
|
||||||
|
assign alu_op_and_o = alu_info[`DECINFO_ALU_AND];
|
||||||
|
assign req_alu_o = op_alu;
|
||||||
|
|
||||||
|
// BJP info
|
||||||
|
wire op_bjp = (disp_info_grp == `DECINFO_GRP_BJP);
|
||||||
|
wire[`DECINFO_WIDTH-1:0] bjp_info = {`DECINFO_WIDTH{op_bjp}} & dec_info_bus_i;
|
||||||
|
// BJP op1
|
||||||
|
wire bjp_op1_rs1 = bjp_info[`DECINFO_BJP_OP1RS1];
|
||||||
|
wire[31:0] bjp_op1 = bjp_op1_rs1? rs1_rdata_i: dec_pc_i;
|
||||||
|
assign bjp_jump_op1_o = op_bjp? bjp_op1: 32'h0;
|
||||||
|
// BJP op2
|
||||||
|
wire[31:0] bjp_op2 = dec_imm_i;
|
||||||
|
assign bjp_jump_op2_o = op_bjp? bjp_op2: 32'h0;
|
||||||
|
assign bjp_op1_o = op_bjp? rs1_rdata_i: 32'h0;
|
||||||
|
assign bjp_op2_o = op_bjp? rs2_rdata_i: 32'h0;
|
||||||
|
assign bjp_op_jump_o = bjp_info[`DECINFO_BJP_JUMP];
|
||||||
|
assign bjp_op_beq_o = bjp_info[`DECINFO_BJP_BEQ];
|
||||||
|
assign bjp_op_bne_o = bjp_info[`DECINFO_BJP_BNE];
|
||||||
|
assign bjp_op_blt_o = bjp_info[`DECINFO_BJP_BLT];
|
||||||
|
assign bjp_op_bltu_o = bjp_info[`DECINFO_BJP_BLTU];
|
||||||
|
assign bjp_op_bge_o = bjp_info[`DECINFO_BJP_BGE];
|
||||||
|
assign bjp_op_bgeu_o = bjp_info[`DECINFO_BJP_BGEU];
|
||||||
|
assign req_bjp_o = op_bjp;
|
||||||
|
assign bjp_op_jalr_o = bjp_op1_rs1;
|
||||||
|
|
||||||
|
// MULDIV info
|
||||||
|
wire op_muldiv = (disp_info_grp == `DECINFO_GRP_MULDIV);
|
||||||
|
wire[`DECINFO_WIDTH-1:0] muldiv_info = {`DECINFO_WIDTH{op_muldiv}} & dec_info_bus_i;
|
||||||
|
// MULDIV op1
|
||||||
|
assign muldiv_op1_o = op_muldiv? rs1_rdata_i: 32'h0;
|
||||||
|
// MULDIV op2
|
||||||
|
assign muldiv_op2_o = op_muldiv? rs2_rdata_i: 32'h0;
|
||||||
|
assign muldiv_op_mul_o = muldiv_info[`DECINFO_MULDIV_MUL];
|
||||||
|
assign muldiv_op_mulh_o = muldiv_info[`DECINFO_MULDIV_MULH];
|
||||||
|
assign muldiv_op_mulhu_o = muldiv_info[`DECINFO_MULDIV_MULHU];
|
||||||
|
assign muldiv_op_mulhsu_o = muldiv_info[`DECINFO_MULDIV_MULHSU];
|
||||||
|
assign muldiv_op_div_o = muldiv_info[`DECINFO_MULDIV_DIV];
|
||||||
|
assign muldiv_op_divu_o = muldiv_info[`DECINFO_MULDIV_DIVU];
|
||||||
|
assign muldiv_op_rem_o = muldiv_info[`DECINFO_MULDIV_REM];
|
||||||
|
assign muldiv_op_remu_o = muldiv_info[`DECINFO_MULDIV_REMU];
|
||||||
|
assign req_muldiv_o = op_muldiv;
|
||||||
|
|
||||||
|
// CSR info
|
||||||
|
wire op_csr = (disp_info_grp == `DECINFO_GRP_CSR);
|
||||||
|
wire[`DECINFO_WIDTH-1:0] csr_info = {`DECINFO_WIDTH{op_csr}} & dec_info_bus_i;
|
||||||
|
// CSR op1
|
||||||
|
wire csr_rs1imm = csr_info[`DECINFO_CSR_RS1IMM];
|
||||||
|
wire[31:0] csr_rs1 = csr_rs1imm? dec_imm_i: rs1_rdata_i;
|
||||||
|
assign csr_op1_o = op_csr? csr_rs1: 32'h0;
|
||||||
|
assign csr_addr_o = {{20{1'b0}}, csr_info[`DECINFO_CSR_CSRADDR]};
|
||||||
|
assign csr_csrrw_o = csr_info[`DECINFO_CSR_CSRRW];
|
||||||
|
assign csr_csrrs_o = csr_info[`DECINFO_CSR_CSRRS];
|
||||||
|
assign csr_csrrc_o = csr_info[`DECINFO_CSR_CSRRC];
|
||||||
|
assign req_csr_o = op_csr;
|
||||||
|
|
||||||
|
// MEM info
|
||||||
|
wire op_mem = (disp_info_grp == `DECINFO_GRP_MEM);
|
||||||
|
wire[`DECINFO_WIDTH-1:0] mem_info = {`DECINFO_WIDTH{op_mem}} & dec_info_bus_i;
|
||||||
|
assign mem_op_lb_o = mem_info[`DECINFO_MEM_LB];
|
||||||
|
assign mem_op_lh_o = mem_info[`DECINFO_MEM_LH];
|
||||||
|
assign mem_op_lw_o = mem_info[`DECINFO_MEM_LW];
|
||||||
|
assign mem_op_lbu_o = mem_info[`DECINFO_MEM_LBU];
|
||||||
|
assign mem_op_lhu_o = mem_info[`DECINFO_MEM_LHU];
|
||||||
|
assign mem_op_sb_o = mem_info[`DECINFO_MEM_SB];
|
||||||
|
assign mem_op_sh_o = mem_info[`DECINFO_MEM_SH];
|
||||||
|
assign mem_op_sw_o = mem_info[`DECINFO_MEM_SW];
|
||||||
|
assign mem_op1_o = op_mem? rs1_rdata_i: 32'h0;
|
||||||
|
assign mem_op2_o = op_mem? dec_imm_i: 32'h0;
|
||||||
|
assign mem_rs2_data_o = op_mem? rs2_rdata_i: 32'h0;
|
||||||
|
assign req_mem_o = op_mem;
|
||||||
|
|
||||||
|
// SYS info
|
||||||
|
wire op_sys = (disp_info_grp == `DECINFO_GRP_SYS);
|
||||||
|
wire[`DECINFO_WIDTH-1:0] sys_info = {`DECINFO_WIDTH{op_sys}} & dec_info_bus_i;
|
||||||
|
assign sys_op_nop_o = sys_info[`DECINFO_SYS_NOP];
|
||||||
|
assign sys_op_mret_o = sys_info[`DECINFO_SYS_MRET];
|
||||||
|
assign sys_op_ecall_o = sys_info[`DECINFO_SYS_ECALL];
|
||||||
|
assign sys_op_ebreak_o = sys_info[`DECINFO_SYS_EBREAK];
|
||||||
|
assign sys_op_fence_o = sys_info[`DECINFO_SYS_FENCE];
|
||||||
|
assign sys_op_dret_o = sys_info[`DECINFO_SYS_DRET];
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,214 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
|
||||||
|
module exu_mem(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input req_mem_i,
|
||||||
|
input wire[31:0] mem_addr_i,
|
||||||
|
input wire[31:0] mem_rs2_data_i,
|
||||||
|
input wire[31:0] mem_rdata_i,
|
||||||
|
input wire mem_gnt_i,
|
||||||
|
input wire mem_rvalid_i,
|
||||||
|
input wire mem_op_lb_i,
|
||||||
|
input wire mem_op_lh_i,
|
||||||
|
input wire mem_op_lw_i,
|
||||||
|
input wire mem_op_lbu_i,
|
||||||
|
input wire mem_op_lhu_i,
|
||||||
|
input wire mem_op_sb_i,
|
||||||
|
input wire mem_op_sh_i,
|
||||||
|
input wire mem_op_sw_i,
|
||||||
|
|
||||||
|
output wire mem_access_misaligned_o,
|
||||||
|
output wire mem_stall_o,
|
||||||
|
output wire[31:0] mem_addr_o,
|
||||||
|
output wire[31:0] mem_wdata_o,
|
||||||
|
output wire mem_reg_we_o,
|
||||||
|
output wire mem_mem_we_o,
|
||||||
|
output wire[3:0] mem_be_o,
|
||||||
|
output wire mem_req_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
wire[1:0] mem_addr_index = mem_addr_i[1:0];
|
||||||
|
wire mem_addr_index00 = (mem_addr_index == 2'b00);
|
||||||
|
wire mem_addr_index01 = (mem_addr_index == 2'b01);
|
||||||
|
wire mem_addr_index10 = (mem_addr_index == 2'b10);
|
||||||
|
wire mem_addr_index11 = (mem_addr_index == 2'b11);
|
||||||
|
|
||||||
|
assign mem_be_o[0] = mem_addr_index00 | mem_op_sw_i;
|
||||||
|
assign mem_be_o[1] = mem_addr_index01 | (mem_op_sh_i & mem_addr_index00) | mem_op_sw_i;
|
||||||
|
assign mem_be_o[2] = mem_addr_index10 | mem_op_sw_i;
|
||||||
|
assign mem_be_o[3] = mem_addr_index11 | (mem_op_sh_i & mem_addr_index10) | mem_op_sw_i;
|
||||||
|
|
||||||
|
reg[31:0] sb_res;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
sb_res = 32'h0;
|
||||||
|
case (1'b1)
|
||||||
|
mem_addr_index00: sb_res = {24'h0, mem_rs2_data_i[7:0]};
|
||||||
|
mem_addr_index01: sb_res = {16'h0, mem_rs2_data_i[7:0], 8'h0};
|
||||||
|
mem_addr_index10: sb_res = {8'h0, mem_rs2_data_i[7:0], 16'h0};
|
||||||
|
mem_addr_index11: sb_res = {mem_rs2_data_i[7:0], 24'h0};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
reg[31:0] sh_res;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
sh_res = 32'h0;
|
||||||
|
case (1'b1)
|
||||||
|
mem_addr_index00: sh_res = {16'h0, mem_rs2_data_i[15:0]};
|
||||||
|
mem_addr_index10: sh_res = {mem_rs2_data_i[15:0], 16'h0};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
wire[31:0] sw_res = mem_rs2_data_i;
|
||||||
|
|
||||||
|
reg[31:0] lb_res;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
lb_res = 32'h0;
|
||||||
|
case (1'b1)
|
||||||
|
mem_addr_index00: lb_res = {{24{mem_op_lb_i & mem_rdata_i[7]}}, mem_rdata_i[7:0]};
|
||||||
|
mem_addr_index01: lb_res = {{24{mem_op_lb_i & mem_rdata_i[15]}}, mem_rdata_i[15:8]};
|
||||||
|
mem_addr_index10: lb_res = {{24{mem_op_lb_i & mem_rdata_i[23]}}, mem_rdata_i[23:16]};
|
||||||
|
mem_addr_index11: lb_res = {{24{mem_op_lb_i & mem_rdata_i[31]}}, mem_rdata_i[31:24]};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
reg[31:0] lh_res;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
lh_res = 32'h0;
|
||||||
|
case (1'b1)
|
||||||
|
mem_addr_index00: lh_res = {{24{mem_op_lh_i & mem_rdata_i[15]}}, mem_rdata_i[15:0]};
|
||||||
|
mem_addr_index10: lh_res = {{24{mem_op_lh_i & mem_rdata_i[31]}}, mem_rdata_i[31:16]};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
wire[31:0] lw_res = mem_rdata_i;
|
||||||
|
|
||||||
|
reg[31:0] mem_wdata;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
mem_wdata = 32'h0;
|
||||||
|
case (1'b1)
|
||||||
|
mem_op_sb_i: mem_wdata = sb_res;
|
||||||
|
mem_op_sh_i: mem_wdata = sh_res;
|
||||||
|
mem_op_sw_i: mem_wdata = sw_res;
|
||||||
|
mem_op_lb_i: mem_wdata = lb_res;
|
||||||
|
mem_op_lbu_i: mem_wdata = lb_res;
|
||||||
|
mem_op_lh_i: mem_wdata = lh_res;
|
||||||
|
mem_op_lhu_i: mem_wdata = lh_res;
|
||||||
|
mem_op_lw_i: mem_wdata = lw_res;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign mem_wdata_o = mem_wdata;
|
||||||
|
|
||||||
|
wire op_load = mem_op_lb_i | mem_op_lh_i | mem_op_lw_i | mem_op_lbu_i | mem_op_lhu_i;
|
||||||
|
wire op_store = mem_op_sb_i | mem_op_sh_i | mem_op_sw_i;
|
||||||
|
|
||||||
|
localparam S_IDLE = 3'b001;
|
||||||
|
localparam S_WAIT_READ = 3'b010;
|
||||||
|
localparam S_WAIT_WRITE = 3'b100;
|
||||||
|
|
||||||
|
reg[2:0] state_d, state_q;
|
||||||
|
reg mem_stall_d;
|
||||||
|
reg mem_reg_we_d;
|
||||||
|
reg mem_mem_we_d;
|
||||||
|
reg req_mem_d;
|
||||||
|
|
||||||
|
// 访存状态机
|
||||||
|
always @ (*) begin
|
||||||
|
state_d = state_q;
|
||||||
|
|
||||||
|
mem_stall_d = 1'b0;
|
||||||
|
mem_reg_we_d = 1'b0;
|
||||||
|
mem_mem_we_d = 1'b0;
|
||||||
|
req_mem_d = 1'b0;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
if (req_mem_i) begin
|
||||||
|
mem_stall_d = 1'b1;
|
||||||
|
req_mem_d = 1'b1;
|
||||||
|
if (mem_gnt_i) begin
|
||||||
|
if (op_load) begin
|
||||||
|
state_d = S_WAIT_READ;
|
||||||
|
end else if (op_store) begin
|
||||||
|
state_d = S_WAIT_WRITE;
|
||||||
|
mem_mem_we_d = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// 读内存
|
||||||
|
S_WAIT_READ: begin
|
||||||
|
mem_stall_d = 1'b1;
|
||||||
|
if (mem_rvalid_i) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
mem_reg_we_d = 1'b1;
|
||||||
|
mem_stall_d = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// 写内存
|
||||||
|
S_WAIT_WRITE: begin
|
||||||
|
mem_stall_d = 1'b1;
|
||||||
|
if (mem_rvalid_i) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
mem_stall_d = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
// 访存请求
|
||||||
|
assign mem_req_o = req_mem_d;
|
||||||
|
// 访存地址
|
||||||
|
assign mem_addr_o = mem_addr_i;
|
||||||
|
|
||||||
|
// 暂停流水线
|
||||||
|
assign mem_stall_o = mem_stall_d;
|
||||||
|
// 写寄存器使能
|
||||||
|
assign mem_reg_we_o = mem_reg_we_d;
|
||||||
|
// 写内存使能
|
||||||
|
assign mem_mem_we_o = mem_mem_we_d;
|
||||||
|
|
||||||
|
assign mem_access_misaligned_o = (mem_op_sw_i | mem_op_lw_i)? (mem_addr_i[0] | mem_addr_i[1]):
|
||||||
|
(mem_op_sh_i | mem_op_lh_i | mem_op_lhu_i)? mem_addr_i[0]:
|
||||||
|
0;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
|
||||||
|
module exu_muldiv(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire[31:0] muldiv_op1_i,
|
||||||
|
input wire[31:0] muldiv_op2_i,
|
||||||
|
input wire muldiv_op_mul_i,
|
||||||
|
input wire muldiv_op_mulh_i,
|
||||||
|
input wire muldiv_op_mulhsu_i,
|
||||||
|
input wire muldiv_op_mulhu_i,
|
||||||
|
input wire muldiv_op_div_i,
|
||||||
|
input wire muldiv_op_divu_i,
|
||||||
|
input wire muldiv_op_rem_i,
|
||||||
|
input wire muldiv_op_remu_i,
|
||||||
|
|
||||||
|
input wire int_stall_i,
|
||||||
|
|
||||||
|
output wire[31:0] muldiv_reg_wdata_o,
|
||||||
|
output wire muldiv_reg_we_o,
|
||||||
|
output wire muldiv_stall_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
// 除法操作
|
||||||
|
wire op_div = muldiv_op_div_i | muldiv_op_divu_i | muldiv_op_rem_i | muldiv_op_remu_i;
|
||||||
|
wire div_start = op_div & (!div_ready) & (~int_stall_i);
|
||||||
|
wire[3:0] div_op = {muldiv_op_div_i, muldiv_op_divu_i, muldiv_op_rem_i, muldiv_op_remu_i};
|
||||||
|
wire[31:0] div_result;
|
||||||
|
wire div_ready;
|
||||||
|
|
||||||
|
divider u_divider(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.dividend_i(muldiv_op1_i),
|
||||||
|
.divisor_i(muldiv_op2_i),
|
||||||
|
.start_i(div_start),
|
||||||
|
.op_i(div_op),
|
||||||
|
.result_o(div_result),
|
||||||
|
.ready_o(div_ready)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 乘法操作
|
||||||
|
wire op_mul = muldiv_op_mul_i | muldiv_op_mulh_i | muldiv_op_mulhsu_i | muldiv_op_mulhu_i;
|
||||||
|
wire[31:0] muldiv_op1_r;
|
||||||
|
gen_en_dff #(32) mul_op1_ff(clk, rst_n, op_mul, muldiv_op1_i, muldiv_op1_r);
|
||||||
|
wire[31:0] muldiv_op2_r;
|
||||||
|
gen_en_dff #(32) mul_op2_ff(clk, rst_n, op_mul, muldiv_op2_i, muldiv_op2_r);
|
||||||
|
|
||||||
|
wire mul_ready_r;
|
||||||
|
wire mul_ready = (~mul_ready_r) & op_mul;
|
||||||
|
gen_rst_0_dff #(1) mul_ready_ff(clk, rst_n, mul_ready, mul_ready_r);
|
||||||
|
|
||||||
|
wire mul_start = (~mul_ready_r) & op_mul;
|
||||||
|
|
||||||
|
wire op1_is_signed = muldiv_op1_r[31];
|
||||||
|
wire op2_is_signed = muldiv_op2_r[31];
|
||||||
|
wire[31:0] op1_complcode = op1_is_signed? (-muldiv_op1_r): muldiv_op1_r;
|
||||||
|
wire[31:0] op2_complcode = op2_is_signed? (-muldiv_op2_r): muldiv_op2_r;
|
||||||
|
|
||||||
|
wire[31:0] op1_mul = ({32{(muldiv_op_mul_i | muldiv_op_mulhu_i)}} & muldiv_op1_r) |
|
||||||
|
({32{(muldiv_op_mulh_i | muldiv_op_mulhsu_i)}} & op1_complcode);
|
||||||
|
wire[31:0] op2_mul = ({32{(muldiv_op_mul_i | muldiv_op_mulhu_i | muldiv_op_mulhsu_i)}} & muldiv_op2_r) |
|
||||||
|
({32{(muldiv_op_mulh_i)}} & op2_complcode);
|
||||||
|
wire[63:0] mul_res_tmp = op1_mul * op2_mul;
|
||||||
|
wire[63:0] mul_res_tmp_complcode = -mul_res_tmp;
|
||||||
|
wire[31:0] mul_res = mul_res_tmp[31:0];
|
||||||
|
wire[31:0] mulhu_res = mul_res_tmp[63:32];
|
||||||
|
wire[31:0] mulh_res = (op1_is_signed ^ op2_is_signed)? mul_res_tmp_complcode[63:32]: mul_res_tmp[63:32];
|
||||||
|
wire[31:0] mulhsu_res = (op1_is_signed)? mul_res_tmp_complcode[63:32]: mul_res_tmp[63:32];
|
||||||
|
|
||||||
|
reg[31:0] mul_op_res;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
mul_op_res = 32'h0;
|
||||||
|
case (1'b1)
|
||||||
|
muldiv_op_mul_i: mul_op_res = mul_res;
|
||||||
|
muldiv_op_mulhu_i: mul_op_res = mulhu_res;
|
||||||
|
muldiv_op_mulh_i: mul_op_res = mulh_res;
|
||||||
|
muldiv_op_mulhsu_i: mul_op_res = mulhsu_res;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
// 运算结果
|
||||||
|
assign muldiv_reg_wdata_o = div_result | mul_op_res;
|
||||||
|
assign muldiv_reg_we_o = div_ready | mul_ready_r;
|
||||||
|
assign muldiv_stall_o = div_start | mul_start;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 通用寄存器模块
|
||||||
|
module gpr_reg(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire we_i, // 写寄存器使能
|
||||||
|
input wire[4:0] waddr_i, // 写寄存器地址
|
||||||
|
input wire[31:0] wdata_i, // 写寄存器数据
|
||||||
|
|
||||||
|
input wire[4:0] raddr1_i, // 读寄存器1地址
|
||||||
|
output wire[31:0] rdata1_o, // 读寄存器1数据
|
||||||
|
|
||||||
|
input wire[4:0] raddr2_i, // 读寄存器2地址
|
||||||
|
output wire[31:0] rdata2_o // 读寄存器2数据
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
wire[32-1:0] regs[32-1:0];
|
||||||
|
wire[32-1:0] we;
|
||||||
|
|
||||||
|
genvar i;
|
||||||
|
|
||||||
|
generate
|
||||||
|
for (i = 0; i < 32; i = i + 1) begin: gpr_rw
|
||||||
|
// x0 cannot be wrote since it is constant-zeros
|
||||||
|
if (i == 0) begin: is_x0
|
||||||
|
assign we[i] = 1'b0;
|
||||||
|
assign regs[i] = 32'h0;
|
||||||
|
end else begin: not_x0
|
||||||
|
assign we[i] = we_i & (waddr_i == i);
|
||||||
|
gen_en_dffnr #(32) rf_dff(clk, we[i], wdata_i, regs[i]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
assign rdata1_o = (|raddr1_i)? ((we_i & (waddr_i == raddr1_i))? wdata_i: regs[raddr1_i]): 32'h0;
|
||||||
|
assign rdata2_o = (|raddr2_i)? ((we_i & (waddr_i == raddr2_i))? wdata_i: regs[raddr2_i]): 32'h0;
|
||||||
|
|
||||||
|
// for debug
|
||||||
|
wire[31:0] ra = regs[1];
|
||||||
|
wire[31:0] sp = regs[2];
|
||||||
|
wire[31:0] gp = regs[3];
|
||||||
|
wire[31:0] tp = regs[4];
|
||||||
|
wire[31:0] t0 = regs[5];
|
||||||
|
wire[31:0] t1 = regs[6];
|
||||||
|
wire[31:0] t2 = regs[7];
|
||||||
|
wire[31:0] s0 = regs[8];
|
||||||
|
wire[31:0] fp = regs[8];
|
||||||
|
wire[31:0] s1 = regs[9];
|
||||||
|
wire[31:0] a0 = regs[10];
|
||||||
|
wire[31:0] a1 = regs[11];
|
||||||
|
wire[31:0] a2 = regs[12];
|
||||||
|
wire[31:0] a3 = regs[13];
|
||||||
|
wire[31:0] a4 = regs[14];
|
||||||
|
wire[31:0] a5 = regs[15];
|
||||||
|
wire[31:0] a6 = regs[16];
|
||||||
|
wire[31:0] a7 = regs[17];
|
||||||
|
wire[31:0] s2 = regs[18];
|
||||||
|
wire[31:0] s3 = regs[19];
|
||||||
|
wire[31:0] s4 = regs[20];
|
||||||
|
wire[31:0] s5 = regs[21];
|
||||||
|
wire[31:0] s6 = regs[22];
|
||||||
|
wire[31:0] s7 = regs[23];
|
||||||
|
wire[31:0] s8 = regs[24];
|
||||||
|
wire[31:0] s9 = regs[25];
|
||||||
|
wire[31:0] s10 = regs[26];
|
||||||
|
wire[31:0] s11 = regs[27];
|
||||||
|
wire[31:0] t3 = regs[28];
|
||||||
|
wire[31:0] t4 = regs[29];
|
||||||
|
wire[31:0] t5 = regs[30];
|
||||||
|
wire[31:0] t6 = regs[31];
|
||||||
|
|
||||||
|
endmodule
|
302
rtl/core/id.v
|
@ -1,302 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
// 译码模块
|
|
||||||
// 纯组合逻辑电路
|
|
||||||
module id(
|
|
||||||
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
// from if_id
|
|
||||||
input wire[`InstBus] inst_i, // 指令内容
|
|
||||||
input wire[`InstAddrBus] inst_addr_i, // 指令地址
|
|
||||||
|
|
||||||
// from regs
|
|
||||||
input wire[`RegBus] reg1_rdata_i, // 通用寄存器1输入数据
|
|
||||||
input wire[`RegBus] reg2_rdata_i, // 通用寄存器2输入数据
|
|
||||||
|
|
||||||
// from csr reg
|
|
||||||
input wire[`RegBus] csr_rdata_i, // CSR寄存器输入数据
|
|
||||||
|
|
||||||
// from ex
|
|
||||||
input wire ex_jump_flag_i, // 跳转标志
|
|
||||||
|
|
||||||
// to regs
|
|
||||||
output reg[`RegAddrBus] reg1_raddr_o, // 读通用寄存器1地址
|
|
||||||
output reg[`RegAddrBus] reg2_raddr_o, // 读通用寄存器2地址
|
|
||||||
|
|
||||||
// to csr reg
|
|
||||||
output reg[`MemAddrBus] csr_raddr_o, // 读CSR寄存器地址
|
|
||||||
|
|
||||||
// to ex
|
|
||||||
output reg[`MemAddrBus] op1_o,
|
|
||||||
output reg[`MemAddrBus] op2_o,
|
|
||||||
output reg[`MemAddrBus] op1_jump_o,
|
|
||||||
output reg[`MemAddrBus] op2_jump_o,
|
|
||||||
output reg[`InstBus] inst_o, // 指令内容
|
|
||||||
output reg[`InstAddrBus] inst_addr_o, // 指令地址
|
|
||||||
output reg[`RegBus] reg1_rdata_o, // 通用寄存器1数据
|
|
||||||
output reg[`RegBus] reg2_rdata_o, // 通用寄存器2数据
|
|
||||||
output reg reg_we_o, // 写通用寄存器标志
|
|
||||||
output reg[`RegAddrBus] reg_waddr_o, // 写通用寄存器地址
|
|
||||||
output reg csr_we_o, // 写CSR寄存器标志
|
|
||||||
output reg[`RegBus] csr_rdata_o, // CSR寄存器数据
|
|
||||||
output reg[`MemAddrBus] csr_waddr_o // 写CSR寄存器地址
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
wire[6:0] opcode = inst_i[6:0];
|
|
||||||
wire[2:0] funct3 = inst_i[14:12];
|
|
||||||
wire[6:0] funct7 = inst_i[31:25];
|
|
||||||
wire[4:0] rd = inst_i[11:7];
|
|
||||||
wire[4:0] rs1 = inst_i[19:15];
|
|
||||||
wire[4:0] rs2 = inst_i[24:20];
|
|
||||||
|
|
||||||
|
|
||||||
always @ (*) begin
|
|
||||||
inst_o = inst_i;
|
|
||||||
inst_addr_o = inst_addr_i;
|
|
||||||
reg1_rdata_o = reg1_rdata_i;
|
|
||||||
reg2_rdata_o = reg2_rdata_i;
|
|
||||||
csr_rdata_o = csr_rdata_i;
|
|
||||||
csr_raddr_o = `ZeroWord;
|
|
||||||
csr_waddr_o = `ZeroWord;
|
|
||||||
csr_we_o = `WriteDisable;
|
|
||||||
op1_o = `ZeroWord;
|
|
||||||
op2_o = `ZeroWord;
|
|
||||||
op1_jump_o = `ZeroWord;
|
|
||||||
op2_jump_o = `ZeroWord;
|
|
||||||
|
|
||||||
case (opcode)
|
|
||||||
`INST_TYPE_I: begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_ADDI, `INST_SLTI, `INST_SLTIU, `INST_XORI, `INST_ORI, `INST_ANDI, `INST_SLLI, `INST_SRI: begin
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
op1_o = reg1_rdata_i;
|
|
||||||
op2_o = {{20{inst_i[31]}}, inst_i[31:20]};
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_TYPE_R_M: begin
|
|
||||||
if ((funct7 == 7'b0000000) || (funct7 == 7'b0100000)) begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_ADD_SUB, `INST_SLL, `INST_SLT, `INST_SLTU, `INST_XOR, `INST_SR, `INST_OR, `INST_AND: begin
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = rs2;
|
|
||||||
op1_o = reg1_rdata_i;
|
|
||||||
op2_o = reg2_rdata_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end else if (funct7 == 7'b0000001) begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_MUL, `INST_MULHU, `INST_MULH, `INST_MULHSU: begin
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = rs2;
|
|
||||||
op1_o = reg1_rdata_i;
|
|
||||||
op2_o = reg2_rdata_i;
|
|
||||||
end
|
|
||||||
`INST_DIV, `INST_DIVU, `INST_REM, `INST_REMU: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = rs2;
|
|
||||||
op1_o = reg1_rdata_i;
|
|
||||||
op2_o = reg2_rdata_i;
|
|
||||||
op1_jump_o = inst_addr_i;
|
|
||||||
op2_jump_o = 32'h4;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end else begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
`INST_TYPE_L: begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_LB, `INST_LH, `INST_LW, `INST_LBU, `INST_LHU: begin
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
op1_o = reg1_rdata_i;
|
|
||||||
op2_o = {{20{inst_i[31]}}, inst_i[31:20]};
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_TYPE_S: begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_SB, `INST_SW, `INST_SH: begin
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = rs2;
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
op1_o = reg1_rdata_i;
|
|
||||||
op2_o = {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]};
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_TYPE_B: begin
|
|
||||||
case (funct3)
|
|
||||||
`INST_BEQ, `INST_BNE, `INST_BLT, `INST_BGE, `INST_BLTU, `INST_BGEU: begin
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = rs2;
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
op1_o = reg1_rdata_i;
|
|
||||||
op2_o = reg2_rdata_i;
|
|
||||||
op1_jump_o = inst_addr_i;
|
|
||||||
op2_jump_o = {{20{inst_i[31]}}, inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0};
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
`INST_JAL: begin
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
op1_o = inst_addr_i;
|
|
||||||
op2_o = 32'h4;
|
|
||||||
op1_jump_o = inst_addr_i;
|
|
||||||
op2_jump_o = {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};
|
|
||||||
end
|
|
||||||
`INST_JALR: begin
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
op1_o = inst_addr_i;
|
|
||||||
op2_o = 32'h4;
|
|
||||||
op1_jump_o = reg1_rdata_i;
|
|
||||||
op2_jump_o = {{20{inst_i[31]}}, inst_i[31:20]};
|
|
||||||
end
|
|
||||||
`INST_LUI: begin
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
op1_o = {inst_i[31:12], 12'b0};
|
|
||||||
op2_o = `ZeroWord;
|
|
||||||
end
|
|
||||||
`INST_AUIPC: begin
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
op1_o = inst_addr_i;
|
|
||||||
op2_o = {inst_i[31:12], 12'b0};
|
|
||||||
end
|
|
||||||
`INST_NOP_OP: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
`INST_FENCE: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
op1_jump_o = inst_addr_i;
|
|
||||||
op2_jump_o = 32'h4;
|
|
||||||
end
|
|
||||||
`INST_CSR: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
csr_raddr_o = {20'h0, inst_i[31:20]};
|
|
||||||
csr_waddr_o = {20'h0, inst_i[31:20]};
|
|
||||||
case (funct3)
|
|
||||||
`INST_CSRRW, `INST_CSRRS, `INST_CSRRC: begin
|
|
||||||
reg1_raddr_o = rs1;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
csr_we_o = `WriteEnable;
|
|
||||||
end
|
|
||||||
`INST_CSRRWI, `INST_CSRRSI, `INST_CSRRCI: begin
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
reg_we_o = `WriteEnable;
|
|
||||||
reg_waddr_o = rd;
|
|
||||||
csr_we_o = `WriteEnable;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
csr_we_o = `WriteDisable;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
reg_we_o = `WriteDisable;
|
|
||||||
reg_waddr_o = `ZeroReg;
|
|
||||||
reg1_raddr_o = `ZeroReg;
|
|
||||||
reg2_raddr_o = `ZeroReg;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
111
rtl/core/id_ex.v
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
// 将译码结果向执行模块传递
|
|
||||||
module id_ex(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
input wire[`InstBus] inst_i, // 指令内容
|
|
||||||
input wire[`InstAddrBus] inst_addr_i, // 指令地址
|
|
||||||
input wire reg_we_i, // 写通用寄存器标志
|
|
||||||
input wire[`RegAddrBus] reg_waddr_i, // 写通用寄存器地址
|
|
||||||
input wire[`RegBus] reg1_rdata_i, // 通用寄存器1读数据
|
|
||||||
input wire[`RegBus] reg2_rdata_i, // 通用寄存器2读数据
|
|
||||||
input wire csr_we_i, // 写CSR寄存器标志
|
|
||||||
input wire[`MemAddrBus] csr_waddr_i, // 写CSR寄存器地址
|
|
||||||
input wire[`RegBus] csr_rdata_i, // CSR寄存器读数据
|
|
||||||
input wire[`MemAddrBus] op1_i,
|
|
||||||
input wire[`MemAddrBus] op2_i,
|
|
||||||
input wire[`MemAddrBus] op1_jump_i,
|
|
||||||
input wire[`MemAddrBus] op2_jump_i,
|
|
||||||
|
|
||||||
input wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志
|
|
||||||
|
|
||||||
output wire[`MemAddrBus] op1_o,
|
|
||||||
output wire[`MemAddrBus] op2_o,
|
|
||||||
output wire[`MemAddrBus] op1_jump_o,
|
|
||||||
output wire[`MemAddrBus] op2_jump_o,
|
|
||||||
output wire[`InstBus] inst_o, // 指令内容
|
|
||||||
output wire[`InstAddrBus] inst_addr_o, // 指令地址
|
|
||||||
output wire reg_we_o, // 写通用寄存器标志
|
|
||||||
output wire[`RegAddrBus] reg_waddr_o, // 写通用寄存器地址
|
|
||||||
output wire[`RegBus] reg1_rdata_o, // 通用寄存器1读数据
|
|
||||||
output wire[`RegBus] reg2_rdata_o, // 通用寄存器2读数据
|
|
||||||
output wire csr_we_o, // 写CSR寄存器标志
|
|
||||||
output wire[`MemAddrBus] csr_waddr_o, // 写CSR寄存器地址
|
|
||||||
output wire[`RegBus] csr_rdata_o // CSR寄存器读数据
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
wire hold_en = (hold_flag_i >= `Hold_Id);
|
|
||||||
|
|
||||||
wire[`InstBus] inst;
|
|
||||||
gen_pipe_dff #(32) inst_ff(clk, rst, hold_en, `INST_NOP, inst_i, inst);
|
|
||||||
assign inst_o = inst;
|
|
||||||
|
|
||||||
wire[`InstAddrBus] inst_addr;
|
|
||||||
gen_pipe_dff #(32) inst_addr_ff(clk, rst, hold_en, `ZeroWord, inst_addr_i, inst_addr);
|
|
||||||
assign inst_addr_o = inst_addr;
|
|
||||||
|
|
||||||
wire reg_we;
|
|
||||||
gen_pipe_dff #(1) reg_we_ff(clk, rst, hold_en, `WriteDisable, reg_we_i, reg_we);
|
|
||||||
assign reg_we_o = reg_we;
|
|
||||||
|
|
||||||
wire[`RegAddrBus] reg_waddr;
|
|
||||||
gen_pipe_dff #(5) reg_waddr_ff(clk, rst, hold_en, `ZeroReg, reg_waddr_i, reg_waddr);
|
|
||||||
assign reg_waddr_o = reg_waddr;
|
|
||||||
|
|
||||||
wire[`RegBus] reg1_rdata;
|
|
||||||
gen_pipe_dff #(32) reg1_rdata_ff(clk, rst, hold_en, `ZeroWord, reg1_rdata_i, reg1_rdata);
|
|
||||||
assign reg1_rdata_o = reg1_rdata;
|
|
||||||
|
|
||||||
wire[`RegBus] reg2_rdata;
|
|
||||||
gen_pipe_dff #(32) reg2_rdata_ff(clk, rst, hold_en, `ZeroWord, reg2_rdata_i, reg2_rdata);
|
|
||||||
assign reg2_rdata_o = reg2_rdata;
|
|
||||||
|
|
||||||
wire csr_we;
|
|
||||||
gen_pipe_dff #(1) csr_we_ff(clk, rst, hold_en, `WriteDisable, csr_we_i, csr_we);
|
|
||||||
assign csr_we_o = csr_we;
|
|
||||||
|
|
||||||
wire[`MemAddrBus] csr_waddr;
|
|
||||||
gen_pipe_dff #(32) csr_waddr_ff(clk, rst, hold_en, `ZeroWord, csr_waddr_i, csr_waddr);
|
|
||||||
assign csr_waddr_o = csr_waddr;
|
|
||||||
|
|
||||||
wire[`RegBus] csr_rdata;
|
|
||||||
gen_pipe_dff #(32) csr_rdata_ff(clk, rst, hold_en, `ZeroWord, csr_rdata_i, csr_rdata);
|
|
||||||
assign csr_rdata_o = csr_rdata;
|
|
||||||
|
|
||||||
wire[`MemAddrBus] op1;
|
|
||||||
gen_pipe_dff #(32) op1_ff(clk, rst, hold_en, `ZeroWord, op1_i, op1);
|
|
||||||
assign op1_o = op1;
|
|
||||||
|
|
||||||
wire[`MemAddrBus] op2;
|
|
||||||
gen_pipe_dff #(32) op2_ff(clk, rst, hold_en, `ZeroWord, op2_i, op2);
|
|
||||||
assign op2_o = op2;
|
|
||||||
|
|
||||||
wire[`MemAddrBus] op1_jump;
|
|
||||||
gen_pipe_dff #(32) op1_jump_ff(clk, rst, hold_en, `ZeroWord, op1_jump_i, op1_jump);
|
|
||||||
assign op1_jump_o = op1_jump;
|
|
||||||
|
|
||||||
wire[`MemAddrBus] op2_jump;
|
|
||||||
gen_pipe_dff #(32) op2_jump_ff(clk, rst, hold_en, `ZeroWord, op2_jump_i, op2_jump);
|
|
||||||
assign op2_jump_o = op2_jump;
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 译码模块
|
||||||
|
// 纯组合逻辑电路
|
||||||
|
module idu(
|
||||||
|
|
||||||
|
input wire clk, // 时钟
|
||||||
|
input wire rst_n, // 复位
|
||||||
|
|
||||||
|
// from ifu_idu
|
||||||
|
input wire[31:0] inst_i, // 指令内容
|
||||||
|
input wire[31:0] inst_addr_i, // 指令地址
|
||||||
|
input wire inst_valid_i, // 指令有效
|
||||||
|
|
||||||
|
// from gpr_reg
|
||||||
|
input wire[31:0] rs1_rdata_i, // 通用寄存器1输入数据
|
||||||
|
input wire[31:0] rs2_rdata_i, // 通用寄存器2输入数据
|
||||||
|
|
||||||
|
output wire stall_o, // 流水线暂停
|
||||||
|
output wire illegal_inst_o, // 非法指令
|
||||||
|
|
||||||
|
// to gpr_reg
|
||||||
|
output wire[4:0] rs1_raddr_o, // 寄存器1地址
|
||||||
|
output wire[4:0] rs2_raddr_o, // 寄存器2地址
|
||||||
|
|
||||||
|
// to idu_exu
|
||||||
|
output wire inst_valid_o, // 指令有效
|
||||||
|
output wire[31:0] inst_o, // 指令内容
|
||||||
|
output wire[`DECINFO_WIDTH-1:0] dec_info_bus_o, // 译码信息
|
||||||
|
output wire[31:0] dec_imm_o, // 立即数
|
||||||
|
output wire[31:0] dec_pc_o, // 指令地址
|
||||||
|
output wire[31:0] rs1_rdata_o, // 寄存器1数据
|
||||||
|
output wire[31:0] rs2_rdata_o, // 寄存器2数据
|
||||||
|
output wire[4:0] rd_waddr_o, // 写寄存器地址
|
||||||
|
output wire rd_we_o // 写寄存器使能
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
wire[31:0] inst = inst_valid_i? inst_i: `INST_NOP;
|
||||||
|
|
||||||
|
assign inst_valid_o = inst_valid_i;
|
||||||
|
assign inst_o = inst;
|
||||||
|
assign rs1_rdata_o = rs1_rdata_i;
|
||||||
|
assign rs2_rdata_o = rs2_rdata_i;
|
||||||
|
|
||||||
|
// 取出指令中的每一个域
|
||||||
|
wire[6:0] opcode = inst[6:0];
|
||||||
|
wire[2:0] funct3 = inst[14:12];
|
||||||
|
wire[6:0] funct7 = inst[31:25];
|
||||||
|
wire[4:0] rd = inst[11:7];
|
||||||
|
wire[4:0] rs1 = inst[19:15];
|
||||||
|
wire[4:0] rs2 = inst[24:20];
|
||||||
|
wire[11:0] type_i_imm_11_0 = inst[31:20];
|
||||||
|
wire[6:0] type_s_imm_11_5 = inst[31:25];
|
||||||
|
wire[4:0] type_s_imm_4_0 = inst[11:7];
|
||||||
|
wire[6:0] type_b_imm_12_10_5 = inst[31:25];
|
||||||
|
wire[4:0] type_b_imm_4_1_11 = inst[11:7];
|
||||||
|
wire[19:0] type_u_imm_31_12 = inst[31:12];
|
||||||
|
wire[19:0] type_j_imm_31_12 = inst[31:12];
|
||||||
|
|
||||||
|
// 指令opcode域的取值
|
||||||
|
wire opcode_0110111 = (opcode == 7'b0110111);
|
||||||
|
wire opcode_0010111 = (opcode == 7'b0010111);
|
||||||
|
wire opcode_1101111 = (opcode == 7'b1101111);
|
||||||
|
wire opcode_1100111 = (opcode == 7'b1100111);
|
||||||
|
wire opcode_1100011 = (opcode == 7'b1100011);
|
||||||
|
wire opcode_0000011 = (opcode == 7'b0000011);
|
||||||
|
wire opcode_0100011 = (opcode == 7'b0100011);
|
||||||
|
wire opcode_0010011 = (opcode == 7'b0010011);
|
||||||
|
wire opcode_0110011 = (opcode == 7'b0110011);
|
||||||
|
wire opcode_0001111 = (opcode == 7'b0001111);
|
||||||
|
wire opcode_1110011 = (opcode == 7'b1110011);
|
||||||
|
|
||||||
|
// 指令funct3域的取值
|
||||||
|
wire funct3_000 = (funct3 == 3'b000);
|
||||||
|
wire funct3_001 = (funct3 == 3'b001);
|
||||||
|
wire funct3_010 = (funct3 == 3'b010);
|
||||||
|
wire funct3_011 = (funct3 == 3'b011);
|
||||||
|
wire funct3_100 = (funct3 == 3'b100);
|
||||||
|
wire funct3_101 = (funct3 == 3'b101);
|
||||||
|
wire funct3_110 = (funct3 == 3'b110);
|
||||||
|
wire funct3_111 = (funct3 == 3'b111);
|
||||||
|
|
||||||
|
// 指令funct7域的取值
|
||||||
|
wire funct7_0000000 = (funct7 == 7'b0000000);
|
||||||
|
wire funct7_0100000 = (funct7 == 7'b0100000);
|
||||||
|
wire funct7_0000001 = (funct7 == 7'b0000001);
|
||||||
|
|
||||||
|
// I类型指令imm域的取值
|
||||||
|
wire type_i_imm_000000000000 = (type_i_imm_11_0 == 12'b000000000000);
|
||||||
|
wire type_i_imm_000000000001 = (type_i_imm_11_0 == 12'b000000000001);
|
||||||
|
|
||||||
|
// 译码出具体指令
|
||||||
|
wire inst_lui = opcode_0110111;
|
||||||
|
wire inst_auipc = opcode_0010111;
|
||||||
|
wire inst_jal = opcode_1101111;
|
||||||
|
wire inst_jalr = opcode_1100111 & funct3_000;
|
||||||
|
wire inst_beq = opcode_1100011 & funct3_000;
|
||||||
|
wire inst_bne = opcode_1100011 & funct3_001;
|
||||||
|
wire inst_blt = opcode_1100011 & funct3_100;
|
||||||
|
wire inst_bge = opcode_1100011 & funct3_101;
|
||||||
|
wire inst_bltu = opcode_1100011 & funct3_110;
|
||||||
|
wire inst_bgeu = opcode_1100011 & funct3_111;
|
||||||
|
wire inst_lb = opcode_0000011 & funct3_000;
|
||||||
|
wire inst_lh = opcode_0000011 & funct3_001;
|
||||||
|
wire inst_lw = opcode_0000011 & funct3_010;
|
||||||
|
wire inst_lbu = opcode_0000011 & funct3_100;
|
||||||
|
wire inst_lhu = opcode_0000011 & funct3_101;
|
||||||
|
wire inst_sb = opcode_0100011 & funct3_000;
|
||||||
|
wire inst_sh = opcode_0100011 & funct3_001;
|
||||||
|
wire inst_sw = opcode_0100011 & funct3_010;
|
||||||
|
wire inst_addi = opcode_0010011 & funct3_000;
|
||||||
|
wire inst_slti = opcode_0010011 & funct3_010;
|
||||||
|
wire inst_sltiu = opcode_0010011 & funct3_011;
|
||||||
|
wire inst_xori = opcode_0010011 & funct3_100;
|
||||||
|
wire inst_ori = opcode_0010011 & funct3_110;
|
||||||
|
wire inst_andi = opcode_0010011 & funct3_111;
|
||||||
|
wire inst_slli = opcode_0010011 & funct3_001 & funct7_0000000;
|
||||||
|
wire inst_srli = opcode_0010011 & funct3_101 & funct7_0000000;
|
||||||
|
wire inst_srai = opcode_0010011 & funct3_101 & funct7_0100000;
|
||||||
|
wire inst_add = opcode_0110011 & funct3_000 & funct7_0000000;
|
||||||
|
wire inst_sub = opcode_0110011 & funct3_000 & funct7_0100000;
|
||||||
|
wire inst_sll = opcode_0110011 & funct3_001 & funct7_0000000;
|
||||||
|
wire inst_slt = opcode_0110011 & funct3_010 & funct7_0000000;
|
||||||
|
wire inst_sltu = opcode_0110011 & funct3_011 & funct7_0000000;
|
||||||
|
wire inst_xor = opcode_0110011 & funct3_100 & funct7_0000000;
|
||||||
|
wire inst_srl = opcode_0110011 & funct3_101 & funct7_0000000;
|
||||||
|
wire inst_sra = opcode_0110011 & funct3_101 & funct7_0100000;
|
||||||
|
wire inst_or = opcode_0110011 & funct3_110 & funct7_0000000;
|
||||||
|
wire inst_and = opcode_0110011 & funct3_111 & funct7_0000000;
|
||||||
|
wire inst_fence = opcode_0001111 & funct3_000;
|
||||||
|
wire inst_ecall = (inst == `INST_ECALL);
|
||||||
|
wire inst_ebreak = (inst == `INST_EBREAK);
|
||||||
|
wire inst_fence_i = opcode_0001111 & funct3_001;
|
||||||
|
wire inst_csrrw = opcode_1110011 & funct3_001;
|
||||||
|
wire inst_csrrs = opcode_1110011 & funct3_010;
|
||||||
|
wire inst_csrrc = opcode_1110011 & funct3_011;
|
||||||
|
wire inst_csrrwi = opcode_1110011 & funct3_101;
|
||||||
|
wire inst_csrrsi = opcode_1110011 & funct3_110;
|
||||||
|
wire inst_csrrci = opcode_1110011 & funct3_111;
|
||||||
|
wire inst_mul = opcode_0110011 & funct3_000 & funct7_0000001;
|
||||||
|
wire inst_mulh = opcode_0110011 & funct3_001 & funct7_0000001;
|
||||||
|
wire inst_mulhsu = opcode_0110011 & funct3_010 & funct7_0000001;
|
||||||
|
wire inst_mulhu = opcode_0110011 & funct3_011 & funct7_0000001;
|
||||||
|
wire inst_div = opcode_0110011 & funct3_100 & funct7_0000001;
|
||||||
|
wire inst_divu = opcode_0110011 & funct3_101 & funct7_0000001;
|
||||||
|
wire inst_rem = opcode_0110011 & funct3_110 & funct7_0000001;
|
||||||
|
wire inst_remu = opcode_0110011 & funct3_111 & funct7_0000001;
|
||||||
|
wire inst_nop = (inst == `INST_NOP);
|
||||||
|
wire inst_mret = (inst == `INST_MRET);
|
||||||
|
wire inst_dret = (inst == `INST_DRET);
|
||||||
|
|
||||||
|
// 将指令分类
|
||||||
|
wire inst_type_load = opcode_0000011;
|
||||||
|
wire inst_type_store = opcode_0100011;
|
||||||
|
wire inst_type_branch = opcode_1100011;
|
||||||
|
wire inst_type_muldiv = inst_mul | inst_mulh | inst_mulhsu | inst_mulhu | inst_div | inst_divu | inst_rem | inst_remu;
|
||||||
|
wire inst_type_div = inst_div | inst_divu | inst_rem | inst_remu;
|
||||||
|
|
||||||
|
wire[`DECINFO_ALU_BUS_WIDTH-1:0] dec_alu_info_bus;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_ALU;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_LUI] = inst_lui;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_AUIPC] = inst_auipc;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_ADD] = inst_add | inst_addi;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_SUB] = inst_sub;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_SLL] = inst_sll | inst_slli;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_SLT] = inst_slt | inst_slti;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_SLTU] = inst_sltu | inst_sltiu;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_XOR] = inst_xor | inst_xori;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_SRL] = inst_srl | inst_srli;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_SRA] = inst_sra | inst_srai;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_OR] = inst_or | inst_ori;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_AND] = inst_and | inst_andi;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_OP2IMM] = opcode_0010011 | inst_lui | inst_auipc;
|
||||||
|
assign dec_alu_info_bus[`DECINFO_ALU_OP1PC] = inst_auipc;
|
||||||
|
|
||||||
|
wire[`DECINFO_BJP_BUS_WIDTH-1:0] dec_bjp_info_bus;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_BJP;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_BJP_JUMP] = inst_jal | inst_jalr;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_BJP_BEQ] = inst_beq;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_BJP_BNE] = inst_bne;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_BJP_BLT] = inst_blt;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_BJP_BGE] = inst_bge;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_BJP_BLTU] = inst_bltu;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_BJP_BGEU] = inst_bgeu;
|
||||||
|
assign dec_bjp_info_bus[`DECINFO_BJP_OP1RS1] = inst_jalr;
|
||||||
|
|
||||||
|
wire[`DECINFO_MULDIV_BUS_WIDTH-1:0] dec_muldiv_info_bus;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_MULDIV;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_MULDIV_MUL] = inst_mul;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_MULDIV_MULH] = inst_mulh;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_MULDIV_MULHSU] = inst_mulhsu;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_MULDIV_MULHU] = inst_mulhu;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_MULDIV_DIV] = inst_div;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_MULDIV_DIVU] = inst_divu;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_MULDIV_REM] = inst_rem;
|
||||||
|
assign dec_muldiv_info_bus[`DECINFO_MULDIV_REMU] = inst_remu;
|
||||||
|
|
||||||
|
wire[`DECINFO_CSR_BUS_WIDTH-1:0] dec_csr_info_bus;
|
||||||
|
assign dec_csr_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_CSR;
|
||||||
|
assign dec_csr_info_bus[`DECINFO_CSR_CSRRW] = inst_csrrw | inst_csrrwi;
|
||||||
|
assign dec_csr_info_bus[`DECINFO_CSR_CSRRS] = inst_csrrs | inst_csrrsi;
|
||||||
|
assign dec_csr_info_bus[`DECINFO_CSR_CSRRC] = inst_csrrc | inst_csrrci;
|
||||||
|
assign dec_csr_info_bus[`DECINFO_CSR_RS1IMM] = inst_csrrwi | inst_csrrsi | inst_csrrci;
|
||||||
|
assign dec_csr_info_bus[`DECINFO_CSR_CSRADDR] = inst[31:20];
|
||||||
|
|
||||||
|
wire[`DECINFO_MEM_BUS_WIDTH-1:0] dec_mem_info_bus;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_MEM;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_MEM_LB] = inst_lb;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_MEM_LH] = inst_lh;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_MEM_LW] = inst_lw;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_MEM_LBU] = inst_lbu;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_MEM_LHU] = inst_lhu;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_MEM_SB] = inst_sb;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_MEM_SH] = inst_sh;
|
||||||
|
assign dec_mem_info_bus[`DECINFO_MEM_SW] = inst_sw;
|
||||||
|
|
||||||
|
wire[`DECINFO_SYS_BUS_WIDTH-1:0] dec_sys_info_bus;
|
||||||
|
assign dec_sys_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_SYS;
|
||||||
|
assign dec_sys_info_bus[`DECINFO_SYS_ECALL] = inst_ecall;
|
||||||
|
assign dec_sys_info_bus[`DECINFO_SYS_EBREAK] = inst_ebreak;
|
||||||
|
assign dec_sys_info_bus[`DECINFO_SYS_NOP] = inst_nop;
|
||||||
|
assign dec_sys_info_bus[`DECINFO_SYS_MRET] = inst_mret;
|
||||||
|
assign dec_sys_info_bus[`DECINFO_SYS_DRET] = inst_dret;
|
||||||
|
assign dec_sys_info_bus[`DECINFO_SYS_FENCE] = inst_fence | inst_fence_i;
|
||||||
|
|
||||||
|
// 指令中的立即数
|
||||||
|
wire[31:0] inst_u_type_imm = {inst[31:12], 12'b0};
|
||||||
|
wire[31:0] inst_j_type_imm = {{12{inst[31]}}, inst[19:12], inst[20], inst[30:21], 1'b0};
|
||||||
|
wire[31:0] inst_b_type_imm = {{20{inst[31]}}, inst[7], inst[30:25], inst[11:8], 1'b0};
|
||||||
|
wire[31:0] inst_s_type_imm = {{20{inst[31]}}, inst[31:25], inst[11:7]};
|
||||||
|
wire[31:0] inst_i_type_imm = {{20{inst[31]}}, inst[31:20]};
|
||||||
|
wire[31:0] inst_csr_type_imm = {27'h0, inst[19:15]};
|
||||||
|
wire[31:0] inst_shift_type_imm = {27'h0, inst[24:20]};
|
||||||
|
|
||||||
|
wire inst_sel_u_imm = inst_lui | inst_auipc;
|
||||||
|
wire inst_sel_j_imm = inst_jal;
|
||||||
|
wire inst_sel_b_imm = inst_type_branch;
|
||||||
|
wire inst_sel_s_imm = inst_type_store;
|
||||||
|
wire inst_sel_i_imm = inst_addi | inst_slti | inst_sltiu | inst_xori | inst_ori | inst_andi | inst_type_load | inst_jalr;
|
||||||
|
wire inst_sel_csr_imm = inst_csrrwi | inst_csrrsi | inst_csrrci;
|
||||||
|
wire inst_sel_shift_imm = inst_slli | inst_srli | inst_srai;
|
||||||
|
|
||||||
|
assign dec_imm_o = ({32{inst_sel_u_imm}} & inst_u_type_imm) |
|
||||||
|
({32{inst_sel_j_imm}} & inst_j_type_imm) |
|
||||||
|
({32{inst_sel_b_imm}} & inst_b_type_imm) |
|
||||||
|
({32{inst_sel_s_imm}} & inst_s_type_imm) |
|
||||||
|
({32{inst_sel_i_imm}} & inst_i_type_imm) |
|
||||||
|
({32{inst_sel_csr_imm}} & inst_csr_type_imm) |
|
||||||
|
({32{inst_sel_shift_imm}} & inst_shift_type_imm);
|
||||||
|
|
||||||
|
wire op_alu = inst_lui | inst_auipc | opcode_0010011 | (opcode_0110011 & (~inst_type_muldiv));
|
||||||
|
wire op_bjp = inst_jal | inst_jalr | inst_type_branch;
|
||||||
|
wire op_muldiv = inst_type_muldiv;
|
||||||
|
wire op_csr = inst_csrrw | inst_csrrwi | inst_csrrs | inst_csrrsi | inst_csrrc | inst_csrrci;
|
||||||
|
wire op_sys = inst_ebreak | inst_ecall | inst_nop | inst_mret | inst_fence | inst_fence_i | inst_dret;
|
||||||
|
wire op_mem = inst_type_load | inst_type_store;
|
||||||
|
|
||||||
|
assign dec_info_bus_o = ({`DECINFO_WIDTH{op_alu}} & {{`DECINFO_WIDTH-`DECINFO_ALU_BUS_WIDTH{1'b0}}, dec_alu_info_bus}) |
|
||||||
|
({`DECINFO_WIDTH{op_bjp}} & {{`DECINFO_WIDTH-`DECINFO_BJP_BUS_WIDTH{1'b0}}, dec_bjp_info_bus}) |
|
||||||
|
({`DECINFO_WIDTH{op_muldiv}} & {{`DECINFO_WIDTH-`DECINFO_MULDIV_BUS_WIDTH{1'b0}}, dec_muldiv_info_bus}) |
|
||||||
|
({`DECINFO_WIDTH{op_csr}} & {{`DECINFO_WIDTH-`DECINFO_CSR_BUS_WIDTH{1'b0}}, dec_csr_info_bus}) |
|
||||||
|
({`DECINFO_WIDTH{op_mem}} & {{`DECINFO_WIDTH-`DECINFO_MEM_BUS_WIDTH{1'b0}}, dec_mem_info_bus}) |
|
||||||
|
({`DECINFO_WIDTH{op_sys}} & {{`DECINFO_WIDTH-`DECINFO_SYS_BUS_WIDTH{1'b0}}, dec_sys_info_bus});
|
||||||
|
|
||||||
|
assign dec_pc_o = inst_addr_i;
|
||||||
|
|
||||||
|
// 是否需要访问rs1寄存器
|
||||||
|
wire access_rs1 = (~inst_lui) &
|
||||||
|
(~inst_auipc) &
|
||||||
|
(~inst_jal) &
|
||||||
|
(~inst_ecall) &
|
||||||
|
(~inst_ebreak) &
|
||||||
|
(~inst_csrrwi) &
|
||||||
|
(~inst_csrrsi) &
|
||||||
|
(~inst_csrrci) &
|
||||||
|
(~inst_nop) &
|
||||||
|
(~inst_fence) &
|
||||||
|
(~inst_fence_i) &
|
||||||
|
(~inst_mret);
|
||||||
|
|
||||||
|
assign rs1_raddr_o = access_rs1? rs1: 5'h0;
|
||||||
|
|
||||||
|
// 是否需要访问rs2寄存器
|
||||||
|
wire access_rs2 = opcode_0110011 | inst_type_store | inst_type_branch;
|
||||||
|
|
||||||
|
assign rs2_raddr_o = access_rs2? rs2: 5'h0;
|
||||||
|
|
||||||
|
// 是否需要访问rd寄存器
|
||||||
|
wire access_rd = inst_lui | inst_auipc | inst_jal | inst_jalr | inst_type_load | opcode_0010011 | opcode_0110011 | op_csr;
|
||||||
|
|
||||||
|
assign rd_waddr_o = access_rd? rd: 5'h0;
|
||||||
|
assign rd_we_o = access_rd;
|
||||||
|
|
||||||
|
assign stall_o = 1'b0;
|
||||||
|
|
||||||
|
//assign illegal_inst_o = ~(|dec_info_bus_o);
|
||||||
|
assign illegal_inst_o = 1'b0;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 将译码结果向执行模块传递
|
||||||
|
module idu_exu(
|
||||||
|
|
||||||
|
input wire clk, // 时钟
|
||||||
|
input wire rst_n, // 复位
|
||||||
|
|
||||||
|
input wire[`STALL_WIDTH-1:0] stall_i, // 流水线暂停
|
||||||
|
input wire flush_i, // 流水线冲刷
|
||||||
|
|
||||||
|
// 输入
|
||||||
|
input wire[31:0] inst_i,
|
||||||
|
input wire inst_valid_i,
|
||||||
|
input wire[`DECINFO_WIDTH-1:0] dec_info_bus_i,
|
||||||
|
input wire[31:0] dec_imm_i,
|
||||||
|
input wire[31:0] dec_pc_i,
|
||||||
|
input wire[31:0] rs1_rdata_i,
|
||||||
|
input wire[31:0] rs2_rdata_i,
|
||||||
|
input wire[4:0] rd_waddr_i,
|
||||||
|
input wire rd_we_i,
|
||||||
|
|
||||||
|
// 输出
|
||||||
|
output wire[31:0] inst_o,
|
||||||
|
output wire inst_valid_o,
|
||||||
|
output wire[`DECINFO_WIDTH-1:0] dec_info_bus_o,
|
||||||
|
output wire[31:0] dec_imm_o,
|
||||||
|
output wire[31:0] dec_pc_o,
|
||||||
|
output wire[31:0] rs1_rdata_o,
|
||||||
|
output wire[31:0] rs2_rdata_o,
|
||||||
|
output wire[4:0] rd_waddr_o,
|
||||||
|
output wire rd_we_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
wire en = (~stall_i[`STALL_EX]) | flush_i;
|
||||||
|
|
||||||
|
wire[`DECINFO_WIDTH-1:0] i_dec_info_bus = flush_i? {`DECINFO_WIDTH{1'b0}}: dec_info_bus_i;
|
||||||
|
wire[`DECINFO_WIDTH-1:0] dec_info_bus;
|
||||||
|
gen_en_dff #(`DECINFO_WIDTH) info_bus_ff(clk, rst_n, en, i_dec_info_bus, dec_info_bus);
|
||||||
|
assign dec_info_bus_o = dec_info_bus;
|
||||||
|
|
||||||
|
wire[31:0] i_dec_imm = flush_i? 32'h0: dec_imm_i;
|
||||||
|
wire[31:0] dec_imm;
|
||||||
|
gen_en_dff #(32) imm_ff(clk, rst_n, en, i_dec_imm, dec_imm);
|
||||||
|
assign dec_imm_o = dec_imm;
|
||||||
|
|
||||||
|
wire[31:0] i_dec_pc = flush_i? 32'h0: dec_pc_i;
|
||||||
|
wire[31:0] dec_pc;
|
||||||
|
gen_en_dff #(32) pc_ff(clk, rst_n, en, i_dec_pc, dec_pc);
|
||||||
|
assign dec_pc_o = dec_pc;
|
||||||
|
|
||||||
|
wire[31:0] i_rs1_rdata = flush_i? 32'h0: rs1_rdata_i;
|
||||||
|
wire[31:0] rs1_rdata;
|
||||||
|
gen_en_dff #(32) rs1_rdata_ff(clk, rst_n, en, i_rs1_rdata, rs1_rdata);
|
||||||
|
assign rs1_rdata_o = rs1_rdata;
|
||||||
|
|
||||||
|
wire[31:0] i_rs2_rdata = flush_i? 32'h0: rs2_rdata_i;
|
||||||
|
wire[31:0] rs2_rdata;
|
||||||
|
gen_en_dff #(32) rs2_rdata_ff(clk, rst_n, en, i_rs2_rdata, rs2_rdata);
|
||||||
|
assign rs2_rdata_o = rs2_rdata;
|
||||||
|
|
||||||
|
wire[4:0] i_rd_waddr = flush_i? 5'h0: rd_waddr_i;
|
||||||
|
wire[4:0] rd_waddr;
|
||||||
|
gen_en_dff #(5) rd_waddr_ff(clk, rst_n, en, i_rd_waddr, rd_waddr);
|
||||||
|
assign rd_waddr_o = rd_waddr;
|
||||||
|
|
||||||
|
wire i_rd_we = flush_i? 1'b0: rd_we_i;
|
||||||
|
wire rd_we;
|
||||||
|
gen_en_dff #(1) rd_we_ff(clk, rst_n, en, i_rd_we, rd_we);
|
||||||
|
assign rd_we_o = rd_we;
|
||||||
|
|
||||||
|
wire[31:0] i_inst = flush_i? `INST_NOP: inst_i;
|
||||||
|
wire[31:0] inst;
|
||||||
|
gen_en_dff #(32) inst_ff(clk, rst_n, en, i_inst, inst);
|
||||||
|
assign inst_o = inst;
|
||||||
|
|
||||||
|
wire i_inst_valid = flush_i? 1'b0: inst_valid_i;
|
||||||
|
wire inst_valid;
|
||||||
|
gen_en_dff #(1) inst_valid_ff(clk, rst_n, en, i_inst_valid, inst_valid);
|
||||||
|
assign inst_valid_o = inst_valid;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
// 将指令向译码模块传递
|
|
||||||
module if_id(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
input wire[`InstBus] inst_i, // 指令内容
|
|
||||||
input wire[`InstAddrBus] inst_addr_i, // 指令地址
|
|
||||||
|
|
||||||
input wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志
|
|
||||||
|
|
||||||
input wire[`INT_BUS] int_flag_i, // 外设中断输入信号
|
|
||||||
output wire[`INT_BUS] int_flag_o,
|
|
||||||
|
|
||||||
output wire[`InstBus] inst_o, // 指令内容
|
|
||||||
output wire[`InstAddrBus] inst_addr_o // 指令地址
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
wire hold_en = (hold_flag_i >= `Hold_If);
|
|
||||||
|
|
||||||
wire[`InstBus] inst;
|
|
||||||
gen_pipe_dff #(32) inst_ff(clk, rst, hold_en, `INST_NOP, inst_i, inst);
|
|
||||||
assign inst_o = inst;
|
|
||||||
|
|
||||||
wire[`InstAddrBus] inst_addr;
|
|
||||||
gen_pipe_dff #(32) inst_addr_ff(clk, rst, hold_en, `ZeroWord, inst_addr_i, inst_addr);
|
|
||||||
assign inst_addr_o = inst_addr;
|
|
||||||
|
|
||||||
wire[`INT_BUS] int_flag;
|
|
||||||
gen_pipe_dff #(8) int_ff(clk, rst, hold_en, `INT_NONE, int_flag_i, int_flag);
|
|
||||||
assign int_flag_o = int_flag;
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 取指模块
|
||||||
|
module ifu #(
|
||||||
|
parameter bit BranchPredictor = 1'b1
|
||||||
|
)(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire flush_i, // 冲刷标志
|
||||||
|
input wire[31:0] flush_addr_i, // 冲刷地址
|
||||||
|
input wire[`STALL_WIDTH-1:0] stall_i, // 流水线暂停标志
|
||||||
|
input wire id_ready_i, // ID模块可以接收指令
|
||||||
|
|
||||||
|
// to ifu_idu
|
||||||
|
output wire[31:0] inst_o,
|
||||||
|
output wire[31:0] pc_o,
|
||||||
|
output wire inst_valid_o,
|
||||||
|
|
||||||
|
// 指令总线信号
|
||||||
|
output wire instr_req_o,
|
||||||
|
input wire instr_gnt_i,
|
||||||
|
input wire instr_rvalid_i,
|
||||||
|
output wire[31:0] instr_addr_o,
|
||||||
|
input wire[31:0] instr_rdata_i,
|
||||||
|
input wire instr_err_i
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam S_RESET = 3'b001;
|
||||||
|
localparam S_FETCH = 3'b010;
|
||||||
|
localparam S_VALID = 3'b100;
|
||||||
|
|
||||||
|
reg[2:0] state_d, state_q;
|
||||||
|
|
||||||
|
wire inst_valid;
|
||||||
|
wire req_valid;
|
||||||
|
wire[31:0] fetch_addr_n;
|
||||||
|
reg[31:0] fetch_addr_q;
|
||||||
|
reg inst_valid_d;
|
||||||
|
reg instr_req_d;
|
||||||
|
|
||||||
|
wire prdt_taken;
|
||||||
|
wire[31:0] prdt_addr;
|
||||||
|
|
||||||
|
// 取指请求有效
|
||||||
|
assign req_valid = instr_gnt_i;
|
||||||
|
|
||||||
|
// 状态切换
|
||||||
|
// 取指模块需要实现连续不断地取指
|
||||||
|
always @ (*) begin
|
||||||
|
state_d = state_q;
|
||||||
|
inst_valid_d = 0;
|
||||||
|
instr_req_d = 1'b0;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
// 复位
|
||||||
|
S_RESET: begin
|
||||||
|
// 复位撤销后转到取指状态
|
||||||
|
if (rst_n) begin
|
||||||
|
state_d = S_FETCH;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// 取指
|
||||||
|
S_FETCH: begin
|
||||||
|
instr_req_d = 1'b1;
|
||||||
|
// 取指有效
|
||||||
|
if (req_valid) begin
|
||||||
|
state_d = S_VALID;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// 指令有效
|
||||||
|
S_VALID: begin
|
||||||
|
if (instr_rvalid_i | flush_i) begin
|
||||||
|
if (instr_rvalid_i) begin
|
||||||
|
inst_valid_d = 1'b1;
|
||||||
|
end
|
||||||
|
instr_req_d = 1'b1;
|
||||||
|
if (~req_valid) begin
|
||||||
|
state_d = S_FETCH;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
// 指令有效
|
||||||
|
assign inst_valid = inst_valid_d & id_ready_i;
|
||||||
|
assign inst_valid_o = inst_valid;
|
||||||
|
// 指令无效时用nop指令代替
|
||||||
|
assign inst_o = inst_valid ? instr_rdata_i: `INST_NOP;
|
||||||
|
assign pc_o = fetch_addr_q;
|
||||||
|
|
||||||
|
// 更新取指地址
|
||||||
|
assign fetch_addr_n = flush_i ? flush_addr_i:
|
||||||
|
prdt_taken ? prdt_addr:
|
||||||
|
inst_valid ? fetch_addr_q + 4'h4:
|
||||||
|
fetch_addr_q;
|
||||||
|
|
||||||
|
// 取指请求
|
||||||
|
assign instr_req_o = instr_req_d;
|
||||||
|
// 取指地址(4字节对齐)
|
||||||
|
assign instr_addr_o = {fetch_addr_n[31:2], 2'b00};
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
state_q <= S_RESET;
|
||||||
|
fetch_addr_q <= `CPU_RESET_ADDR;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
// 取指有效时保存当前取指地址
|
||||||
|
if (req_valid | flush_i) begin
|
||||||
|
fetch_addr_q <= fetch_addr_n;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// 分支预测
|
||||||
|
if (BranchPredictor) begin: g_branch_predictor
|
||||||
|
bpu u_bpu(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.inst_i(inst_o),
|
||||||
|
.inst_valid_i(inst_valid_o),
|
||||||
|
.pc_i(pc_o),
|
||||||
|
.prdt_taken_o(prdt_taken),
|
||||||
|
.prdt_addr_o(prdt_addr)
|
||||||
|
);
|
||||||
|
end else begin: g_no_branch_predictor
|
||||||
|
assign prdt_taken = 1'b0;
|
||||||
|
assign prdt_addr = 32'h0;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 将指令信息向译码模块(通过寄存器)传递
|
||||||
|
module ifu_idu(
|
||||||
|
|
||||||
|
input wire clk, // 时钟
|
||||||
|
input wire rst_n, // 复位
|
||||||
|
|
||||||
|
input wire[`STALL_WIDTH-1:0] stall_i, // 流水线暂停
|
||||||
|
input wire flush_i, // 流水线冲刷
|
||||||
|
|
||||||
|
input wire[31:0] inst_i, // 指令内容
|
||||||
|
input wire[31:0] inst_addr_i, // 指令地址
|
||||||
|
input wire inst_valid_i, // 指令有效
|
||||||
|
|
||||||
|
output wire ready_o, // 可以接收指令
|
||||||
|
output wire[31:0] inst_o, // 指令内容
|
||||||
|
output wire[31:0] inst_addr_o, // 指令地址
|
||||||
|
output wire inst_valid_o // 指令有效
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
// 使能信号,只要流水线不暂停就传递
|
||||||
|
wire en = (~stall_i[`STALL_ID]) | flush_i;
|
||||||
|
|
||||||
|
assign ready_o = en;
|
||||||
|
|
||||||
|
// 指令内容传递,冲刷或指令无效时传递NOP指令
|
||||||
|
wire[31:0] i_inst = (flush_i | (~inst_valid_i))? `INST_NOP: inst_i;
|
||||||
|
wire[31:0] inst;
|
||||||
|
gen_en_dff #(32) inst_ff(clk, rst_n, en, i_inst, inst);
|
||||||
|
assign inst_o = inst;
|
||||||
|
|
||||||
|
// 指令地址传递
|
||||||
|
wire[31:0] i_inst_addr = flush_i? 32'h0: inst_addr_i;
|
||||||
|
wire[31:0] inst_addr;
|
||||||
|
gen_en_dff #(32) inst_addr_ff(clk, rst_n, en, i_inst_addr, inst_addr);
|
||||||
|
assign inst_addr_o = inst_addr;
|
||||||
|
|
||||||
|
// 指令有效性传递,冲刷时无效
|
||||||
|
wire i_inst_valid = flush_i? 1'b0: inst_valid_i;
|
||||||
|
wire inst_valid;
|
||||||
|
gen_en_dff #(1) inst_valid_ff(clk, rst_n, en, i_inst_valid, inst_valid);
|
||||||
|
assign inst_valid_o = inst_valid;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 流水线控制模块
|
||||||
|
// 发出暂停、冲刷流水线信号
|
||||||
|
module pipe_ctrl(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire stall_from_id_i,
|
||||||
|
input wire stall_from_ex_i,
|
||||||
|
input wire stall_from_jtag_i,
|
||||||
|
input wire stall_from_clint_i,
|
||||||
|
input wire jump_assert_i,
|
||||||
|
input wire[31:0] jump_addr_i,
|
||||||
|
|
||||||
|
output wire flush_o, // 冲刷标志
|
||||||
|
output wire[`STALL_WIDTH-1:0] stall_o, // 暂停标志
|
||||||
|
output wire[31:0] flush_addr_o // 冲刷地址
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
assign flush_addr_o = jump_addr_i;
|
||||||
|
assign flush_o = jump_assert_i;
|
||||||
|
|
||||||
|
reg[`STALL_WIDTH-1:0] stall;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
stall[`STALL_EX] = 1'b0;
|
||||||
|
stall[`STALL_ID] = 1'b0;
|
||||||
|
stall[`STALL_IF] = 1'b0;
|
||||||
|
stall[`STALL_PC] = 1'b0;
|
||||||
|
|
||||||
|
if (stall_from_clint_i) begin
|
||||||
|
stall[`STALL_EX] = 1'b1;
|
||||||
|
stall[`STALL_ID] = 1'b1;
|
||||||
|
stall[`STALL_IF] = 1'b1;
|
||||||
|
stall[`STALL_PC] = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (stall_from_ex_i) begin
|
||||||
|
stall[`STALL_EX] = 1'b1;
|
||||||
|
stall[`STALL_ID] = 1'b1;
|
||||||
|
stall[`STALL_IF] = 1'b1;
|
||||||
|
stall[`STALL_PC] = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (stall_from_id_i) begin
|
||||||
|
stall[`STALL_IF] = 1'b1;
|
||||||
|
stall[`STALL_PC] = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign stall_o = stall;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
// 通用寄存器模块
|
|
||||||
module regs(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
// from ex
|
|
||||||
input wire we_i, // 写寄存器标志
|
|
||||||
input wire[`RegAddrBus] waddr_i, // 写寄存器地址
|
|
||||||
input wire[`RegBus] wdata_i, // 写寄存器数据
|
|
||||||
|
|
||||||
// from jtag
|
|
||||||
input wire jtag_we_i, // 写寄存器标志
|
|
||||||
input wire[`RegAddrBus] jtag_addr_i, // 读、写寄存器地址
|
|
||||||
input wire[`RegBus] jtag_data_i, // 写寄存器数据
|
|
||||||
|
|
||||||
// from id
|
|
||||||
input wire[`RegAddrBus] raddr1_i, // 读寄存器1地址
|
|
||||||
|
|
||||||
// to id
|
|
||||||
output reg[`RegBus] rdata1_o, // 读寄存器1数据
|
|
||||||
|
|
||||||
// from id
|
|
||||||
input wire[`RegAddrBus] raddr2_i, // 读寄存器2地址
|
|
||||||
|
|
||||||
// to id
|
|
||||||
output reg[`RegBus] rdata2_o, // 读寄存器2数据
|
|
||||||
|
|
||||||
// to jtag
|
|
||||||
output reg[`RegBus] jtag_data_o // 读寄存器数据
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
reg[`RegBus] regs[0:`RegNum - 1];
|
|
||||||
|
|
||||||
// 写寄存器
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == `RstDisable) begin
|
|
||||||
// 优先ex模块写操作
|
|
||||||
if ((we_i == `WriteEnable) && (waddr_i != `ZeroReg)) begin
|
|
||||||
regs[waddr_i] <= wdata_i;
|
|
||||||
end else if ((jtag_we_i == `WriteEnable) && (jtag_addr_i != `ZeroReg)) begin
|
|
||||||
regs[jtag_addr_i] <= jtag_data_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 读寄存器1
|
|
||||||
always @ (*) begin
|
|
||||||
if (raddr1_i == `ZeroReg) begin
|
|
||||||
rdata1_o = `ZeroWord;
|
|
||||||
// 如果读地址等于写地址,并且正在写操作,则直接返回写数据
|
|
||||||
end else if (raddr1_i == waddr_i && we_i == `WriteEnable) begin
|
|
||||||
rdata1_o = wdata_i;
|
|
||||||
end else begin
|
|
||||||
rdata1_o = regs[raddr1_i];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 读寄存器2
|
|
||||||
always @ (*) begin
|
|
||||||
if (raddr2_i == `ZeroReg) begin
|
|
||||||
rdata2_o = `ZeroWord;
|
|
||||||
// 如果读地址等于写地址,并且正在写操作,则直接返回写数据
|
|
||||||
end else if (raddr2_i == waddr_i && we_i == `WriteEnable) begin
|
|
||||||
rdata2_o = wdata_i;
|
|
||||||
end else begin
|
|
||||||
rdata2_o = regs[raddr2_i];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// jtag读寄存器
|
|
||||||
always @ (*) begin
|
|
||||||
if (jtag_addr_i == `ZeroReg) begin
|
|
||||||
jtag_data_o = `ZeroWord;
|
|
||||||
end else begin
|
|
||||||
jtag_data_o = regs[jtag_addr_i];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
340
rtl/core/rib.v
|
@ -1,340 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
|
|
||||||
// RIB总线模块
|
|
||||||
module rib(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
// master 0 interface
|
|
||||||
input wire[`MemAddrBus] m0_addr_i, // 主设备0读、写地址
|
|
||||||
input wire[`MemBus] m0_data_i, // 主设备0写数据
|
|
||||||
output reg[`MemBus] m0_data_o, // 主设备0读取到的数据
|
|
||||||
input wire m0_req_i, // 主设备0访问请求标志
|
|
||||||
input wire m0_we_i, // 主设备0写标志
|
|
||||||
|
|
||||||
// master 1 interface
|
|
||||||
input wire[`MemAddrBus] m1_addr_i, // 主设备1读、写地址
|
|
||||||
input wire[`MemBus] m1_data_i, // 主设备1写数据
|
|
||||||
output reg[`MemBus] m1_data_o, // 主设备1读取到的数据
|
|
||||||
input wire m1_req_i, // 主设备1访问请求标志
|
|
||||||
input wire m1_we_i, // 主设备1写标志
|
|
||||||
|
|
||||||
// master 2 interface
|
|
||||||
input wire[`MemAddrBus] m2_addr_i, // 主设备2读、写地址
|
|
||||||
input wire[`MemBus] m2_data_i, // 主设备2写数据
|
|
||||||
output reg[`MemBus] m2_data_o, // 主设备2读取到的数据
|
|
||||||
input wire m2_req_i, // 主设备2访问请求标志
|
|
||||||
input wire m2_we_i, // 主设备2写标志
|
|
||||||
|
|
||||||
// master 3 interface
|
|
||||||
input wire[`MemAddrBus] m3_addr_i, // 主设备3读、写地址
|
|
||||||
input wire[`MemBus] m3_data_i, // 主设备3写数据
|
|
||||||
output reg[`MemBus] m3_data_o, // 主设备3读取到的数据
|
|
||||||
input wire m3_req_i, // 主设备3访问请求标志
|
|
||||||
input wire m3_we_i, // 主设备3写标志
|
|
||||||
|
|
||||||
// slave 0 interface
|
|
||||||
output reg[`MemAddrBus] s0_addr_o, // 从设备0读、写地址
|
|
||||||
output reg[`MemBus] s0_data_o, // 从设备0写数据
|
|
||||||
input wire[`MemBus] s0_data_i, // 从设备0读取到的数据
|
|
||||||
output reg s0_we_o, // 从设备0写标志
|
|
||||||
|
|
||||||
// slave 1 interface
|
|
||||||
output reg[`MemAddrBus] s1_addr_o, // 从设备1读、写地址
|
|
||||||
output reg[`MemBus] s1_data_o, // 从设备1写数据
|
|
||||||
input wire[`MemBus] s1_data_i, // 从设备1读取到的数据
|
|
||||||
output reg s1_we_o, // 从设备1写标志
|
|
||||||
|
|
||||||
// slave 2 interface
|
|
||||||
output reg[`MemAddrBus] s2_addr_o, // 从设备2读、写地址
|
|
||||||
output reg[`MemBus] s2_data_o, // 从设备2写数据
|
|
||||||
input wire[`MemBus] s2_data_i, // 从设备2读取到的数据
|
|
||||||
output reg s2_we_o, // 从设备2写标志
|
|
||||||
|
|
||||||
// slave 3 interface
|
|
||||||
output reg[`MemAddrBus] s3_addr_o, // 从设备3读、写地址
|
|
||||||
output reg[`MemBus] s3_data_o, // 从设备3写数据
|
|
||||||
input wire[`MemBus] s3_data_i, // 从设备3读取到的数据
|
|
||||||
output reg s3_we_o, // 从设备3写标志
|
|
||||||
|
|
||||||
// slave 4 interface
|
|
||||||
output reg[`MemAddrBus] s4_addr_o, // 从设备4读、写地址
|
|
||||||
output reg[`MemBus] s4_data_o, // 从设备4写数据
|
|
||||||
input wire[`MemBus] s4_data_i, // 从设备4读取到的数据
|
|
||||||
output reg s4_we_o, // 从设备4写标志
|
|
||||||
|
|
||||||
// slave 5 interface
|
|
||||||
output reg[`MemAddrBus] s5_addr_o, // 从设备5读、写地址
|
|
||||||
output reg[`MemBus] s5_data_o, // 从设备5写数据
|
|
||||||
input wire[`MemBus] s5_data_i, // 从设备5读取到的数据
|
|
||||||
output reg s5_we_o, // 从设备5写标志
|
|
||||||
|
|
||||||
output reg hold_flag_o // 暂停流水线标志
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// 访问地址的最高4位决定要访问的是哪一个从设备
|
|
||||||
// 因此最多支持16个从设备
|
|
||||||
parameter [3:0]slave_0 = 4'b0000;
|
|
||||||
parameter [3:0]slave_1 = 4'b0001;
|
|
||||||
parameter [3:0]slave_2 = 4'b0010;
|
|
||||||
parameter [3:0]slave_3 = 4'b0011;
|
|
||||||
parameter [3:0]slave_4 = 4'b0100;
|
|
||||||
parameter [3:0]slave_5 = 4'b0101;
|
|
||||||
|
|
||||||
parameter [1:0]grant0 = 2'h0;
|
|
||||||
parameter [1:0]grant1 = 2'h1;
|
|
||||||
parameter [1:0]grant2 = 2'h2;
|
|
||||||
parameter [1:0]grant3 = 2'h3;
|
|
||||||
|
|
||||||
wire[3:0] req;
|
|
||||||
reg[1:0] grant;
|
|
||||||
|
|
||||||
|
|
||||||
// 主设备请求信号
|
|
||||||
assign req = {m3_req_i, m2_req_i, m1_req_i, m0_req_i};
|
|
||||||
|
|
||||||
// 仲裁逻辑
|
|
||||||
// 固定优先级仲裁机制
|
|
||||||
// 优先级由高到低:主设备3,主设备0,主设备2,主设备1
|
|
||||||
always @ (*) begin
|
|
||||||
if (req[3]) begin
|
|
||||||
grant = grant3;
|
|
||||||
hold_flag_o = `HoldEnable;
|
|
||||||
end else if (req[0]) begin
|
|
||||||
grant = grant0;
|
|
||||||
hold_flag_o = `HoldEnable;
|
|
||||||
end else if (req[2]) begin
|
|
||||||
grant = grant2;
|
|
||||||
hold_flag_o = `HoldEnable;
|
|
||||||
end else begin
|
|
||||||
grant = grant1;
|
|
||||||
hold_flag_o = `HoldDisable;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 根据仲裁结果,选择(访问)对应的从设备
|
|
||||||
always @ (*) begin
|
|
||||||
m0_data_o = `ZeroWord;
|
|
||||||
m1_data_o = `INST_NOP;
|
|
||||||
m2_data_o = `ZeroWord;
|
|
||||||
m3_data_o = `ZeroWord;
|
|
||||||
|
|
||||||
s0_addr_o = `ZeroWord;
|
|
||||||
s1_addr_o = `ZeroWord;
|
|
||||||
s2_addr_o = `ZeroWord;
|
|
||||||
s3_addr_o = `ZeroWord;
|
|
||||||
s4_addr_o = `ZeroWord;
|
|
||||||
s5_addr_o = `ZeroWord;
|
|
||||||
s0_data_o = `ZeroWord;
|
|
||||||
s1_data_o = `ZeroWord;
|
|
||||||
s2_data_o = `ZeroWord;
|
|
||||||
s3_data_o = `ZeroWord;
|
|
||||||
s4_data_o = `ZeroWord;
|
|
||||||
s5_data_o = `ZeroWord;
|
|
||||||
s0_we_o = `WriteDisable;
|
|
||||||
s1_we_o = `WriteDisable;
|
|
||||||
s2_we_o = `WriteDisable;
|
|
||||||
s3_we_o = `WriteDisable;
|
|
||||||
s4_we_o = `WriteDisable;
|
|
||||||
s5_we_o = `WriteDisable;
|
|
||||||
|
|
||||||
case (grant)
|
|
||||||
grant0: begin
|
|
||||||
case (m0_addr_i[31:28])
|
|
||||||
slave_0: begin
|
|
||||||
s0_we_o = m0_we_i;
|
|
||||||
s0_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
|
|
||||||
s0_data_o = m0_data_i;
|
|
||||||
m0_data_o = s0_data_i;
|
|
||||||
end
|
|
||||||
slave_1: begin
|
|
||||||
s1_we_o = m0_we_i;
|
|
||||||
s1_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
|
|
||||||
s1_data_o = m0_data_i;
|
|
||||||
m0_data_o = s1_data_i;
|
|
||||||
end
|
|
||||||
slave_2: begin
|
|
||||||
s2_we_o = m0_we_i;
|
|
||||||
s2_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
|
|
||||||
s2_data_o = m0_data_i;
|
|
||||||
m0_data_o = s2_data_i;
|
|
||||||
end
|
|
||||||
slave_3: begin
|
|
||||||
s3_we_o = m0_we_i;
|
|
||||||
s3_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
|
|
||||||
s3_data_o = m0_data_i;
|
|
||||||
m0_data_o = s3_data_i;
|
|
||||||
end
|
|
||||||
slave_4: begin
|
|
||||||
s4_we_o = m0_we_i;
|
|
||||||
s4_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
|
|
||||||
s4_data_o = m0_data_i;
|
|
||||||
m0_data_o = s4_data_i;
|
|
||||||
end
|
|
||||||
slave_5: begin
|
|
||||||
s5_we_o = m0_we_i;
|
|
||||||
s5_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
|
|
||||||
s5_data_o = m0_data_i;
|
|
||||||
m0_data_o = s5_data_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
grant1: begin
|
|
||||||
case (m1_addr_i[31:28])
|
|
||||||
slave_0: begin
|
|
||||||
s0_we_o = m1_we_i;
|
|
||||||
s0_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
|
|
||||||
s0_data_o = m1_data_i;
|
|
||||||
m1_data_o = s0_data_i;
|
|
||||||
end
|
|
||||||
slave_1: begin
|
|
||||||
s1_we_o = m1_we_i;
|
|
||||||
s1_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
|
|
||||||
s1_data_o = m1_data_i;
|
|
||||||
m1_data_o = s1_data_i;
|
|
||||||
end
|
|
||||||
slave_2: begin
|
|
||||||
s2_we_o = m1_we_i;
|
|
||||||
s2_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
|
|
||||||
s2_data_o = m1_data_i;
|
|
||||||
m1_data_o = s2_data_i;
|
|
||||||
end
|
|
||||||
slave_3: begin
|
|
||||||
s3_we_o = m1_we_i;
|
|
||||||
s3_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
|
|
||||||
s3_data_o = m1_data_i;
|
|
||||||
m1_data_o = s3_data_i;
|
|
||||||
end
|
|
||||||
slave_4: begin
|
|
||||||
s4_we_o = m1_we_i;
|
|
||||||
s4_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
|
|
||||||
s4_data_o = m1_data_i;
|
|
||||||
m1_data_o = s4_data_i;
|
|
||||||
end
|
|
||||||
slave_5: begin
|
|
||||||
s5_we_o = m1_we_i;
|
|
||||||
s5_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
|
|
||||||
s5_data_o = m1_data_i;
|
|
||||||
m1_data_o = s5_data_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
grant2: begin
|
|
||||||
case (m2_addr_i[31:28])
|
|
||||||
slave_0: begin
|
|
||||||
s0_we_o = m2_we_i;
|
|
||||||
s0_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
|
|
||||||
s0_data_o = m2_data_i;
|
|
||||||
m2_data_o = s0_data_i;
|
|
||||||
end
|
|
||||||
slave_1: begin
|
|
||||||
s1_we_o = m2_we_i;
|
|
||||||
s1_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
|
|
||||||
s1_data_o = m2_data_i;
|
|
||||||
m2_data_o = s1_data_i;
|
|
||||||
end
|
|
||||||
slave_2: begin
|
|
||||||
s2_we_o = m2_we_i;
|
|
||||||
s2_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
|
|
||||||
s2_data_o = m2_data_i;
|
|
||||||
m2_data_o = s2_data_i;
|
|
||||||
end
|
|
||||||
slave_3: begin
|
|
||||||
s3_we_o = m2_we_i;
|
|
||||||
s3_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
|
|
||||||
s3_data_o = m2_data_i;
|
|
||||||
m2_data_o = s3_data_i;
|
|
||||||
end
|
|
||||||
slave_4: begin
|
|
||||||
s4_we_o = m2_we_i;
|
|
||||||
s4_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
|
|
||||||
s4_data_o = m2_data_i;
|
|
||||||
m2_data_o = s4_data_i;
|
|
||||||
end
|
|
||||||
slave_5: begin
|
|
||||||
s5_we_o = m2_we_i;
|
|
||||||
s5_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
|
|
||||||
s5_data_o = m2_data_i;
|
|
||||||
m2_data_o = s5_data_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
grant3: begin
|
|
||||||
case (m3_addr_i[31:28])
|
|
||||||
slave_0: begin
|
|
||||||
s0_we_o = m3_we_i;
|
|
||||||
s0_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
|
|
||||||
s0_data_o = m3_data_i;
|
|
||||||
m3_data_o = s0_data_i;
|
|
||||||
end
|
|
||||||
slave_1: begin
|
|
||||||
s1_we_o = m3_we_i;
|
|
||||||
s1_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
|
|
||||||
s1_data_o = m3_data_i;
|
|
||||||
m3_data_o = s1_data_i;
|
|
||||||
end
|
|
||||||
slave_2: begin
|
|
||||||
s2_we_o = m3_we_i;
|
|
||||||
s2_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
|
|
||||||
s2_data_o = m3_data_i;
|
|
||||||
m3_data_o = s2_data_i;
|
|
||||||
end
|
|
||||||
slave_3: begin
|
|
||||||
s3_we_o = m3_we_i;
|
|
||||||
s3_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
|
|
||||||
s3_data_o = m3_data_i;
|
|
||||||
m3_data_o = s3_data_i;
|
|
||||||
end
|
|
||||||
slave_4: begin
|
|
||||||
s4_we_o = m3_we_i;
|
|
||||||
s4_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
|
|
||||||
s4_data_o = m3_data_i;
|
|
||||||
m3_data_o = s4_data_i;
|
|
||||||
end
|
|
||||||
slave_5: begin
|
|
||||||
s5_we_o = m3_we_i;
|
|
||||||
s5_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
|
|
||||||
s5_data_o = m3_data_i;
|
|
||||||
m3_data_o = s5_data_i;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -14,37 +14,30 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
`include "../core/defines.v"
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// 复位控制模块
|
||||||
module rom(
|
module rst_gen #(
|
||||||
|
parameter RESET_FIFO_DEPTH = 5
|
||||||
|
)(
|
||||||
|
|
||||||
input wire clk,
|
input wire clk,
|
||||||
input wire rst,
|
input wire rst_ni,
|
||||||
|
|
||||||
input wire we_i, // write enable
|
output wire rst_no
|
||||||
input wire[`MemAddrBus] addr_i, // addr
|
|
||||||
input wire[`MemBus] data_i,
|
|
||||||
|
|
||||||
output reg[`MemBus] data_o // read data
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
reg[`MemBus] _rom[0:`RomNum - 1];
|
reg[RESET_FIFO_DEPTH-1:0] synch_regs_q;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_ni) begin
|
||||||
always @ (posedge clk) begin
|
if (~rst_ni) begin
|
||||||
if (we_i == `WriteEnable) begin
|
synch_regs_q <= 0;
|
||||||
_rom[addr_i[31:2]] <= data_i;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (*) begin
|
|
||||||
if (rst == `RstEnable) begin
|
|
||||||
data_o = `ZeroWord;
|
|
||||||
end else begin
|
end else begin
|
||||||
data_o = _rom[addr_i[31:2]];
|
synch_regs_q <= {synch_regs_q[RESET_FIFO_DEPTH-2:0], 1'b1};
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
assign rst_no = synch_regs_q[RESET_FIFO_DEPTH-1];
|
||||||
|
|
||||||
endmodule
|
endmodule
|
|
@ -1,369 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "defines.v"
|
|
||||||
|
|
||||||
// tinyriscv处理器核顶层模块
|
|
||||||
module tinyriscv(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
output wire[`MemAddrBus] rib_ex_addr_o, // 读、写外设的地址
|
|
||||||
input wire[`MemBus] rib_ex_data_i, // 从外设读取的数据
|
|
||||||
output wire[`MemBus] rib_ex_data_o, // 写入外设的数据
|
|
||||||
output wire rib_ex_req_o, // 访问外设请求
|
|
||||||
output wire rib_ex_we_o, // 写外设标志
|
|
||||||
|
|
||||||
output wire[`MemAddrBus] rib_pc_addr_o, // 取指地址
|
|
||||||
input wire[`MemBus] rib_pc_data_i, // 取到的指令内容
|
|
||||||
|
|
||||||
input wire[`RegAddrBus] jtag_reg_addr_i, // jtag模块读、写寄存器的地址
|
|
||||||
input wire[`RegBus] jtag_reg_data_i, // jtag模块写寄存器数据
|
|
||||||
input wire jtag_reg_we_i, // jtag模块写寄存器标志
|
|
||||||
output wire[`RegBus] jtag_reg_data_o, // jtag模块读取到的寄存器数据
|
|
||||||
|
|
||||||
input wire rib_hold_flag_i, // 总线暂停标志
|
|
||||||
input wire jtag_halt_flag_i, // jtag暂停标志
|
|
||||||
input wire jtag_reset_flag_i, // jtag复位PC标志
|
|
||||||
|
|
||||||
input wire[`INT_BUS] int_i // 中断信号
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
// pc_reg模块输出信号
|
|
||||||
wire[`InstAddrBus] pc_pc_o;
|
|
||||||
|
|
||||||
// if_id模块输出信号
|
|
||||||
wire[`InstBus] if_inst_o;
|
|
||||||
wire[`InstAddrBus] if_inst_addr_o;
|
|
||||||
wire[`INT_BUS] if_int_flag_o;
|
|
||||||
|
|
||||||
// id模块输出信号
|
|
||||||
wire[`RegAddrBus] id_reg1_raddr_o;
|
|
||||||
wire[`RegAddrBus] id_reg2_raddr_o;
|
|
||||||
wire[`InstBus] id_inst_o;
|
|
||||||
wire[`InstAddrBus] id_inst_addr_o;
|
|
||||||
wire[`RegBus] id_reg1_rdata_o;
|
|
||||||
wire[`RegBus] id_reg2_rdata_o;
|
|
||||||
wire id_reg_we_o;
|
|
||||||
wire[`RegAddrBus] id_reg_waddr_o;
|
|
||||||
wire[`MemAddrBus] id_csr_raddr_o;
|
|
||||||
wire id_csr_we_o;
|
|
||||||
wire[`RegBus] id_csr_rdata_o;
|
|
||||||
wire[`MemAddrBus] id_csr_waddr_o;
|
|
||||||
wire[`MemAddrBus] id_op1_o;
|
|
||||||
wire[`MemAddrBus] id_op2_o;
|
|
||||||
wire[`MemAddrBus] id_op1_jump_o;
|
|
||||||
wire[`MemAddrBus] id_op2_jump_o;
|
|
||||||
|
|
||||||
// id_ex模块输出信号
|
|
||||||
wire[`InstBus] ie_inst_o;
|
|
||||||
wire[`InstAddrBus] ie_inst_addr_o;
|
|
||||||
wire ie_reg_we_o;
|
|
||||||
wire[`RegAddrBus] ie_reg_waddr_o;
|
|
||||||
wire[`RegBus] ie_reg1_rdata_o;
|
|
||||||
wire[`RegBus] ie_reg2_rdata_o;
|
|
||||||
wire ie_csr_we_o;
|
|
||||||
wire[`MemAddrBus] ie_csr_waddr_o;
|
|
||||||
wire[`RegBus] ie_csr_rdata_o;
|
|
||||||
wire[`MemAddrBus] ie_op1_o;
|
|
||||||
wire[`MemAddrBus] ie_op2_o;
|
|
||||||
wire[`MemAddrBus] ie_op1_jump_o;
|
|
||||||
wire[`MemAddrBus] ie_op2_jump_o;
|
|
||||||
|
|
||||||
// ex模块输出信号
|
|
||||||
wire[`MemBus] ex_mem_wdata_o;
|
|
||||||
wire[`MemAddrBus] ex_mem_raddr_o;
|
|
||||||
wire[`MemAddrBus] ex_mem_waddr_o;
|
|
||||||
wire ex_mem_we_o;
|
|
||||||
wire ex_mem_req_o;
|
|
||||||
wire[`RegBus] ex_reg_wdata_o;
|
|
||||||
wire ex_reg_we_o;
|
|
||||||
wire[`RegAddrBus] ex_reg_waddr_o;
|
|
||||||
wire ex_hold_flag_o;
|
|
||||||
wire ex_jump_flag_o;
|
|
||||||
wire[`InstAddrBus] ex_jump_addr_o;
|
|
||||||
wire ex_div_start_o;
|
|
||||||
wire[`RegBus] ex_div_dividend_o;
|
|
||||||
wire[`RegBus] ex_div_divisor_o;
|
|
||||||
wire[2:0] ex_div_op_o;
|
|
||||||
wire[`RegAddrBus] ex_div_reg_waddr_o;
|
|
||||||
wire[`RegBus] ex_csr_wdata_o;
|
|
||||||
wire ex_csr_we_o;
|
|
||||||
wire[`MemAddrBus] ex_csr_waddr_o;
|
|
||||||
|
|
||||||
// regs模块输出信号
|
|
||||||
wire[`RegBus] regs_rdata1_o;
|
|
||||||
wire[`RegBus] regs_rdata2_o;
|
|
||||||
|
|
||||||
// csr_reg模块输出信号
|
|
||||||
wire[`RegBus] csr_data_o;
|
|
||||||
wire[`RegBus] csr_clint_data_o;
|
|
||||||
wire csr_global_int_en_o;
|
|
||||||
wire[`RegBus] csr_clint_csr_mtvec;
|
|
||||||
wire[`RegBus] csr_clint_csr_mepc;
|
|
||||||
wire[`RegBus] csr_clint_csr_mstatus;
|
|
||||||
|
|
||||||
// ctrl模块输出信号
|
|
||||||
wire[`Hold_Flag_Bus] ctrl_hold_flag_o;
|
|
||||||
wire ctrl_jump_flag_o;
|
|
||||||
wire[`InstAddrBus] ctrl_jump_addr_o;
|
|
||||||
|
|
||||||
// div模块输出信号
|
|
||||||
wire[`RegBus] div_result_o;
|
|
||||||
wire div_ready_o;
|
|
||||||
wire div_busy_o;
|
|
||||||
wire[`RegAddrBus] div_reg_waddr_o;
|
|
||||||
|
|
||||||
// clint模块输出信号
|
|
||||||
wire clint_we_o;
|
|
||||||
wire[`MemAddrBus] clint_waddr_o;
|
|
||||||
wire[`MemAddrBus] clint_raddr_o;
|
|
||||||
wire[`RegBus] clint_data_o;
|
|
||||||
wire[`InstAddrBus] clint_int_addr_o;
|
|
||||||
wire clint_int_assert_o;
|
|
||||||
wire clint_hold_flag_o;
|
|
||||||
|
|
||||||
|
|
||||||
assign rib_ex_addr_o = (ex_mem_we_o == `WriteEnable)? ex_mem_waddr_o: ex_mem_raddr_o;
|
|
||||||
assign rib_ex_data_o = ex_mem_wdata_o;
|
|
||||||
assign rib_ex_req_o = ex_mem_req_o;
|
|
||||||
assign rib_ex_we_o = ex_mem_we_o;
|
|
||||||
|
|
||||||
assign rib_pc_addr_o = pc_pc_o;
|
|
||||||
|
|
||||||
|
|
||||||
// pc_reg模块例化
|
|
||||||
pc_reg u_pc_reg(
|
|
||||||
.clk(clk),
|
|
||||||
.rst(rst),
|
|
||||||
.jtag_reset_flag_i(jtag_reset_flag_i),
|
|
||||||
.pc_o(pc_pc_o),
|
|
||||||
.hold_flag_i(ctrl_hold_flag_o),
|
|
||||||
.jump_flag_i(ctrl_jump_flag_o),
|
|
||||||
.jump_addr_i(ctrl_jump_addr_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
// ctrl模块例化
|
|
||||||
ctrl u_ctrl(
|
|
||||||
.rst(rst),
|
|
||||||
.jump_flag_i(ex_jump_flag_o),
|
|
||||||
.jump_addr_i(ex_jump_addr_o),
|
|
||||||
.hold_flag_ex_i(ex_hold_flag_o),
|
|
||||||
.hold_flag_rib_i(rib_hold_flag_i),
|
|
||||||
.hold_flag_o(ctrl_hold_flag_o),
|
|
||||||
.hold_flag_clint_i(clint_hold_flag_o),
|
|
||||||
.jump_flag_o(ctrl_jump_flag_o),
|
|
||||||
.jump_addr_o(ctrl_jump_addr_o),
|
|
||||||
.jtag_halt_flag_i(jtag_halt_flag_i)
|
|
||||||
);
|
|
||||||
|
|
||||||
// regs模块例化
|
|
||||||
regs u_regs(
|
|
||||||
.clk(clk),
|
|
||||||
.rst(rst),
|
|
||||||
.we_i(ex_reg_we_o),
|
|
||||||
.waddr_i(ex_reg_waddr_o),
|
|
||||||
.wdata_i(ex_reg_wdata_o),
|
|
||||||
.raddr1_i(id_reg1_raddr_o),
|
|
||||||
.rdata1_o(regs_rdata1_o),
|
|
||||||
.raddr2_i(id_reg2_raddr_o),
|
|
||||||
.rdata2_o(regs_rdata2_o),
|
|
||||||
.jtag_we_i(jtag_reg_we_i),
|
|
||||||
.jtag_addr_i(jtag_reg_addr_i),
|
|
||||||
.jtag_data_i(jtag_reg_data_i),
|
|
||||||
.jtag_data_o(jtag_reg_data_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
// csr_reg模块例化
|
|
||||||
csr_reg u_csr_reg(
|
|
||||||
.clk(clk),
|
|
||||||
.rst(rst),
|
|
||||||
.we_i(ex_csr_we_o),
|
|
||||||
.raddr_i(id_csr_raddr_o),
|
|
||||||
.waddr_i(ex_csr_waddr_o),
|
|
||||||
.data_i(ex_csr_wdata_o),
|
|
||||||
.data_o(csr_data_o),
|
|
||||||
.global_int_en_o(csr_global_int_en_o),
|
|
||||||
.clint_we_i(clint_we_o),
|
|
||||||
.clint_raddr_i(clint_raddr_o),
|
|
||||||
.clint_waddr_i(clint_waddr_o),
|
|
||||||
.clint_data_i(clint_data_o),
|
|
||||||
.clint_data_o(csr_clint_data_o),
|
|
||||||
.clint_csr_mtvec(csr_clint_csr_mtvec),
|
|
||||||
.clint_csr_mepc(csr_clint_csr_mepc),
|
|
||||||
.clint_csr_mstatus(csr_clint_csr_mstatus)
|
|
||||||
);
|
|
||||||
|
|
||||||
// if_id模块例化
|
|
||||||
if_id u_if_id(
|
|
||||||
.clk(clk),
|
|
||||||
.rst(rst),
|
|
||||||
.inst_i(rib_pc_data_i),
|
|
||||||
.inst_addr_i(pc_pc_o),
|
|
||||||
.int_flag_i(int_i),
|
|
||||||
.int_flag_o(if_int_flag_o),
|
|
||||||
.hold_flag_i(ctrl_hold_flag_o),
|
|
||||||
.inst_o(if_inst_o),
|
|
||||||
.inst_addr_o(if_inst_addr_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
// id模块例化
|
|
||||||
id u_id(
|
|
||||||
.rst(rst),
|
|
||||||
.inst_i(if_inst_o),
|
|
||||||
.inst_addr_i(if_inst_addr_o),
|
|
||||||
.reg1_rdata_i(regs_rdata1_o),
|
|
||||||
.reg2_rdata_i(regs_rdata2_o),
|
|
||||||
.ex_jump_flag_i(ex_jump_flag_o),
|
|
||||||
.reg1_raddr_o(id_reg1_raddr_o),
|
|
||||||
.reg2_raddr_o(id_reg2_raddr_o),
|
|
||||||
.inst_o(id_inst_o),
|
|
||||||
.inst_addr_o(id_inst_addr_o),
|
|
||||||
.reg1_rdata_o(id_reg1_rdata_o),
|
|
||||||
.reg2_rdata_o(id_reg2_rdata_o),
|
|
||||||
.reg_we_o(id_reg_we_o),
|
|
||||||
.reg_waddr_o(id_reg_waddr_o),
|
|
||||||
.op1_o(id_op1_o),
|
|
||||||
.op2_o(id_op2_o),
|
|
||||||
.op1_jump_o(id_op1_jump_o),
|
|
||||||
.op2_jump_o(id_op2_jump_o),
|
|
||||||
.csr_rdata_i(csr_data_o),
|
|
||||||
.csr_raddr_o(id_csr_raddr_o),
|
|
||||||
.csr_we_o(id_csr_we_o),
|
|
||||||
.csr_rdata_o(id_csr_rdata_o),
|
|
||||||
.csr_waddr_o(id_csr_waddr_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
// id_ex模块例化
|
|
||||||
id_ex u_id_ex(
|
|
||||||
.clk(clk),
|
|
||||||
.rst(rst),
|
|
||||||
.inst_i(id_inst_o),
|
|
||||||
.inst_addr_i(id_inst_addr_o),
|
|
||||||
.reg_we_i(id_reg_we_o),
|
|
||||||
.reg_waddr_i(id_reg_waddr_o),
|
|
||||||
.reg1_rdata_i(id_reg1_rdata_o),
|
|
||||||
.reg2_rdata_i(id_reg2_rdata_o),
|
|
||||||
.hold_flag_i(ctrl_hold_flag_o),
|
|
||||||
.inst_o(ie_inst_o),
|
|
||||||
.inst_addr_o(ie_inst_addr_o),
|
|
||||||
.reg_we_o(ie_reg_we_o),
|
|
||||||
.reg_waddr_o(ie_reg_waddr_o),
|
|
||||||
.reg1_rdata_o(ie_reg1_rdata_o),
|
|
||||||
.reg2_rdata_o(ie_reg2_rdata_o),
|
|
||||||
.op1_i(id_op1_o),
|
|
||||||
.op2_i(id_op2_o),
|
|
||||||
.op1_jump_i(id_op1_jump_o),
|
|
||||||
.op2_jump_i(id_op2_jump_o),
|
|
||||||
.op1_o(ie_op1_o),
|
|
||||||
.op2_o(ie_op2_o),
|
|
||||||
.op1_jump_o(ie_op1_jump_o),
|
|
||||||
.op2_jump_o(ie_op2_jump_o),
|
|
||||||
.csr_we_i(id_csr_we_o),
|
|
||||||
.csr_waddr_i(id_csr_waddr_o),
|
|
||||||
.csr_rdata_i(id_csr_rdata_o),
|
|
||||||
.csr_we_o(ie_csr_we_o),
|
|
||||||
.csr_waddr_o(ie_csr_waddr_o),
|
|
||||||
.csr_rdata_o(ie_csr_rdata_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
// ex模块例化
|
|
||||||
ex u_ex(
|
|
||||||
.rst(rst),
|
|
||||||
.inst_i(ie_inst_o),
|
|
||||||
.inst_addr_i(ie_inst_addr_o),
|
|
||||||
.reg_we_i(ie_reg_we_o),
|
|
||||||
.reg_waddr_i(ie_reg_waddr_o),
|
|
||||||
.reg1_rdata_i(ie_reg1_rdata_o),
|
|
||||||
.reg2_rdata_i(ie_reg2_rdata_o),
|
|
||||||
.op1_i(ie_op1_o),
|
|
||||||
.op2_i(ie_op2_o),
|
|
||||||
.op1_jump_i(ie_op1_jump_o),
|
|
||||||
.op2_jump_i(ie_op2_jump_o),
|
|
||||||
.mem_rdata_i(rib_ex_data_i),
|
|
||||||
.mem_wdata_o(ex_mem_wdata_o),
|
|
||||||
.mem_raddr_o(ex_mem_raddr_o),
|
|
||||||
.mem_waddr_o(ex_mem_waddr_o),
|
|
||||||
.mem_we_o(ex_mem_we_o),
|
|
||||||
.mem_req_o(ex_mem_req_o),
|
|
||||||
.reg_wdata_o(ex_reg_wdata_o),
|
|
||||||
.reg_we_o(ex_reg_we_o),
|
|
||||||
.reg_waddr_o(ex_reg_waddr_o),
|
|
||||||
.hold_flag_o(ex_hold_flag_o),
|
|
||||||
.jump_flag_o(ex_jump_flag_o),
|
|
||||||
.jump_addr_o(ex_jump_addr_o),
|
|
||||||
.int_assert_i(clint_int_assert_o),
|
|
||||||
.int_addr_i(clint_int_addr_o),
|
|
||||||
.div_ready_i(div_ready_o),
|
|
||||||
.div_result_i(div_result_o),
|
|
||||||
.div_busy_i(div_busy_o),
|
|
||||||
.div_reg_waddr_i(div_reg_waddr_o),
|
|
||||||
.div_start_o(ex_div_start_o),
|
|
||||||
.div_dividend_o(ex_div_dividend_o),
|
|
||||||
.div_divisor_o(ex_div_divisor_o),
|
|
||||||
.div_op_o(ex_div_op_o),
|
|
||||||
.div_reg_waddr_o(ex_div_reg_waddr_o),
|
|
||||||
.csr_we_i(ie_csr_we_o),
|
|
||||||
.csr_waddr_i(ie_csr_waddr_o),
|
|
||||||
.csr_rdata_i(ie_csr_rdata_o),
|
|
||||||
.csr_wdata_o(ex_csr_wdata_o),
|
|
||||||
.csr_we_o(ex_csr_we_o),
|
|
||||||
.csr_waddr_o(ex_csr_waddr_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
// div模块例化
|
|
||||||
div u_div(
|
|
||||||
.clk(clk),
|
|
||||||
.rst(rst),
|
|
||||||
.dividend_i(ex_div_dividend_o),
|
|
||||||
.divisor_i(ex_div_divisor_o),
|
|
||||||
.start_i(ex_div_start_o),
|
|
||||||
.op_i(ex_div_op_o),
|
|
||||||
.reg_waddr_i(ex_div_reg_waddr_o),
|
|
||||||
.result_o(div_result_o),
|
|
||||||
.ready_o(div_ready_o),
|
|
||||||
.busy_o(div_busy_o),
|
|
||||||
.reg_waddr_o(div_reg_waddr_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
// clint模块例化
|
|
||||||
clint u_clint(
|
|
||||||
.clk(clk),
|
|
||||||
.rst(rst),
|
|
||||||
.int_flag_i(if_int_flag_o),
|
|
||||||
.inst_i(id_inst_o),
|
|
||||||
.inst_addr_i(id_inst_addr_o),
|
|
||||||
.jump_flag_i(ex_jump_flag_o),
|
|
||||||
.jump_addr_i(ex_jump_addr_o),
|
|
||||||
.hold_flag_i(ctrl_hold_flag_o),
|
|
||||||
.div_started_i(ex_div_start_o),
|
|
||||||
.data_i(csr_clint_data_o),
|
|
||||||
.csr_mtvec(csr_clint_csr_mtvec),
|
|
||||||
.csr_mepc(csr_clint_csr_mepc),
|
|
||||||
.csr_mstatus(csr_clint_csr_mstatus),
|
|
||||||
.we_o(clint_we_o),
|
|
||||||
.waddr_o(clint_waddr_o),
|
|
||||||
.raddr_o(clint_raddr_o),
|
|
||||||
.data_o(clint_data_o),
|
|
||||||
.hold_flag_o(clint_hold_flag_o),
|
|
||||||
.global_int_en_i(csr_global_int_en_o),
|
|
||||||
.int_addr_o(clint_int_addr_o),
|
|
||||||
.int_assert_o(clint_int_assert_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,366 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "defines.sv"
|
||||||
|
|
||||||
|
// tinyriscv处理器核顶层模块
|
||||||
|
module tinyriscv_core #(
|
||||||
|
parameter int unsigned DEBUG_HALT_ADDR = 32'h10000800,
|
||||||
|
parameter int unsigned DEBUG_EXCEPTION_ADDR = 32'h10000808,
|
||||||
|
parameter bit BranchPredictor = 1'b1,
|
||||||
|
parameter bit TRACE_ENABLE = 1'b0
|
||||||
|
)(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
// instr fetch interface
|
||||||
|
output wire instr_req_o,
|
||||||
|
input wire instr_gnt_i,
|
||||||
|
input wire instr_rvalid_i,
|
||||||
|
output wire[31:0] instr_addr_o,
|
||||||
|
input wire[31:0] instr_rdata_i,
|
||||||
|
input wire instr_err_i,
|
||||||
|
|
||||||
|
// data access interface
|
||||||
|
output wire data_req_o,
|
||||||
|
input wire data_gnt_i,
|
||||||
|
input wire data_rvalid_i,
|
||||||
|
output wire data_we_o,
|
||||||
|
output wire[3:0] data_be_o,
|
||||||
|
output wire[31:0] data_addr_o,
|
||||||
|
output wire[31:0] data_wdata_o,
|
||||||
|
input wire[31:0] data_rdata_i,
|
||||||
|
input wire data_err_i,
|
||||||
|
|
||||||
|
// interrupt input
|
||||||
|
input wire int_req_i,
|
||||||
|
input wire[7:0] int_id_i,
|
||||||
|
|
||||||
|
// debug request signal
|
||||||
|
input wire debug_req_i
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
// ifu模块输出信号
|
||||||
|
wire[31:0] ifetch_inst_o;
|
||||||
|
wire[31:0] ifetch_pc_o;
|
||||||
|
wire ifetch_inst_valid_o;
|
||||||
|
|
||||||
|
// ifu_idu模块输出信号
|
||||||
|
wire[31:0] if_inst_o;
|
||||||
|
wire[31:0] if_inst_addr_o;
|
||||||
|
wire if_inst_valid_o;
|
||||||
|
wire if_ready_o;
|
||||||
|
|
||||||
|
// idu模块输出信号
|
||||||
|
wire[31:0] id_inst_o;
|
||||||
|
wire[31:0] id_inst_addr_o;
|
||||||
|
wire[`DECINFO_WIDTH-1:0] id_dec_info_bus_o;
|
||||||
|
wire[31:0] id_dec_imm_o;
|
||||||
|
wire[31:0] id_dec_pc_o;
|
||||||
|
wire[4:0] id_rs1_raddr_o;
|
||||||
|
wire[4:0] id_rs2_raddr_o;
|
||||||
|
wire[4:0] id_rd_waddr_o;
|
||||||
|
wire id_rd_we_o;
|
||||||
|
wire id_stall_o;
|
||||||
|
wire[31:0] id_rs1_rdata_o;
|
||||||
|
wire[31:0] id_rs2_rdata_o;
|
||||||
|
wire id_illegal_inst_o;
|
||||||
|
wire id_inst_valid_o;
|
||||||
|
|
||||||
|
// idu_exu模块输出信号
|
||||||
|
wire[31:0] ie_inst_o;
|
||||||
|
wire[31:0] ie_inst_addr_o;
|
||||||
|
wire[`DECINFO_WIDTH-1:0] ie_dec_info_bus_o;
|
||||||
|
wire[31:0] ie_dec_imm_o;
|
||||||
|
wire[31:0] ie_dec_pc_o;
|
||||||
|
wire[31:0] ie_rs1_rdata_o;
|
||||||
|
wire[31:0] ie_rs2_rdata_o;
|
||||||
|
wire[4:0] ie_rd_waddr_o;
|
||||||
|
wire ie_rd_we_o;
|
||||||
|
wire ie_inst_valid_o;
|
||||||
|
|
||||||
|
// exu模块输出信号
|
||||||
|
wire[31:0] ex_mem_wdata_o;
|
||||||
|
wire[31:0] ex_mem_addr_o;
|
||||||
|
wire ex_mem_we_o;
|
||||||
|
wire[3:0] ex_mem_sel_o;
|
||||||
|
wire ex_mem_req_valid_o;
|
||||||
|
wire ex_mem_rsp_ready_o;
|
||||||
|
wire ex_mem_access_misaligned_o;
|
||||||
|
wire[31:0] ex_reg_wdata_o;
|
||||||
|
wire ex_reg_we_o;
|
||||||
|
wire[4:0] ex_reg_waddr_o;
|
||||||
|
wire ex_hold_flag_o;
|
||||||
|
wire ex_jump_flag_o;
|
||||||
|
wire[31:0] ex_jump_addr_o;
|
||||||
|
wire[31:0] ex_csr_wdata_o;
|
||||||
|
wire ex_csr_we_o;
|
||||||
|
wire[31:0] ex_csr_waddr_o;
|
||||||
|
wire[31:0] ex_csr_raddr_o;
|
||||||
|
wire ex_inst_ecall_o;
|
||||||
|
wire ex_inst_ebreak_o;
|
||||||
|
wire ex_inst_mret_o;
|
||||||
|
wire ex_inst_dret_o;
|
||||||
|
wire ex_inst_valid_o;
|
||||||
|
wire ex_inst_executed_o;
|
||||||
|
|
||||||
|
// gpr_reg模块输出信号
|
||||||
|
wire[31:0] regs_rdata1_o;
|
||||||
|
wire[31:0] regs_rdata2_o;
|
||||||
|
|
||||||
|
// csr_reg模块输出信号
|
||||||
|
wire[31:0] csr_ex_data_o;
|
||||||
|
wire[31:0] csr_clint_data_o;
|
||||||
|
wire[31:0] csr_mtvec_o;
|
||||||
|
wire[31:0] csr_mepc_o;
|
||||||
|
wire[31:0] csr_mstatus_o;
|
||||||
|
wire[31:0] csr_mie_o;
|
||||||
|
wire[31:0] csr_dpc_o;
|
||||||
|
wire[31:0] csr_dcsr_o;
|
||||||
|
wire csr_trigger_match_o;
|
||||||
|
|
||||||
|
// pipe_ctrl模块输出信号
|
||||||
|
wire[31:0] ctrl_flush_addr_o;
|
||||||
|
wire ctrl_flush_o;
|
||||||
|
wire[`STALL_WIDTH-1:0] ctrl_stall_o;
|
||||||
|
|
||||||
|
// exception模块输出信号
|
||||||
|
wire excep_csr_we_o;
|
||||||
|
wire[31:0] excep_csr_waddr_o;
|
||||||
|
wire[31:0] excep_csr_wdata_o;
|
||||||
|
wire excep_stall_flag_o;
|
||||||
|
wire[31:0] excep_int_addr_o;
|
||||||
|
wire excep_int_assert_o;
|
||||||
|
|
||||||
|
|
||||||
|
ifu #(
|
||||||
|
.BranchPredictor(BranchPredictor)
|
||||||
|
) u_ifu (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.flush_addr_i(ctrl_flush_addr_o),
|
||||||
|
.stall_i(ctrl_stall_o),
|
||||||
|
.flush_i(ctrl_flush_o),
|
||||||
|
.id_ready_i(if_ready_o),
|
||||||
|
.inst_o(ifetch_inst_o),
|
||||||
|
.pc_o(ifetch_pc_o),
|
||||||
|
.inst_valid_o(ifetch_inst_valid_o),
|
||||||
|
.instr_req_o(instr_req_o),
|
||||||
|
.instr_gnt_i(instr_gnt_i),
|
||||||
|
.instr_rvalid_i(instr_rvalid_i),
|
||||||
|
.instr_addr_o(instr_addr_o),
|
||||||
|
.instr_rdata_i(instr_rdata_i),
|
||||||
|
.instr_err_i(instr_err_i)
|
||||||
|
);
|
||||||
|
|
||||||
|
pipe_ctrl u_pipe_ctrl(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.stall_from_id_i(id_stall_o),
|
||||||
|
.stall_from_ex_i(ex_hold_flag_o),
|
||||||
|
.stall_from_jtag_i(1'b0),
|
||||||
|
.stall_from_clint_i(excep_stall_flag_o),
|
||||||
|
.jump_assert_i(ex_jump_flag_o),
|
||||||
|
.jump_addr_i(ex_jump_addr_o),
|
||||||
|
.flush_o(ctrl_flush_o),
|
||||||
|
.stall_o(ctrl_stall_o),
|
||||||
|
.flush_addr_o(ctrl_flush_addr_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
gpr_reg u_gpr_reg(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.we_i(ex_reg_we_o),
|
||||||
|
.waddr_i(ex_reg_waddr_o),
|
||||||
|
.wdata_i(ex_reg_wdata_o),
|
||||||
|
.raddr1_i(id_rs1_raddr_o),
|
||||||
|
.rdata1_o(regs_rdata1_o),
|
||||||
|
.raddr2_i(id_rs2_raddr_o),
|
||||||
|
.rdata2_o(regs_rdata2_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
csr_reg u_csr_reg(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.pc_if_i(ie_dec_pc_o),
|
||||||
|
.trigger_match_o(csr_trigger_match_o),
|
||||||
|
.exu_we_i(ex_csr_we_o),
|
||||||
|
.exu_raddr_i(ex_csr_raddr_o),
|
||||||
|
.exu_waddr_i(ex_csr_waddr_o),
|
||||||
|
.exu_wdata_i(ex_csr_wdata_o),
|
||||||
|
.exu_rdata_o(csr_ex_data_o),
|
||||||
|
.excep_we_i(excep_csr_we_o),
|
||||||
|
.excep_waddr_i(excep_csr_waddr_o),
|
||||||
|
.excep_wdata_i(excep_csr_wdata_o),
|
||||||
|
.mtvec_o(csr_mtvec_o),
|
||||||
|
.mepc_o(csr_mepc_o),
|
||||||
|
.mstatus_o(csr_mstatus_o),
|
||||||
|
.mie_o(csr_mie_o),
|
||||||
|
.dpc_o(csr_dpc_o),
|
||||||
|
.dcsr_o(csr_dcsr_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
ifu_idu u_ifu_idu(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.inst_i(ifetch_inst_o),
|
||||||
|
.inst_addr_i(ifetch_pc_o),
|
||||||
|
.stall_i(ctrl_stall_o),
|
||||||
|
.flush_i(ctrl_flush_o),
|
||||||
|
.inst_valid_i(ifetch_inst_valid_o),
|
||||||
|
.ready_o(if_ready_o),
|
||||||
|
.inst_valid_o(if_inst_valid_o),
|
||||||
|
.inst_o(if_inst_o),
|
||||||
|
.inst_addr_o(if_inst_addr_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
idu u_idu(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.inst_i(if_inst_o),
|
||||||
|
.inst_valid_i(if_inst_valid_o),
|
||||||
|
.rs1_rdata_i(regs_rdata1_o),
|
||||||
|
.rs2_rdata_i(regs_rdata2_o),
|
||||||
|
.inst_o(id_inst_o),
|
||||||
|
.inst_valid_o(id_inst_valid_o),
|
||||||
|
.inst_addr_i(if_inst_addr_o),
|
||||||
|
.rs1_rdata_o(id_rs1_rdata_o),
|
||||||
|
.rs2_rdata_o(id_rs2_rdata_o),
|
||||||
|
.stall_o(id_stall_o),
|
||||||
|
.illegal_inst_o(id_illegal_inst_o),
|
||||||
|
.dec_info_bus_o(id_dec_info_bus_o),
|
||||||
|
.dec_imm_o(id_dec_imm_o),
|
||||||
|
.dec_pc_o(id_dec_pc_o),
|
||||||
|
.rs1_raddr_o(id_rs1_raddr_o),
|
||||||
|
.rs2_raddr_o(id_rs2_raddr_o),
|
||||||
|
.rd_waddr_o(id_rd_waddr_o),
|
||||||
|
.rd_we_o(id_rd_we_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
idu_exu u_idu_exu(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.inst_i(id_inst_o),
|
||||||
|
.stall_i(ctrl_stall_o),
|
||||||
|
.flush_i(ctrl_flush_o),
|
||||||
|
.dec_info_bus_i(id_dec_info_bus_o),
|
||||||
|
.dec_imm_i(id_dec_imm_o),
|
||||||
|
.dec_pc_i(id_dec_pc_o),
|
||||||
|
.rs1_rdata_i(id_rs1_rdata_o),
|
||||||
|
.rs2_rdata_i(id_rs2_rdata_o),
|
||||||
|
.rd_waddr_i(id_rd_waddr_o),
|
||||||
|
.rd_we_i(id_rd_we_o),
|
||||||
|
.inst_valid_i(id_inst_valid_o),
|
||||||
|
.inst_valid_o(ie_inst_valid_o),
|
||||||
|
.inst_o(ie_inst_o),
|
||||||
|
.dec_info_bus_o(ie_dec_info_bus_o),
|
||||||
|
.dec_imm_o(ie_dec_imm_o),
|
||||||
|
.dec_pc_o(ie_dec_pc_o),
|
||||||
|
.rs1_rdata_o(ie_rs1_rdata_o),
|
||||||
|
.rs2_rdata_o(ie_rs2_rdata_o),
|
||||||
|
.rd_waddr_o(ie_rd_waddr_o),
|
||||||
|
.rd_we_o(ie_rd_we_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
exu #(
|
||||||
|
.BranchPredictor(BranchPredictor)
|
||||||
|
) u_exu (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.reg1_rdata_i(ie_rs1_rdata_o),
|
||||||
|
.reg2_rdata_i(ie_rs2_rdata_o),
|
||||||
|
.mem_rdata_i(data_rdata_i),
|
||||||
|
.mem_gnt_i(data_gnt_i),
|
||||||
|
.mem_rvalid_i(data_rvalid_i),
|
||||||
|
.mem_wdata_o(data_wdata_o),
|
||||||
|
.mem_addr_o(data_addr_o),
|
||||||
|
.mem_we_o(data_we_o),
|
||||||
|
.mem_be_o(data_be_o),
|
||||||
|
.mem_req_o(data_req_o),
|
||||||
|
.mem_access_misaligned_o(ex_mem_access_misaligned_o),
|
||||||
|
.reg_wdata_o(ex_reg_wdata_o),
|
||||||
|
.reg_we_o(ex_reg_we_o),
|
||||||
|
.reg_waddr_o(ex_reg_waddr_o),
|
||||||
|
.hold_flag_o(ex_hold_flag_o),
|
||||||
|
.jump_flag_o(ex_jump_flag_o),
|
||||||
|
.jump_addr_o(ex_jump_addr_o),
|
||||||
|
.int_assert_i(excep_int_assert_o),
|
||||||
|
.int_addr_i(excep_int_addr_o),
|
||||||
|
.inst_ecall_o(ex_inst_ecall_o),
|
||||||
|
.inst_ebreak_o(ex_inst_ebreak_o),
|
||||||
|
.inst_mret_o(ex_inst_mret_o),
|
||||||
|
.inst_dret_o(ex_inst_dret_o),
|
||||||
|
.int_stall_i(excep_stall_flag_o),
|
||||||
|
.csr_raddr_o(ex_csr_raddr_o),
|
||||||
|
.csr_rdata_i(csr_ex_data_o),
|
||||||
|
.csr_wdata_o(ex_csr_wdata_o),
|
||||||
|
.csr_we_o(ex_csr_we_o),
|
||||||
|
.csr_waddr_o(ex_csr_waddr_o),
|
||||||
|
.inst_valid_o(ex_inst_valid_o),
|
||||||
|
.inst_valid_i(ie_inst_valid_o),
|
||||||
|
.inst_executed_o(ex_inst_executed_o),
|
||||||
|
.inst_i(ie_inst_o),
|
||||||
|
.dec_info_bus_i(ie_dec_info_bus_o),
|
||||||
|
.dec_imm_i(ie_dec_imm_o),
|
||||||
|
.dec_pc_i(ie_dec_pc_o),
|
||||||
|
.next_pc_i(if_inst_addr_o),
|
||||||
|
.rd_waddr_i(ie_rd_waddr_o),
|
||||||
|
.rd_we_i(ie_rd_we_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
exception u_exception(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.illegal_inst_i(id_illegal_inst_o),
|
||||||
|
.inst_valid_i(ie_inst_valid_o),
|
||||||
|
.inst_executed_i(ex_inst_executed_o),
|
||||||
|
.inst_ecall_i(ex_inst_ecall_o),
|
||||||
|
.inst_ebreak_i(ex_inst_ebreak_o),
|
||||||
|
.inst_mret_i(ex_inst_mret_o),
|
||||||
|
.inst_dret_i(ex_inst_dret_o),
|
||||||
|
.inst_addr_i(ie_dec_pc_o),
|
||||||
|
.mtvec_i(csr_mtvec_o),
|
||||||
|
.mepc_i(csr_mepc_o),
|
||||||
|
.mstatus_i(csr_mstatus_o),
|
||||||
|
.mie_i(csr_mie_o),
|
||||||
|
.dpc_i(csr_dpc_o),
|
||||||
|
.dcsr_i(csr_dcsr_o),
|
||||||
|
.trigger_match_i(csr_trigger_match_o),
|
||||||
|
.int_req_i(int_req_i),
|
||||||
|
.int_id_i(int_id_i),
|
||||||
|
.debug_halt_addr_i(DEBUG_HALT_ADDR),
|
||||||
|
.debug_req_i(debug_req_i),
|
||||||
|
.csr_we_o(excep_csr_we_o),
|
||||||
|
.csr_waddr_o(excep_csr_waddr_o),
|
||||||
|
.csr_wdata_o(excep_csr_wdata_o),
|
||||||
|
.stall_flag_o(excep_stall_flag_o),
|
||||||
|
.int_addr_o(excep_int_addr_o),
|
||||||
|
.int_assert_o(excep_int_assert_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (TRACE_ENABLE) begin: instr_trace
|
||||||
|
tracer u_tracer(
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.inst_i(ie_inst_o),
|
||||||
|
.pc_i(ie_dec_pc_o),
|
||||||
|
.inst_valid_i(ex_inst_valid_o)
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,613 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module tracer(
|
||||||
|
input logic clk,
|
||||||
|
input logic rst_n,
|
||||||
|
|
||||||
|
input logic[31:0] inst_i,
|
||||||
|
input logic[31:0] pc_i,
|
||||||
|
input logic inst_valid_i
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum logic [6:0] {
|
||||||
|
OPCODE_LOAD = 7'h03,
|
||||||
|
OPCODE_MISC_MEM = 7'h0f,
|
||||||
|
OPCODE_OP_IMM = 7'h13,
|
||||||
|
OPCODE_AUIPC = 7'h17,
|
||||||
|
OPCODE_STORE = 7'h23,
|
||||||
|
OPCODE_OP = 7'h33,
|
||||||
|
OPCODE_LUI = 7'h37,
|
||||||
|
OPCODE_BRANCH = 7'h63,
|
||||||
|
OPCODE_JALR = 7'h67,
|
||||||
|
OPCODE_JAL = 7'h6f,
|
||||||
|
OPCODE_SYSTEM = 7'h73
|
||||||
|
} opcode_e;
|
||||||
|
|
||||||
|
|
||||||
|
// instruction masks (for tracer)
|
||||||
|
parameter logic [31:0] INSN_LUI = { 25'h?, {OPCODE_LUI } };
|
||||||
|
parameter logic [31:0] INSN_AUIPC = { 25'h?, {OPCODE_AUIPC} };
|
||||||
|
parameter logic [31:0] INSN_JAL = { 25'h?, {OPCODE_JAL } };
|
||||||
|
parameter logic [31:0] INSN_JALR = { 17'h?, 3'b000, 5'h?, {OPCODE_JALR } };
|
||||||
|
|
||||||
|
// BRANCH
|
||||||
|
parameter logic [31:0] INSN_BEQ = { 17'h?, 3'b000, 5'h?, {OPCODE_BRANCH} };
|
||||||
|
parameter logic [31:0] INSN_BNE = { 17'h?, 3'b001, 5'h?, {OPCODE_BRANCH} };
|
||||||
|
parameter logic [31:0] INSN_BLT = { 17'h?, 3'b100, 5'h?, {OPCODE_BRANCH} };
|
||||||
|
parameter logic [31:0] INSN_BGE = { 17'h?, 3'b101, 5'h?, {OPCODE_BRANCH} };
|
||||||
|
parameter logic [31:0] INSN_BLTU = { 17'h?, 3'b110, 5'h?, {OPCODE_BRANCH} };
|
||||||
|
parameter logic [31:0] INSN_BGEU = { 17'h?, 3'b111, 5'h?, {OPCODE_BRANCH} };
|
||||||
|
|
||||||
|
// OPIMM
|
||||||
|
parameter logic [31:0] INSN_ADDI = { 17'h?, 3'b000, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
parameter logic [31:0] INSN_SLTI = { 17'h?, 3'b010, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
parameter logic [31:0] INSN_SLTIU = { 17'h?, 3'b011, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
parameter logic [31:0] INSN_XORI = { 17'h?, 3'b100, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
parameter logic [31:0] INSN_ORI = { 17'h?, 3'b110, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
parameter logic [31:0] INSN_ANDI = { 17'h?, 3'b111, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
parameter logic [31:0] INSN_SLLI = { 7'b0000000, 10'h?, 3'b001, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
parameter logic [31:0] INSN_SRLI = { 7'b0000000, 10'h?, 3'b101, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
parameter logic [31:0] INSN_SRAI = { 7'b0100000, 10'h?, 3'b101, 5'h?, {OPCODE_OP_IMM} };
|
||||||
|
|
||||||
|
// OP
|
||||||
|
parameter logic [31:0] INSN_ADD = { 7'b0000000, 10'h?, 3'b000, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_SUB = { 7'b0100000, 10'h?, 3'b000, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_SLL = { 7'b0000000, 10'h?, 3'b001, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_SLT = { 7'b0000000, 10'h?, 3'b010, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_SLTU = { 7'b0000000, 10'h?, 3'b011, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_XOR = { 7'b0000000, 10'h?, 3'b100, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_SRL = { 7'b0000000, 10'h?, 3'b101, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_SRA = { 7'b0100000, 10'h?, 3'b101, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_OR = { 7'b0000000, 10'h?, 3'b110, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_AND = { 7'b0000000, 10'h?, 3'b111, 5'h?, {OPCODE_OP} };
|
||||||
|
|
||||||
|
// SYSTEM
|
||||||
|
parameter logic [31:0] INSN_CSRRW = { 17'h?, 3'b001, 5'h?, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_CSRRS = { 17'h?, 3'b010, 5'h?, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_CSRRC = { 17'h?, 3'b011, 5'h?, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_CSRRWI = { 17'h?, 3'b101, 5'h?, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_CSRRSI = { 17'h?, 3'b110, 5'h?, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_CSRRCI = { 17'h?, 3'b111, 5'h?, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_ECALL = { 12'b000000000000, 13'b0, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_EBREAK = { 12'b000000000001, 13'b0, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_MRET = { 12'b001100000010, 13'b0, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_DRET = { 12'b011110110010, 13'b0, {OPCODE_SYSTEM} };
|
||||||
|
parameter logic [31:0] INSN_WFI = { 12'b000100000101, 13'b0, {OPCODE_SYSTEM} };
|
||||||
|
|
||||||
|
// RV32M
|
||||||
|
parameter logic [31:0] INSN_MUL = { 7'b0000001, 10'h?, 3'b000, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_MULH = { 7'b0000001, 10'h?, 3'b001, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_MULHSU = { 7'b0000001, 10'h?, 3'b010, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_MULHU = { 7'b0000001, 10'h?, 3'b011, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_DIV = { 7'b0000001, 10'h?, 3'b100, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_DIVU = { 7'b0000001, 10'h?, 3'b101, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_REM = { 7'b0000001, 10'h?, 3'b110, 5'h?, {OPCODE_OP} };
|
||||||
|
parameter logic [31:0] INSN_REMU = { 7'b0000001, 10'h?, 3'b111, 5'h?, {OPCODE_OP} };
|
||||||
|
|
||||||
|
// LOAD & STORE
|
||||||
|
parameter logic [31:0] INSN_LOAD = {25'h?, {OPCODE_LOAD } };
|
||||||
|
parameter logic [31:0] INSN_STORE = {25'h?, {OPCODE_STORE} };
|
||||||
|
|
||||||
|
// MISC-MEM
|
||||||
|
parameter logic [31:0] INSN_FENCE = { 17'h?, 3'b000, 5'h?, {OPCODE_MISC_MEM} };
|
||||||
|
parameter logic [31:0] INSN_FENCEI = { 17'h0, 3'b001, 5'h0, {OPCODE_MISC_MEM} };
|
||||||
|
|
||||||
|
// Get a CSR name for a CSR address.
|
||||||
|
function automatic string get_csr_name(input logic [11:0] csr_addr);
|
||||||
|
unique case (csr_addr)
|
||||||
|
12'd0: return "ustatus";
|
||||||
|
12'd4: return "uie";
|
||||||
|
12'd5: return "utvec";
|
||||||
|
12'd64: return "uscratch";
|
||||||
|
12'd65: return "uepc";
|
||||||
|
12'd66: return "ucause";
|
||||||
|
12'd67: return "utval";
|
||||||
|
12'd68: return "uip";
|
||||||
|
12'd1: return "fflags";
|
||||||
|
12'd2: return "frm";
|
||||||
|
12'd3: return "fcsr";
|
||||||
|
12'd3072: return "cycle";
|
||||||
|
12'd3073: return "time";
|
||||||
|
12'd3074: return "instret";
|
||||||
|
12'd3075: return "hpmcounter3";
|
||||||
|
12'd3076: return "hpmcounter4";
|
||||||
|
12'd3077: return "hpmcounter5";
|
||||||
|
12'd3078: return "hpmcounter6";
|
||||||
|
12'd3079: return "hpmcounter7";
|
||||||
|
12'd3080: return "hpmcounter8";
|
||||||
|
12'd3081: return "hpmcounter9";
|
||||||
|
12'd3082: return "hpmcounter10";
|
||||||
|
12'd3083: return "hpmcounter11";
|
||||||
|
12'd3084: return "hpmcounter12";
|
||||||
|
12'd3085: return "hpmcounter13";
|
||||||
|
12'd3086: return "hpmcounter14";
|
||||||
|
12'd3087: return "hpmcounter15";
|
||||||
|
12'd3088: return "hpmcounter16";
|
||||||
|
12'd3089: return "hpmcounter17";
|
||||||
|
12'd3090: return "hpmcounter18";
|
||||||
|
12'd3091: return "hpmcounter19";
|
||||||
|
12'd3092: return "hpmcounter20";
|
||||||
|
12'd3093: return "hpmcounter21";
|
||||||
|
12'd3094: return "hpmcounter22";
|
||||||
|
12'd3095: return "hpmcounter23";
|
||||||
|
12'd3096: return "hpmcounter24";
|
||||||
|
12'd3097: return "hpmcounter25";
|
||||||
|
12'd3098: return "hpmcounter26";
|
||||||
|
12'd3099: return "hpmcounter27";
|
||||||
|
12'd3100: return "hpmcounter28";
|
||||||
|
12'd3101: return "hpmcounter29";
|
||||||
|
12'd3102: return "hpmcounter30";
|
||||||
|
12'd3103: return "hpmcounter31";
|
||||||
|
12'd3200: return "cycleh";
|
||||||
|
12'd3201: return "timeh";
|
||||||
|
12'd3202: return "instreth";
|
||||||
|
12'd3203: return "hpmcounter3h";
|
||||||
|
12'd3204: return "hpmcounter4h";
|
||||||
|
12'd3205: return "hpmcounter5h";
|
||||||
|
12'd3206: return "hpmcounter6h";
|
||||||
|
12'd3207: return "hpmcounter7h";
|
||||||
|
12'd3208: return "hpmcounter8h";
|
||||||
|
12'd3209: return "hpmcounter9h";
|
||||||
|
12'd3210: return "hpmcounter10h";
|
||||||
|
12'd3211: return "hpmcounter11h";
|
||||||
|
12'd3212: return "hpmcounter12h";
|
||||||
|
12'd3213: return "hpmcounter13h";
|
||||||
|
12'd3214: return "hpmcounter14h";
|
||||||
|
12'd3215: return "hpmcounter15h";
|
||||||
|
12'd3216: return "hpmcounter16h";
|
||||||
|
12'd3217: return "hpmcounter17h";
|
||||||
|
12'd3218: return "hpmcounter18h";
|
||||||
|
12'd3219: return "hpmcounter19h";
|
||||||
|
12'd3220: return "hpmcounter20h";
|
||||||
|
12'd3221: return "hpmcounter21h";
|
||||||
|
12'd3222: return "hpmcounter22h";
|
||||||
|
12'd3223: return "hpmcounter23h";
|
||||||
|
12'd3224: return "hpmcounter24h";
|
||||||
|
12'd3225: return "hpmcounter25h";
|
||||||
|
12'd3226: return "hpmcounter26h";
|
||||||
|
12'd3227: return "hpmcounter27h";
|
||||||
|
12'd3228: return "hpmcounter28h";
|
||||||
|
12'd3229: return "hpmcounter29h";
|
||||||
|
12'd3230: return "hpmcounter30h";
|
||||||
|
12'd3231: return "hpmcounter31h";
|
||||||
|
12'd256: return "sstatus";
|
||||||
|
12'd258: return "sedeleg";
|
||||||
|
12'd259: return "sideleg";
|
||||||
|
12'd260: return "sie";
|
||||||
|
12'd261: return "stvec";
|
||||||
|
12'd262: return "scounteren";
|
||||||
|
12'd320: return "sscratch";
|
||||||
|
12'd321: return "sepc";
|
||||||
|
12'd322: return "scause";
|
||||||
|
12'd323: return "stval";
|
||||||
|
12'd324: return "sip";
|
||||||
|
12'd384: return "satp";
|
||||||
|
12'd3857: return "mvendorid";
|
||||||
|
12'd3858: return "marchid";
|
||||||
|
12'd3859: return "mimpid";
|
||||||
|
12'd3860: return "mhartid";
|
||||||
|
12'd768: return "mstatus";
|
||||||
|
12'd769: return "misa";
|
||||||
|
12'd770: return "medeleg";
|
||||||
|
12'd771: return "mideleg";
|
||||||
|
12'd772: return "mie";
|
||||||
|
12'd773: return "mtvec";
|
||||||
|
12'd774: return "mcounteren";
|
||||||
|
12'd832: return "mscratch";
|
||||||
|
12'd833: return "mepc";
|
||||||
|
12'd834: return "mcause";
|
||||||
|
12'd835: return "mtval";
|
||||||
|
12'd836: return "mip";
|
||||||
|
12'd928: return "pmpcfg0";
|
||||||
|
12'd929: return "pmpcfg1";
|
||||||
|
12'd930: return "pmpcfg2";
|
||||||
|
12'd931: return "pmpcfg3";
|
||||||
|
12'd944: return "pmpaddr0";
|
||||||
|
12'd945: return "pmpaddr1";
|
||||||
|
12'd946: return "pmpaddr2";
|
||||||
|
12'd947: return "pmpaddr3";
|
||||||
|
12'd948: return "pmpaddr4";
|
||||||
|
12'd949: return "pmpaddr5";
|
||||||
|
12'd950: return "pmpaddr6";
|
||||||
|
12'd951: return "pmpaddr7";
|
||||||
|
12'd952: return "pmpaddr8";
|
||||||
|
12'd953: return "pmpaddr9";
|
||||||
|
12'd954: return "pmpaddr10";
|
||||||
|
12'd955: return "pmpaddr11";
|
||||||
|
12'd956: return "pmpaddr12";
|
||||||
|
12'd957: return "pmpaddr13";
|
||||||
|
12'd958: return "pmpaddr14";
|
||||||
|
12'd959: return "pmpaddr15";
|
||||||
|
12'd2816: return "mcycle";
|
||||||
|
12'd2818: return "minstret";
|
||||||
|
12'd2819: return "mhpmcounter3";
|
||||||
|
12'd2820: return "mhpmcounter4";
|
||||||
|
12'd2821: return "mhpmcounter5";
|
||||||
|
12'd2822: return "mhpmcounter6";
|
||||||
|
12'd2823: return "mhpmcounter7";
|
||||||
|
12'd2824: return "mhpmcounter8";
|
||||||
|
12'd2825: return "mhpmcounter9";
|
||||||
|
12'd2826: return "mhpmcounter10";
|
||||||
|
12'd2827: return "mhpmcounter11";
|
||||||
|
12'd2828: return "mhpmcounter12";
|
||||||
|
12'd2829: return "mhpmcounter13";
|
||||||
|
12'd2830: return "mhpmcounter14";
|
||||||
|
12'd2831: return "mhpmcounter15";
|
||||||
|
12'd2832: return "mhpmcounter16";
|
||||||
|
12'd2833: return "mhpmcounter17";
|
||||||
|
12'd2834: return "mhpmcounter18";
|
||||||
|
12'd2835: return "mhpmcounter19";
|
||||||
|
12'd2836: return "mhpmcounter20";
|
||||||
|
12'd2837: return "mhpmcounter21";
|
||||||
|
12'd2838: return "mhpmcounter22";
|
||||||
|
12'd2839: return "mhpmcounter23";
|
||||||
|
12'd2840: return "mhpmcounter24";
|
||||||
|
12'd2841: return "mhpmcounter25";
|
||||||
|
12'd2842: return "mhpmcounter26";
|
||||||
|
12'd2843: return "mhpmcounter27";
|
||||||
|
12'd2844: return "mhpmcounter28";
|
||||||
|
12'd2845: return "mhpmcounter29";
|
||||||
|
12'd2846: return "mhpmcounter30";
|
||||||
|
12'd2847: return "mhpmcounter31";
|
||||||
|
12'd2944: return "mcycleh";
|
||||||
|
12'd2946: return "minstreth";
|
||||||
|
12'd2947: return "mhpmcounter3h";
|
||||||
|
12'd2948: return "mhpmcounter4h";
|
||||||
|
12'd2949: return "mhpmcounter5h";
|
||||||
|
12'd2950: return "mhpmcounter6h";
|
||||||
|
12'd2951: return "mhpmcounter7h";
|
||||||
|
12'd2952: return "mhpmcounter8h";
|
||||||
|
12'd2953: return "mhpmcounter9h";
|
||||||
|
12'd2954: return "mhpmcounter10h";
|
||||||
|
12'd2955: return "mhpmcounter11h";
|
||||||
|
12'd2956: return "mhpmcounter12h";
|
||||||
|
12'd2957: return "mhpmcounter13h";
|
||||||
|
12'd2958: return "mhpmcounter14h";
|
||||||
|
12'd2959: return "mhpmcounter15h";
|
||||||
|
12'd2960: return "mhpmcounter16h";
|
||||||
|
12'd2961: return "mhpmcounter17h";
|
||||||
|
12'd2962: return "mhpmcounter18h";
|
||||||
|
12'd2963: return "mhpmcounter19h";
|
||||||
|
12'd2964: return "mhpmcounter20h";
|
||||||
|
12'd2965: return "mhpmcounter21h";
|
||||||
|
12'd2966: return "mhpmcounter22h";
|
||||||
|
12'd2967: return "mhpmcounter23h";
|
||||||
|
12'd2968: return "mhpmcounter24h";
|
||||||
|
12'd2969: return "mhpmcounter25h";
|
||||||
|
12'd2970: return "mhpmcounter26h";
|
||||||
|
12'd2971: return "mhpmcounter27h";
|
||||||
|
12'd2972: return "mhpmcounter28h";
|
||||||
|
12'd2973: return "mhpmcounter29h";
|
||||||
|
12'd2974: return "mhpmcounter30h";
|
||||||
|
12'd2975: return "mhpmcounter31h";
|
||||||
|
12'd803: return "mhpmevent3";
|
||||||
|
12'd804: return "mhpmevent4";
|
||||||
|
12'd805: return "mhpmevent5";
|
||||||
|
12'd806: return "mhpmevent6";
|
||||||
|
12'd807: return "mhpmevent7";
|
||||||
|
12'd808: return "mhpmevent8";
|
||||||
|
12'd809: return "mhpmevent9";
|
||||||
|
12'd810: return "mhpmevent10";
|
||||||
|
12'd811: return "mhpmevent11";
|
||||||
|
12'd812: return "mhpmevent12";
|
||||||
|
12'd813: return "mhpmevent13";
|
||||||
|
12'd814: return "mhpmevent14";
|
||||||
|
12'd815: return "mhpmevent15";
|
||||||
|
12'd816: return "mhpmevent16";
|
||||||
|
12'd817: return "mhpmevent17";
|
||||||
|
12'd818: return "mhpmevent18";
|
||||||
|
12'd819: return "mhpmevent19";
|
||||||
|
12'd820: return "mhpmevent20";
|
||||||
|
12'd821: return "mhpmevent21";
|
||||||
|
12'd822: return "mhpmevent22";
|
||||||
|
12'd823: return "mhpmevent23";
|
||||||
|
12'd824: return "mhpmevent24";
|
||||||
|
12'd825: return "mhpmevent25";
|
||||||
|
12'd826: return "mhpmevent26";
|
||||||
|
12'd827: return "mhpmevent27";
|
||||||
|
12'd828: return "mhpmevent28";
|
||||||
|
12'd829: return "mhpmevent29";
|
||||||
|
12'd830: return "mhpmevent30";
|
||||||
|
12'd831: return "mhpmevent31";
|
||||||
|
12'd1952: return "tselect";
|
||||||
|
12'd1953: return "tdata1";
|
||||||
|
12'd1954: return "tdata2";
|
||||||
|
12'd1955: return "tdata3";
|
||||||
|
12'd1968: return "dcsr";
|
||||||
|
12'd1969: return "dpc";
|
||||||
|
12'd1970: return "dscratch0";
|
||||||
|
12'd1971: return "dscratch1";
|
||||||
|
12'd512: return "hstatus";
|
||||||
|
12'd514: return "hedeleg";
|
||||||
|
12'd515: return "hideleg";
|
||||||
|
12'd516: return "hie";
|
||||||
|
12'd517: return "htvec";
|
||||||
|
12'd576: return "hscratch";
|
||||||
|
12'd577: return "hepc";
|
||||||
|
12'd578: return "hcause";
|
||||||
|
12'd579: return "hbadaddr";
|
||||||
|
12'd580: return "hip";
|
||||||
|
12'd896: return "mbase";
|
||||||
|
12'd897: return "mbound";
|
||||||
|
12'd898: return "mibase";
|
||||||
|
12'd899: return "mibound";
|
||||||
|
12'd900: return "mdbase";
|
||||||
|
12'd901: return "mdbound";
|
||||||
|
12'd800: return "mcountinhibit";
|
||||||
|
default: return $sformatf("0x%x", csr_addr);
|
||||||
|
endcase
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
int unsigned cycle;
|
||||||
|
string decoded_str;
|
||||||
|
int file_handle;
|
||||||
|
string file_name;
|
||||||
|
|
||||||
|
logic[4:0] rd_addr = inst_i[11:7];
|
||||||
|
logic[4:0] rs1_addr = inst_i[19:15];
|
||||||
|
logic[4:0] rs2_addr = inst_i[24:20];
|
||||||
|
|
||||||
|
|
||||||
|
function automatic void decode_u_insn(input string mnemonic);
|
||||||
|
decoded_str = $sformatf("%s x%0d,0x%0x", mnemonic, rd_addr, {inst_i[31:12]});
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_j_insn(input string mnemonic);
|
||||||
|
decoded_str = $sformatf("%s x%0d,%0x", mnemonic, rd_addr,
|
||||||
|
{{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0});
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_i_jalr_insn(input string mnemonic);
|
||||||
|
decoded_str = $sformatf("%s x%0d,%0d(x%0d)", mnemonic, rd_addr,
|
||||||
|
$signed({{20 {inst_i[31]}}, inst_i[31:20]}), rs1_addr);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_b_insn(input string mnemonic);
|
||||||
|
logic [31:0] branch_target;
|
||||||
|
logic [31:0] imm;
|
||||||
|
|
||||||
|
// We cannot use rvfi_pc_wdata for conditional jumps.
|
||||||
|
imm = $signed({ {19 {inst_i[31]}}, inst_i[31], inst_i[7],
|
||||||
|
inst_i[30:25], inst_i[11:8], 1'b0 });
|
||||||
|
branch_target = pc_i + imm;
|
||||||
|
|
||||||
|
decoded_str = $sformatf("%s x%0d,x%0d,%0x", mnemonic, rs1_addr, rs2_addr, branch_target);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_i_insn(input string mnemonic);
|
||||||
|
decoded_str = $sformatf("%s x%0d,x%0d,%0d", mnemonic, rd_addr, rs1_addr,
|
||||||
|
$signed({{20 {inst_i[31]}}, inst_i[31:20]}));
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_i_shift_insn(input string mnemonic);
|
||||||
|
logic [4:0] shamt;
|
||||||
|
|
||||||
|
shamt = {inst_i[24:20]};
|
||||||
|
decoded_str = $sformatf("%s x%0d,x%0d,0x%0x", mnemonic, rd_addr, rs1_addr, shamt);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_r_insn(input string mnemonic);
|
||||||
|
decoded_str = $sformatf("%s x%0d,x%0d,x%0d", mnemonic, rd_addr, rs1_addr, rs2_addr);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_csr_insn(input string mnemonic);
|
||||||
|
logic [11:0] csr;
|
||||||
|
string csr_name;
|
||||||
|
|
||||||
|
csr = inst_i[31:20];
|
||||||
|
csr_name = get_csr_name(csr);
|
||||||
|
|
||||||
|
if (!inst_i[14]) begin
|
||||||
|
decoded_str = $sformatf("%s x%0d,%s,x%0d", mnemonic, rd_addr, csr_name, rs1_addr);
|
||||||
|
end else begin
|
||||||
|
decoded_str = $sformatf("%s x%0d,%s,%0d", mnemonic, rd_addr, csr_name, { 27'b0, inst_i[19:15]});
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_mnemonic(input string mnemonic);
|
||||||
|
decoded_str = mnemonic;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_load_insn();
|
||||||
|
string mnemonic;
|
||||||
|
|
||||||
|
logic [2:0] size;
|
||||||
|
size = inst_i[14:12];
|
||||||
|
if (size == 3'b000) begin
|
||||||
|
mnemonic = "lb";
|
||||||
|
end else if (size == 3'b001) begin
|
||||||
|
mnemonic = "lh";
|
||||||
|
end else if (size == 3'b010) begin
|
||||||
|
mnemonic = "lw";
|
||||||
|
end else if (size == 3'b100) begin
|
||||||
|
mnemonic = "lbu";
|
||||||
|
end else if (size == 3'b101) begin
|
||||||
|
mnemonic = "lhu";
|
||||||
|
end else begin
|
||||||
|
decode_mnemonic("INVALID");
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
decoded_str = $sformatf("%s x%0d,%0d(x%0d)", mnemonic, rd_addr,
|
||||||
|
$signed({{20 {inst_i[31]}}, inst_i[31:20]}), rs1_addr);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_store_insn();
|
||||||
|
string mnemonic;
|
||||||
|
|
||||||
|
if (inst_i[13:12] == 2'b00) begin
|
||||||
|
mnemonic = "sb";
|
||||||
|
end else if (inst_i[13:12] == 2'b01) begin
|
||||||
|
mnemonic = "sh";
|
||||||
|
end else if (inst_i[13:12] == 2'b10) begin
|
||||||
|
mnemonic = "sw";
|
||||||
|
end else begin
|
||||||
|
decode_mnemonic("INVALID");
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (!inst_i[14]) begin
|
||||||
|
decoded_str = $sformatf("%s x%0d,%0d(x%0d)", mnemonic, rs2_addr,
|
||||||
|
$signed({ {20 {inst_i[31]}}, inst_i[31:25], inst_i[11:7] }), rs1_addr);
|
||||||
|
end else begin
|
||||||
|
decode_mnemonic("INVALID");
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic string get_fence_description(logic [3:0] bits);
|
||||||
|
string desc = "";
|
||||||
|
|
||||||
|
if (bits[3]) begin
|
||||||
|
desc = {desc, "i"};
|
||||||
|
end
|
||||||
|
if (bits[2]) begin
|
||||||
|
desc = {desc, "o"};
|
||||||
|
end
|
||||||
|
if (bits[1]) begin
|
||||||
|
desc = {desc, "r"};
|
||||||
|
end
|
||||||
|
if (bits[0]) begin
|
||||||
|
desc = {desc, "w"};
|
||||||
|
end
|
||||||
|
return desc;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic void decode_fence();
|
||||||
|
string predecessor;
|
||||||
|
string successor;
|
||||||
|
|
||||||
|
predecessor = get_fence_description(inst_i[27:24]);
|
||||||
|
successor = get_fence_description(inst_i[23:20]);
|
||||||
|
decoded_str = $sformatf("fence %s,%s", predecessor, successor);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
decoded_str = "";
|
||||||
|
|
||||||
|
unique casez (inst_i)
|
||||||
|
INSN_LUI: decode_u_insn("lui");
|
||||||
|
INSN_AUIPC: decode_u_insn("auipc");
|
||||||
|
INSN_JAL: decode_j_insn("jal");
|
||||||
|
INSN_JALR: decode_i_jalr_insn("jalr");
|
||||||
|
// BRANCH
|
||||||
|
INSN_BEQ: decode_b_insn("beq");
|
||||||
|
INSN_BNE: decode_b_insn("bne");
|
||||||
|
INSN_BLT: decode_b_insn("blt");
|
||||||
|
INSN_BGE: decode_b_insn("bge");
|
||||||
|
INSN_BLTU: decode_b_insn("bltu");
|
||||||
|
INSN_BGEU: decode_b_insn("bgeu");
|
||||||
|
// OPIMM
|
||||||
|
INSN_ADDI: begin
|
||||||
|
if (inst_i == 32'h00_00_00_13) begin
|
||||||
|
decode_mnemonic("nop");
|
||||||
|
end else begin
|
||||||
|
decode_i_insn("addi");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
INSN_SLTI: decode_i_insn("slti");
|
||||||
|
INSN_SLTIU: decode_i_insn("sltiu");
|
||||||
|
INSN_XORI: decode_i_insn("xori");
|
||||||
|
INSN_ORI: decode_i_insn("ori");
|
||||||
|
INSN_ANDI: decode_i_insn("andi");
|
||||||
|
INSN_SLLI: decode_i_shift_insn("slli");
|
||||||
|
INSN_SRLI: decode_i_shift_insn("srli");
|
||||||
|
INSN_SRAI: decode_i_shift_insn("srai");
|
||||||
|
// OP
|
||||||
|
INSN_ADD: decode_r_insn("add");
|
||||||
|
INSN_SUB: decode_r_insn("sub");
|
||||||
|
INSN_SLL: decode_r_insn("sll");
|
||||||
|
INSN_SLT: decode_r_insn("slt");
|
||||||
|
INSN_SLTU: decode_r_insn("sltu");
|
||||||
|
INSN_XOR: decode_r_insn("xor");
|
||||||
|
INSN_SRL: decode_r_insn("srl");
|
||||||
|
INSN_SRA: decode_r_insn("sra");
|
||||||
|
INSN_OR: decode_r_insn("or");
|
||||||
|
INSN_AND: decode_r_insn("and");
|
||||||
|
// SYSTEM (CSR manipulation)
|
||||||
|
INSN_CSRRW: decode_csr_insn("csrrw");
|
||||||
|
INSN_CSRRS: decode_csr_insn("csrrs");
|
||||||
|
INSN_CSRRC: decode_csr_insn("csrrc");
|
||||||
|
INSN_CSRRWI: decode_csr_insn("csrrwi");
|
||||||
|
INSN_CSRRSI: decode_csr_insn("csrrsi");
|
||||||
|
INSN_CSRRCI: decode_csr_insn("csrrci");
|
||||||
|
// SYSTEM (others)
|
||||||
|
INSN_ECALL: decode_mnemonic("ecall");
|
||||||
|
INSN_EBREAK: decode_mnemonic("ebreak");
|
||||||
|
INSN_MRET: decode_mnemonic("mret");
|
||||||
|
INSN_DRET: decode_mnemonic("dret");
|
||||||
|
INSN_WFI: decode_mnemonic("wfi");
|
||||||
|
// RV32M
|
||||||
|
INSN_MUL: decode_r_insn("mul");
|
||||||
|
INSN_MULH: decode_r_insn("mulh");
|
||||||
|
INSN_MULHSU: decode_r_insn("mulhsu");
|
||||||
|
INSN_MULHU: decode_r_insn("mulhu");
|
||||||
|
INSN_DIV: decode_r_insn("div");
|
||||||
|
INSN_DIVU: decode_r_insn("divu");
|
||||||
|
INSN_REM: decode_r_insn("rem");
|
||||||
|
INSN_REMU: decode_r_insn("remu");
|
||||||
|
// LOAD & STORE
|
||||||
|
INSN_LOAD: decode_load_insn();
|
||||||
|
INSN_STORE: decode_store_insn();
|
||||||
|
// MISC-MEM
|
||||||
|
INSN_FENCE: decode_fence();
|
||||||
|
INSN_FENCEI: decode_mnemonic("fence.i");
|
||||||
|
default: decode_mnemonic("INVALID");
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
string file_name_base = "trace_core";
|
||||||
|
$sformat(file_name, "%s.log", file_name_base);
|
||||||
|
|
||||||
|
$display("Writing execution trace to %s", file_name);
|
||||||
|
file_handle = $fopen(file_name, "w");
|
||||||
|
$fwrite(file_handle, "\t\t\tTime\t\tCycle\tPC\t\t\tInsn\t\tDecoded instruction\n");
|
||||||
|
$fflush(file_handle);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function automatic void printbuffer_dumpline();
|
||||||
|
string insn_str = $sformatf("%h", inst_i);
|
||||||
|
|
||||||
|
$fwrite(file_handle, "%15t\t%d\t\t%h\t%s\t%s", $time, cycle, pc_i, insn_str, decoded_str);
|
||||||
|
$fwrite(file_handle, "\n");
|
||||||
|
$fflush(file_handle);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// log execution
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (inst_valid_i) begin
|
||||||
|
printbuffer_dumpline();
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// cycle counter
|
||||||
|
always @(posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
cycle <= 0;
|
||||||
|
end else begin
|
||||||
|
cycle <= cycle + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module debug_rom (
|
||||||
|
input wire clk_i,
|
||||||
|
input wire req_i,
|
||||||
|
input wire [31:0] addr_i,
|
||||||
|
output wire [31:0] rdata_o
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam RomSize = 38;
|
||||||
|
|
||||||
|
wire [RomSize-1:0][31:0] mem;
|
||||||
|
|
||||||
|
assign mem = {
|
||||||
|
32'h00000000,
|
||||||
|
32'h7b200073,
|
||||||
|
32'h7b202473,
|
||||||
|
32'h7b302573,
|
||||||
|
32'h10852423,
|
||||||
|
32'hf1402473,
|
||||||
|
32'ha85ff06f,
|
||||||
|
32'h7b202473,
|
||||||
|
32'h7b302573,
|
||||||
|
32'h10052223,
|
||||||
|
32'h00100073,
|
||||||
|
32'h7b202473,
|
||||||
|
32'h7b302573,
|
||||||
|
32'h10052623,
|
||||||
|
32'h00c51513,
|
||||||
|
32'h00c55513,
|
||||||
|
32'h00000517,
|
||||||
|
32'hfd5ff06f,
|
||||||
|
32'hfa041ce3,
|
||||||
|
32'h00247413,
|
||||||
|
32'h40044403,
|
||||||
|
32'h00a40433,
|
||||||
|
32'hf1402473,
|
||||||
|
32'h02041c63,
|
||||||
|
32'h00147413,
|
||||||
|
32'h40044403,
|
||||||
|
32'h00a40433,
|
||||||
|
32'h10852023,
|
||||||
|
32'hf1402473,
|
||||||
|
32'h00c51513,
|
||||||
|
32'h00c55513,
|
||||||
|
32'h00000517,
|
||||||
|
32'h7b351073,
|
||||||
|
32'h7b241073,
|
||||||
|
32'h0ff0000f,
|
||||||
|
32'h04c0006f,
|
||||||
|
32'h07c0006f,
|
||||||
|
32'h00c0006f
|
||||||
|
};
|
||||||
|
|
||||||
|
reg [5:0] addr_q;
|
||||||
|
|
||||||
|
always @ (posedge clk_i) begin
|
||||||
|
if (req_i) begin
|
||||||
|
addr_q <= addr_i[7:2];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg[31:0] rdata;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
rdata = 32'h0;
|
||||||
|
if (addr_q < 6'd38) begin
|
||||||
|
rdata = mem[addr_q];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign rdata_o = rdata;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
`define DbgVersion013 4'h2
|
||||||
|
`define ProgBufSize 5'h8
|
||||||
|
`define DataCount 4'h1
|
||||||
|
`define HaltAddress 64'h800
|
||||||
|
`define ResumeAddress `HaltAddress + 4
|
||||||
|
`define ExceptionAddress `HaltAddress + 8
|
||||||
|
`define DataBaseAddr 12'h380
|
||||||
|
`define AbstCmdBaseAddr 12'h338
|
||||||
|
`define AbstCmdCount 12'd10
|
||||||
|
`define ProgbufBaseAddr `AbstCmdBaseAddr + (4 * `AbstCmdCount)
|
||||||
|
|
||||||
|
// dmi op
|
||||||
|
`define DMI_OP_NOP 2'b00
|
||||||
|
`define DMI_OP_READ 2'b01
|
||||||
|
`define DMI_OP_WRITE 2'b10
|
||||||
|
|
||||||
|
// DM regs addr
|
||||||
|
`define Data0 7'h04
|
||||||
|
`define Data1 7'h05
|
||||||
|
`define Data2 7'h06
|
||||||
|
`define Data3 7'h07
|
||||||
|
`define Data4 7'h08
|
||||||
|
`define DMControl 7'h10
|
||||||
|
`define DMStatus 7'h11
|
||||||
|
`define Hartinfo 7'h12
|
||||||
|
`define AbstractCS 7'h16
|
||||||
|
`define Command 7'h17
|
||||||
|
`define AbstractAuto 7'h18
|
||||||
|
`define ProgBuf0 7'h20
|
||||||
|
`define ProgBuf1 7'h21
|
||||||
|
`define ProgBuf2 7'h22
|
||||||
|
`define ProgBuf3 7'h23
|
||||||
|
`define ProgBuf4 7'h24
|
||||||
|
`define ProgBuf5 7'h25
|
||||||
|
`define ProgBuf6 7'h26
|
||||||
|
`define ProgBuf7 7'h27
|
||||||
|
`define ProgBuf8 7'h28
|
||||||
|
`define ProgBuf9 7'h29
|
||||||
|
`define ProgBuf10 7'h2A
|
||||||
|
`define ProgBuf11 7'h2B
|
||||||
|
`define ProgBuf12 7'h2C
|
||||||
|
`define ProgBuf13 7'h2D
|
||||||
|
`define ProgBuf14 7'h2E
|
||||||
|
`define ProgBuf15 7'h2F
|
||||||
|
`define SBAddress3 7'h37
|
||||||
|
`define SBCS 7'h38
|
||||||
|
`define SBAddress0 7'h39
|
||||||
|
`define SBAddress1 7'h3A
|
||||||
|
`define SBAddress2 7'h3B
|
||||||
|
`define SBData0 7'h3C
|
||||||
|
`define SBData1 7'h3D
|
||||||
|
`define SBData2 7'h3E
|
||||||
|
`define SBData3 7'h3F
|
||||||
|
`define HaltSum0 7'h40
|
||||||
|
`define HaltSum1 7'h13
|
||||||
|
|
||||||
|
// dmstatus bit index
|
||||||
|
`define Impebreak 22
|
||||||
|
`define Allhavereset 19
|
||||||
|
`define Anyhavereset 18
|
||||||
|
`define Allresumeack 17
|
||||||
|
`define Anyresumeack 16
|
||||||
|
`define Allnonexistent 15
|
||||||
|
`define Anynonexistent 14
|
||||||
|
`define Allunavail 13
|
||||||
|
`define Anyunavail 12
|
||||||
|
`define Allrunning 11
|
||||||
|
`define Anyrunning 10
|
||||||
|
`define Allhalted 9
|
||||||
|
`define Anyhalted 8
|
||||||
|
`define Authenticated 7
|
||||||
|
`define Authbusy 6
|
||||||
|
`define Hasresethaltreq 5
|
||||||
|
`define Confstrptrvalid 4
|
||||||
|
`define Version 3:0
|
||||||
|
|
||||||
|
// dmcontrol bit index
|
||||||
|
`define Haltreq 31
|
||||||
|
`define Resumereq 30
|
||||||
|
`define Hartreset 29
|
||||||
|
`define Ackhavereset 28
|
||||||
|
`define Hasel 26
|
||||||
|
`define Hartsello 25:16
|
||||||
|
`define Hartselhi 15:6
|
||||||
|
`define Setresethaltreq 3
|
||||||
|
`define Clrresethaltreq 2
|
||||||
|
`define Ndmreset 1
|
||||||
|
`define Dmactive 0
|
||||||
|
|
||||||
|
// abstractcs bit index
|
||||||
|
`define Progbufsize 28:24
|
||||||
|
`define Busy 12
|
||||||
|
`define Cmderr 10:8
|
||||||
|
`define Datacount 3:0
|
||||||
|
|
||||||
|
// abstract command access register bit index
|
||||||
|
`define Cmdtype 31:24
|
||||||
|
`define Aarsize 22:20
|
||||||
|
`define Aarpostincrement 19
|
||||||
|
`define Postexec 18
|
||||||
|
`define Transfer 17
|
||||||
|
`define Write 16
|
||||||
|
`define Regno 15:0
|
||||||
|
|
||||||
|
// sbcs bit index
|
||||||
|
`define Sbversion 31:29
|
||||||
|
`define Sbbusyerror 22
|
||||||
|
`define Sbbusy 21
|
||||||
|
`define Sbreadonaddr 20
|
||||||
|
`define Sbaccess 19:17
|
||||||
|
`define Sbautoincrement 16
|
||||||
|
`define Sbreadondata 15
|
||||||
|
`define Sberror 14:12
|
||||||
|
`define Sbasize 11:5
|
||||||
|
`define Sbaccess128 4
|
||||||
|
`define Sbaccess64 3
|
||||||
|
`define Sbaccess32 2
|
||||||
|
`define Sbaccess16 1
|
||||||
|
`define Sbaccess8 0
|
||||||
|
|
||||||
|
// abstractauto
|
||||||
|
`define AutoexecData 11:0
|
||||||
|
`define AutoexecProgbuf 31:16
|
||||||
|
|
||||||
|
`define CSR_CYCLE 12'hc00
|
||||||
|
`define CSR_CYCLEH 12'hc80
|
||||||
|
`define CSR_MTVEC 12'h305
|
||||||
|
`define CSR_MCAUSE 12'h342
|
||||||
|
`define CSR_MEPC 12'h341
|
||||||
|
`define CSR_MIE 12'h304
|
||||||
|
`define CSR_MSTATUS 12'h300
|
||||||
|
`define CSR_MSCRATCH 12'h340
|
||||||
|
`define CSR_MHARTID 12'hF14
|
||||||
|
`define CSR_DCSR 12'h7b0
|
||||||
|
`define CSR_DPC 12'h7b1
|
||||||
|
`define CSR_DSCRATCH0 12'h7b2
|
||||||
|
`define CSR_DSCRATCH1 12'h7b3
|
||||||
|
|
|
@ -0,0 +1,533 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "jtag_def.sv"
|
||||||
|
|
||||||
|
module jtag_dm #(
|
||||||
|
parameter DMI_ADDR_BITS = 7,
|
||||||
|
parameter DMI_DATA_BITS = 32,
|
||||||
|
parameter DMI_OP_BITS = 2,
|
||||||
|
parameter DMI_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
|
||||||
|
parameter DMI_RESP_BITS = DMI_REQ_BITS
|
||||||
|
)(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
// from DMI
|
||||||
|
input wire [DMI_REQ_BITS-1:0] dmi_data_i,
|
||||||
|
input wire dmi_valid_i,
|
||||||
|
output wire dm_ready_o,
|
||||||
|
|
||||||
|
// to DMI
|
||||||
|
output wire [DMI_RESP_BITS-1:0] dm_data_o,
|
||||||
|
output wire dm_valid_o,
|
||||||
|
input wire dmi_ready_i,
|
||||||
|
|
||||||
|
output wire debug_req_o,
|
||||||
|
output wire ndmreset_o,
|
||||||
|
output wire halted_o,
|
||||||
|
|
||||||
|
// jtag access mem devices(DM as master)
|
||||||
|
output wire master_req_o,
|
||||||
|
input wire master_gnt_i,
|
||||||
|
input wire master_rvalid_i,
|
||||||
|
output wire master_we_o,
|
||||||
|
output wire [3:0] master_be_o,
|
||||||
|
output wire [31:0] master_addr_o,
|
||||||
|
output wire [31:0] master_wdata_o,
|
||||||
|
input wire [31:0] master_rdata_i,
|
||||||
|
input wire master_err_i,
|
||||||
|
|
||||||
|
// core fetch instr or mem(DM as slave)
|
||||||
|
input wire slave_req_i,
|
||||||
|
input wire slave_we_i,
|
||||||
|
input wire [31:0] slave_addr_i,
|
||||||
|
input wire [3:0] slave_be_i,
|
||||||
|
input wire [31:0] slave_wdata_i,
|
||||||
|
output wire slave_gnt_o,
|
||||||
|
output wire slave_rvalid_o,
|
||||||
|
output wire [31:0] slave_rdata_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam HARTINFO = {8'h0, 4'h2, 3'b0, 1'b1, `DataCount, `DataBaseAddr};
|
||||||
|
|
||||||
|
localparam CmdErrorNone = 3'h0;
|
||||||
|
localparam CmdErrorBusy = 3'h1;
|
||||||
|
|
||||||
|
wire halted;
|
||||||
|
wire resumeack;
|
||||||
|
wire sbbusy;
|
||||||
|
wire[2:0] sberror;
|
||||||
|
wire[DMI_OP_BITS-1:0] dm_op;
|
||||||
|
wire[DMI_ADDR_BITS-1:0] dm_op_addr;
|
||||||
|
wire[DMI_DATA_BITS-1:0] dm_op_data;
|
||||||
|
|
||||||
|
reg havereset_d, havereset_q;
|
||||||
|
reg clear_resumeack;
|
||||||
|
reg sbaddress_write_valid;
|
||||||
|
reg sbdata_write_valid;
|
||||||
|
reg sbdata_read_valid;
|
||||||
|
reg[31:0] sbcs;
|
||||||
|
reg[31:0] a_abstractcs;
|
||||||
|
reg[31:0] dm_resp_data_d, dm_resp_data_q;
|
||||||
|
reg cmd_valid_d, cmd_valid_q;
|
||||||
|
reg[15:0] abstractautoprogbuf;
|
||||||
|
reg[3:0] progbuf_index;
|
||||||
|
wire[31:0] sba_sbaddress;
|
||||||
|
wire[31:0] dm_sbaddress;
|
||||||
|
wire resumereq;
|
||||||
|
wire cmdbusy;
|
||||||
|
wire sbdata_valid;
|
||||||
|
wire[31:0] sbdata;
|
||||||
|
wire[19:0] hartsel;
|
||||||
|
wire data_valid;
|
||||||
|
wire[31:0] data0;
|
||||||
|
wire cmderror_valid;
|
||||||
|
wire[2:0] cmderror;
|
||||||
|
|
||||||
|
// DM regs
|
||||||
|
reg[31:0] dmstatus;
|
||||||
|
reg[31:0] dmcontrol_d, dmcontrol_q;
|
||||||
|
reg[31:0] abstractcs;
|
||||||
|
reg[31:0] abstractauto_d, abstractauto_q;
|
||||||
|
reg[31:0] sbcs_d, sbcs_q;
|
||||||
|
reg[31:0] sbdata0_d, sbdata0_q;
|
||||||
|
reg[31:0] sbaddress0_d, sbaddress0_q;
|
||||||
|
reg[31:0] command_d, command_q;
|
||||||
|
reg[31:0] data0_d, data0_q;
|
||||||
|
reg[2:0] cmderr_d, cmderr_q;
|
||||||
|
reg[`ProgBufSize-1:0][31:0] progbuf_d, progbuf_q;
|
||||||
|
|
||||||
|
assign dm_sbaddress = sbaddress0_q;
|
||||||
|
|
||||||
|
assign hartsel = {dmcontrol_q[`Hartselhi], dmcontrol_q[`Hartsello]};
|
||||||
|
|
||||||
|
assign dm_op = dmi_data_i[DMI_OP_BITS-1:0];
|
||||||
|
assign dm_op_addr = dmi_data_i[DMI_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
|
||||||
|
assign dm_op_data = dmi_data_i[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
|
||||||
|
|
||||||
|
|
||||||
|
localparam S_REQ = 2'b01;
|
||||||
|
localparam S_RESP = 2'b10;
|
||||||
|
|
||||||
|
reg[2:0] req_state_d, req_state_q;
|
||||||
|
reg dm_valid_d;
|
||||||
|
|
||||||
|
// response FSM
|
||||||
|
always @ (*) begin
|
||||||
|
req_state_d = req_state_q;
|
||||||
|
dm_valid_d = 1'b0;
|
||||||
|
|
||||||
|
case (req_state_q)
|
||||||
|
S_REQ: begin
|
||||||
|
if (dmi_valid_i & dm_ready_o) begin
|
||||||
|
req_state_d = S_RESP;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_RESP: begin
|
||||||
|
if (dmi_ready_i) begin
|
||||||
|
dm_valid_d = 1'b1;
|
||||||
|
req_state_d = S_REQ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default:;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
req_state_q <= S_REQ;
|
||||||
|
end else begin
|
||||||
|
req_state_q <= req_state_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// we always ready to receive dmi request
|
||||||
|
assign dm_ready_o = ~sbbusy;
|
||||||
|
assign dm_valid_o = dm_valid_d;
|
||||||
|
assign dm_data_o = {{DMI_ADDR_BITS{1'b0}}, dm_resp_data_q, 2'b00}; // response successfully
|
||||||
|
|
||||||
|
|
||||||
|
// DMI read or write operation
|
||||||
|
always @ (*) begin
|
||||||
|
// dmstatus
|
||||||
|
dmstatus = 32'h0;
|
||||||
|
dmstatus[`Version] = `DbgVersion013;
|
||||||
|
dmstatus[`Authenticated] = 1'b1;
|
||||||
|
dmstatus[`Allresumeack] = resumeack;
|
||||||
|
dmstatus[`Anyresumeack] = resumeack;
|
||||||
|
dmstatus[`Allhavereset] = havereset_q;
|
||||||
|
dmstatus[`Anyhavereset] = havereset_q;
|
||||||
|
dmstatus[`Allhalted] = halted;
|
||||||
|
dmstatus[`Anyhalted] = halted;
|
||||||
|
dmstatus[`Allrunning] = ~halted;
|
||||||
|
dmstatus[`Anyrunning] = ~halted;
|
||||||
|
dmstatus[`Allnonexistent] = hartsel > 20'h0;
|
||||||
|
dmstatus[`Anynonexistent] = hartsel > 20'h0;
|
||||||
|
|
||||||
|
// abstractcs
|
||||||
|
cmderr_d = cmderr_q;
|
||||||
|
abstractcs = 32'h0;
|
||||||
|
abstractcs[`Datacount] = `DataCount;
|
||||||
|
abstractcs[`Progbufsize] = `ProgBufSize;
|
||||||
|
abstractcs[`Busy] = cmdbusy;
|
||||||
|
abstractcs[`Cmderr] = cmderr_q;
|
||||||
|
a_abstractcs = 32'h0;
|
||||||
|
abstractauto_d = abstractauto_q;
|
||||||
|
|
||||||
|
havereset_d = havereset_q;
|
||||||
|
sbaddress0_d = sba_sbaddress;
|
||||||
|
dmcontrol_d = dmcontrol_q;
|
||||||
|
clear_resumeack = 1'b0;
|
||||||
|
sbaddress_write_valid = 1'b0;
|
||||||
|
sbdata_write_valid = 1'b0;
|
||||||
|
sbdata_read_valid = 1'b0;
|
||||||
|
sbcs = 32'h0;
|
||||||
|
command_d = command_q;
|
||||||
|
cmd_valid_d = 1'b0;
|
||||||
|
|
||||||
|
progbuf_index = 4'h0;
|
||||||
|
progbuf_d = progbuf_q;
|
||||||
|
abstractautoprogbuf = abstractauto_q[`AutoexecProgbuf];
|
||||||
|
|
||||||
|
data0_d = data0_q;
|
||||||
|
sbcs_d = sbcs_q;
|
||||||
|
sbdata0_d = sbdata0_q;
|
||||||
|
dm_resp_data_d = dm_resp_data_q;
|
||||||
|
|
||||||
|
if (dmi_valid_i & dm_ready_o) begin
|
||||||
|
// read
|
||||||
|
if (dm_op == `DMI_OP_READ) begin
|
||||||
|
case (dm_op_addr)
|
||||||
|
`DMStatus :dm_resp_data_d = dmstatus;
|
||||||
|
`DMControl :dm_resp_data_d = dmcontrol_q;
|
||||||
|
`Hartinfo :dm_resp_data_d = HARTINFO;
|
||||||
|
`SBCS :dm_resp_data_d = sbcs_q;
|
||||||
|
`AbstractCS:dm_resp_data_d = abstractcs;
|
||||||
|
`AbstractAuto: dm_resp_data_d = abstractauto_q;
|
||||||
|
`Command :dm_resp_data_d = 32'h0;
|
||||||
|
`SBAddress0:dm_resp_data_d = sbaddress0_q;
|
||||||
|
`SBData0 : begin
|
||||||
|
if (sbbusy || sbcs_q[`Sbbusyerror]) begin
|
||||||
|
sbcs_d[`Sbbusyerror] = 1'b1;
|
||||||
|
end else begin
|
||||||
|
sbdata_read_valid = (sbcs_q[`Sberror] == 3'b0);
|
||||||
|
dm_resp_data_d = sbdata0_q;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
`Data0: begin
|
||||||
|
dm_resp_data_d = data0_q;
|
||||||
|
if (!cmdbusy) begin
|
||||||
|
cmd_valid_d = abstractauto_q[0];
|
||||||
|
end else if (cmderr_q == CmdErrorNone) begin
|
||||||
|
cmderr_d = CmdErrorBusy;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
`ProgBuf0, `ProgBuf1, `ProgBuf2, `ProgBuf3,
|
||||||
|
`ProgBuf4, `ProgBuf5, `ProgBuf6, `ProgBuf7,
|
||||||
|
`ProgBuf8, `ProgBuf9: begin
|
||||||
|
progbuf_index = dm_op_addr[3:0];
|
||||||
|
dm_resp_data_d = progbuf_q[progbuf_index];
|
||||||
|
if (!cmdbusy) begin
|
||||||
|
cmd_valid_d = abstractautoprogbuf[progbuf_index];
|
||||||
|
end else if (cmderr_q == CmdErrorNone) begin
|
||||||
|
cmderr_d = CmdErrorBusy;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
`HaltSum0: dm_resp_data_d = {31'h0, halted};
|
||||||
|
`HaltSum1: dm_resp_data_d = {31'h0, halted};
|
||||||
|
default: dm_resp_data_d = 32'h0;
|
||||||
|
endcase
|
||||||
|
// write
|
||||||
|
end else if (dm_op == `DMI_OP_WRITE) begin
|
||||||
|
case (dm_op_addr)
|
||||||
|
`DMControl: begin
|
||||||
|
dmcontrol_d = dm_op_data;
|
||||||
|
if (dmcontrol_d[`Ackhavereset]) begin
|
||||||
|
havereset_d = 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
`Data0: begin
|
||||||
|
if (!cmdbusy) begin
|
||||||
|
data0_d = dm_op_data;
|
||||||
|
cmd_valid_d = abstractauto_q[0];
|
||||||
|
end else if (cmderr_q == CmdErrorNone) begin
|
||||||
|
cmderr_d = CmdErrorBusy;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
`SBCS: begin
|
||||||
|
if (sbbusy) begin
|
||||||
|
sbcs_d[`Sbbusyerror] = 1'b1;
|
||||||
|
end else begin
|
||||||
|
sbcs = dm_op_data;
|
||||||
|
sbcs_d = dm_op_data;
|
||||||
|
// write 1 to clear
|
||||||
|
sbcs_d[`Sbbusyerror] = sbcs_q[`Sbbusyerror] & (~sbcs[`Sbbusyerror]);
|
||||||
|
sbcs_d[`Sberror] = sbcs_q[`Sberror] & (~sbcs[`Sberror]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
`SBAddress0: begin
|
||||||
|
if (sbbusy | sbcs_q[`Sbbusyerror]) begin
|
||||||
|
sbcs_d[`Sbbusyerror] = 1'b1;
|
||||||
|
end else begin
|
||||||
|
sbaddress0_d = dm_op_data;
|
||||||
|
sbaddress_write_valid = (sbcs_q[`Sberror] == 3'b0);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
`SBData0: begin
|
||||||
|
if (sbbusy | sbcs_q[`Sbbusyerror]) begin
|
||||||
|
sbcs_d[`Sbbusyerror] = 1'b1;
|
||||||
|
end else begin
|
||||||
|
sbdata0_d = dm_op_data;
|
||||||
|
sbdata_write_valid = (sbcs_q[`Sberror] == 3'b0);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
`Command: begin
|
||||||
|
if (!cmdbusy) begin
|
||||||
|
cmd_valid_d = 1'b1;
|
||||||
|
command_d = dm_op_data;
|
||||||
|
end else if (cmderr_q == CmdErrorNone) begin
|
||||||
|
cmderr_d = CmdErrorBusy;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
`AbstractCS: begin
|
||||||
|
a_abstractcs = dm_op_data;
|
||||||
|
if (!cmdbusy) begin
|
||||||
|
cmderr_d = (~a_abstractcs[`Cmderr]) & cmderr_q;
|
||||||
|
end else if (cmderr_q == CmdErrorNone) begin
|
||||||
|
cmderr_d = CmdErrorBusy;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
`AbstractAuto: begin
|
||||||
|
if (!cmdbusy) begin
|
||||||
|
abstractauto_d = 32'h0;
|
||||||
|
abstractauto_d[`AutoexecData] = {11'h0, dm_op_data[0]};
|
||||||
|
abstractauto_d[`AutoexecProgbuf] = dm_op_data[`ProgBufSize-1+16:16];
|
||||||
|
end else if (cmderr_q == CmdErrorNone) begin
|
||||||
|
cmderr_d = CmdErrorBusy;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
`ProgBuf0, `ProgBuf1, `ProgBuf2, `ProgBuf3,
|
||||||
|
`ProgBuf4, `ProgBuf5, `ProgBuf6, `ProgBuf7,
|
||||||
|
`ProgBuf8, `ProgBuf9: begin
|
||||||
|
if (!cmdbusy) begin
|
||||||
|
progbuf_index = dm_op_addr[3:0];
|
||||||
|
progbuf_d[progbuf_index] = dm_op_data;
|
||||||
|
cmd_valid_d = abstractautoprogbuf[progbuf_index];
|
||||||
|
end else if (cmderr_q == CmdErrorNone) begin
|
||||||
|
cmderr_d = CmdErrorBusy;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default:;
|
||||||
|
endcase
|
||||||
|
// nop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// dmcontrol
|
||||||
|
dmcontrol_d[`Hasel] = 1'b0;
|
||||||
|
dmcontrol_d[`Hartreset] = 1'b0;
|
||||||
|
dmcontrol_d[`Setresethaltreq] = 1'b0;
|
||||||
|
dmcontrol_d[`Clrresethaltreq] = 1'b0;
|
||||||
|
dmcontrol_d[`Ackhavereset] = 1'b0;
|
||||||
|
// 收到resume请求后清resume应答
|
||||||
|
if (!dmcontrol_q[`Resumereq] && dmcontrol_d[`Resumereq]) begin
|
||||||
|
clear_resumeack = 1'b1;
|
||||||
|
end
|
||||||
|
// 发出resume后并且收到应答
|
||||||
|
if (dmcontrol_q[`Resumereq] && resumeack) begin
|
||||||
|
// 清resume请求位
|
||||||
|
dmcontrol_d[`Resumereq] = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// sbcs
|
||||||
|
sbcs_d[`Sbversion] = 3'd1;
|
||||||
|
sbcs_d[`Sbbusy] = sbbusy;
|
||||||
|
sbcs_d[`Sberror] = sberror;
|
||||||
|
sbcs_d[`Sbasize] = 7'd32;
|
||||||
|
sbcs_d[`Sbaccess128] = 1'b0;
|
||||||
|
sbcs_d[`Sbaccess64] = 1'b0;
|
||||||
|
sbcs_d[`Sbaccess32] = 1'b1;
|
||||||
|
sbcs_d[`Sbaccess16] = 1'b0;
|
||||||
|
sbcs_d[`Sbaccess8] = 1'b0;
|
||||||
|
sbcs_d[`Sbaccess] = 3'd2;
|
||||||
|
|
||||||
|
if (sbdata_valid) begin
|
||||||
|
sbdata0_d = sbdata;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (cmderror_valid) begin
|
||||||
|
cmderr_d = cmderror;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (data_valid) begin
|
||||||
|
data0_d = data0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// set the havereset flag when we did a ndmreset
|
||||||
|
if (ndmreset_o) begin
|
||||||
|
havereset_d = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign debug_req_o = dmcontrol_q[`Haltreq];
|
||||||
|
assign ndmreset_o = dmcontrol_q[`Ndmreset];
|
||||||
|
assign resumereq = dmcontrol_q[`Resumereq];
|
||||||
|
assign halted_o = halted;
|
||||||
|
|
||||||
|
genvar i;
|
||||||
|
|
||||||
|
generate
|
||||||
|
for (i = 0; i < `ProgBufSize; i = i + 1) begin: gen_progbuf
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
progbuf_q[i] <= 32'h0;
|
||||||
|
end else begin
|
||||||
|
if (!dmcontrol_q[`Dmactive]) begin
|
||||||
|
progbuf_q[i] <= 32'h0;
|
||||||
|
end else begin
|
||||||
|
progbuf_q[i] <= progbuf_d[i];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
dmcontrol_q <= 32'h0;
|
||||||
|
havereset_q <= 1'b1;
|
||||||
|
data0_q <= 32'h0;
|
||||||
|
sbcs_q <= 32'h0;
|
||||||
|
sbaddress0_q <= 32'h0;
|
||||||
|
sbdata0_q <= 32'h0;
|
||||||
|
dm_resp_data_q <= 32'h0;
|
||||||
|
cmderr_q <= 3'h0;
|
||||||
|
command_q <= 32'h0;
|
||||||
|
abstractauto_q <= 32'h0;
|
||||||
|
cmd_valid_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
if (!dmcontrol_q[`Dmactive]) begin
|
||||||
|
dmcontrol_q[`Haltreq] <= 1'b0;
|
||||||
|
dmcontrol_q[`Resumereq] <= 1'b0;
|
||||||
|
dmcontrol_q[`Hartreset] <= 1'b0;
|
||||||
|
dmcontrol_q[`Ackhavereset] <= 1'b0;
|
||||||
|
dmcontrol_q[`Hasel] <= 1'b0;
|
||||||
|
dmcontrol_q[`Hartsello] <= 10'b0;
|
||||||
|
dmcontrol_q[`Hartselhi] <= 10'b0;
|
||||||
|
dmcontrol_q[`Setresethaltreq] <= 1'b0;
|
||||||
|
dmcontrol_q[`Clrresethaltreq] <= 1'b0;
|
||||||
|
dmcontrol_q[`Ndmreset] <= 1'b0;
|
||||||
|
dmcontrol_q[`Dmactive] <= dmcontrol_d[`Dmactive];
|
||||||
|
data0_q <= 32'h0;
|
||||||
|
sbcs_q <= 32'h0;
|
||||||
|
sbaddress0_q <= 32'h0;
|
||||||
|
sbdata0_q <= 32'h0;
|
||||||
|
dm_resp_data_q <= 32'h0;
|
||||||
|
cmderr_q <= 3'h0;
|
||||||
|
command_q <= 32'h0;
|
||||||
|
abstractauto_q <= 32'h0;
|
||||||
|
cmd_valid_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
dmcontrol_q <= dmcontrol_d;
|
||||||
|
data0_q <= data0_d;
|
||||||
|
sbcs_q <= sbcs_d;
|
||||||
|
sbaddress0_q <= sbaddress0_d;
|
||||||
|
sbdata0_q <= sbdata0_d;
|
||||||
|
dm_resp_data_q <= dm_resp_data_d;
|
||||||
|
cmderr_q <= cmderr_d;
|
||||||
|
command_q <= command_d;
|
||||||
|
abstractauto_q <= abstractauto_d;
|
||||||
|
cmd_valid_q <= cmd_valid_d;
|
||||||
|
end
|
||||||
|
havereset_q <= havereset_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
jtag_mem u_jtag_mem (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
|
||||||
|
.halted_o(halted),
|
||||||
|
.resumeack_o(resumeack),
|
||||||
|
.clear_resumeack_i(clear_resumeack),
|
||||||
|
.resumereq_i(resumereq),
|
||||||
|
.haltreq_i(debug_req_o),
|
||||||
|
.ndmreset_i(ndmreset_o),
|
||||||
|
|
||||||
|
.progbuf_i(progbuf_q),
|
||||||
|
.data_i(data0_q),
|
||||||
|
.data_o(data0),
|
||||||
|
.data_valid_o(data_valid),
|
||||||
|
.cmd_valid_i(cmd_valid_q),
|
||||||
|
.cmd_i(command_q),
|
||||||
|
.cmderror_valid_o(cmderror_valid),
|
||||||
|
.cmderror_o(cmderror),
|
||||||
|
.cmdbusy_o(cmdbusy),
|
||||||
|
|
||||||
|
.req_i(slave_req_i),
|
||||||
|
.we_i(slave_we_i),
|
||||||
|
.addr_i(slave_addr_i),
|
||||||
|
.be_i(slave_be_i),
|
||||||
|
.wdata_i(slave_wdata_i),
|
||||||
|
.gnt_o(slave_gnt_o),
|
||||||
|
.rvalid_o(slave_rvalid_o),
|
||||||
|
.rdata_o(slave_rdata_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
jtag_sba u_jtag_sba (
|
||||||
|
.clk(clk),
|
||||||
|
.rst_n(rst_n),
|
||||||
|
.sbaddress_i(sbaddress0_q),
|
||||||
|
.sbaddress_write_valid_i(sbaddress_write_valid),
|
||||||
|
.sbreadonaddr_i(sbcs_q[`Sbreadonaddr]),
|
||||||
|
.sbaddress_o(sba_sbaddress),
|
||||||
|
.sbautoincrement_i(sbcs_q[`Sbautoincrement]),
|
||||||
|
.sbaccess_i(sbcs_q[`Sbaccess]),
|
||||||
|
.sbreadondata_i(sbcs_q[`Sbreadondata]),
|
||||||
|
.sbdata_i(sbdata0_q),
|
||||||
|
.sbdata_read_valid_i(sbdata_read_valid),
|
||||||
|
.sbdata_write_valid_i(sbdata_write_valid),
|
||||||
|
.sbdata_o(sbdata),
|
||||||
|
.sbdata_valid_o(sbdata_valid),
|
||||||
|
.sbbusy_o(sbbusy),
|
||||||
|
.sberror_o(sberror),
|
||||||
|
|
||||||
|
.master_req_o(master_req_o),
|
||||||
|
.master_gnt_i(master_gnt_i),
|
||||||
|
.master_rvalid_i(master_rvalid_i),
|
||||||
|
.master_we_o(master_we_o),
|
||||||
|
.master_be_o(master_be_o),
|
||||||
|
.master_addr_o(master_addr_o),
|
||||||
|
.master_wdata_o(master_wdata_o),
|
||||||
|
.master_rdata_i(master_rdata_i),
|
||||||
|
.master_err_i(master_err_i)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,342 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`define DM_RESP_VALID 1'b1
|
|
||||||
`define DM_RESP_INVALID 1'b0
|
|
||||||
`define DTM_REQ_VALID 1'b1
|
|
||||||
`define DTM_REQ_INVALID 1'b0
|
|
||||||
|
|
||||||
`define DTM_OP_NOP 2'b00
|
|
||||||
`define DTM_OP_READ 2'b01
|
|
||||||
`define DTM_OP_WRITE 2'b10
|
|
||||||
|
|
||||||
|
|
||||||
module jtag_dm #(
|
|
||||||
parameter DMI_ADDR_BITS = 6,
|
|
||||||
parameter DMI_DATA_BITS = 32,
|
|
||||||
parameter DMI_OP_BITS = 2)(
|
|
||||||
|
|
||||||
clk,
|
|
||||||
rst_n,
|
|
||||||
|
|
||||||
// rx
|
|
||||||
dm_ack_o,
|
|
||||||
dtm_req_valid_i,
|
|
||||||
dtm_req_data_i,
|
|
||||||
|
|
||||||
// tx
|
|
||||||
dtm_ack_i,
|
|
||||||
dm_resp_data_o,
|
|
||||||
dm_resp_valid_o,
|
|
||||||
|
|
||||||
dm_reg_we_o,
|
|
||||||
dm_reg_addr_o,
|
|
||||||
dm_reg_wdata_o,
|
|
||||||
dm_reg_rdata_i,
|
|
||||||
dm_mem_we_o,
|
|
||||||
dm_mem_addr_o,
|
|
||||||
dm_mem_wdata_o,
|
|
||||||
dm_mem_rdata_i,
|
|
||||||
|
|
||||||
dm_op_req_o,
|
|
||||||
dm_halt_req_o,
|
|
||||||
dm_reset_req_o
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
|
||||||
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
|
||||||
parameter SHIFT_REG_BITS = DTM_REQ_BITS;
|
|
||||||
|
|
||||||
// 输入输出信号
|
|
||||||
input wire clk;
|
|
||||||
input wire rst_n;
|
|
||||||
output wire dm_ack_o;
|
|
||||||
input wire dtm_req_valid_i;
|
|
||||||
input wire[DTM_REQ_BITS-1:0] dtm_req_data_i;
|
|
||||||
input wire dtm_ack_i;
|
|
||||||
output wire[DM_RESP_BITS-1:0] dm_resp_data_o;
|
|
||||||
output wire dm_resp_valid_o;
|
|
||||||
output wire dm_reg_we_o;
|
|
||||||
output wire[4:0] dm_reg_addr_o;
|
|
||||||
output wire[31:0] dm_reg_wdata_o;
|
|
||||||
input wire[31:0] dm_reg_rdata_i;
|
|
||||||
output wire dm_mem_we_o;
|
|
||||||
output wire[31:0] dm_mem_addr_o;
|
|
||||||
output wire[31:0] dm_mem_wdata_o;
|
|
||||||
input wire[31:0] dm_mem_rdata_i;
|
|
||||||
output wire dm_op_req_o;
|
|
||||||
output wire dm_halt_req_o;
|
|
||||||
output wire dm_reset_req_o;
|
|
||||||
|
|
||||||
// DM模块寄存器
|
|
||||||
reg[31:0] dcsr;
|
|
||||||
reg[31:0] dmstatus;
|
|
||||||
reg[31:0] dmcontrol;
|
|
||||||
reg[31:0] hartinfo;
|
|
||||||
reg[31:0] abstractcs;
|
|
||||||
reg[31:0] data0;
|
|
||||||
reg[31:0] sbcs;
|
|
||||||
reg[31:0] sbaddress0;
|
|
||||||
reg[31:0] sbdata0;
|
|
||||||
reg[31:0] command;
|
|
||||||
|
|
||||||
// DM模块寄存器地址
|
|
||||||
localparam DCSR = 16'h7b0;
|
|
||||||
localparam DMSTATUS = 6'h11;
|
|
||||||
localparam DMCONTROL = 6'h10;
|
|
||||||
localparam HARTINFO = 6'h12;
|
|
||||||
localparam ABSTRACTCS = 6'h16;
|
|
||||||
localparam DATA0 = 6'h04;
|
|
||||||
localparam SBCS = 6'h38;
|
|
||||||
localparam SBADDRESS0 = 6'h39;
|
|
||||||
localparam SBDATA0 = 6'h3C;
|
|
||||||
localparam COMMAND = 6'h17;
|
|
||||||
localparam DPC = 16'h7b1;
|
|
||||||
|
|
||||||
localparam OP_SUCC = 2'b00;
|
|
||||||
|
|
||||||
reg[31:0] read_data;
|
|
||||||
reg dm_reg_we;
|
|
||||||
reg[4:0] dm_reg_addr;
|
|
||||||
reg[31:0] dm_reg_wdata;
|
|
||||||
reg dm_mem_we;
|
|
||||||
reg[31:0] dm_mem_addr;
|
|
||||||
reg[31:0] dm_mem_wdata;
|
|
||||||
reg dm_halt_req;
|
|
||||||
reg dm_reset_req;
|
|
||||||
reg need_resp;
|
|
||||||
reg is_read_reg;
|
|
||||||
wire rx_valid;
|
|
||||||
wire[DTM_REQ_BITS-1:0] rx_data;
|
|
||||||
|
|
||||||
wire[31:0] sbaddress0_next = sbaddress0 + 4;
|
|
||||||
wire[DM_RESP_BITS-1:0] dm_resp_data;
|
|
||||||
|
|
||||||
wire[DMI_OP_BITS-1:0] op = rx_data[DMI_OP_BITS-1:0];
|
|
||||||
wire[DMI_DATA_BITS-1:0] data = rx_data[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
|
|
||||||
wire[DMI_ADDR_BITS-1:0] address = rx_data[DTM_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
|
|
||||||
|
|
||||||
wire read_dmstatus = (op == `DTM_OP_READ) & (address == DMSTATUS);
|
|
||||||
|
|
||||||
always @ (posedge clk or negedge rst_n) begin
|
|
||||||
if (!rst_n) begin
|
|
||||||
dm_mem_we <= 1'b0;
|
|
||||||
dm_reg_we <= 1'b0;
|
|
||||||
dm_halt_req <= 1'b0;
|
|
||||||
dm_reset_req <= 1'b0;
|
|
||||||
dm_mem_addr <= 32'h0;
|
|
||||||
dm_reg_addr <= 5'h0;
|
|
||||||
sbaddress0 <= 32'h0;
|
|
||||||
dcsr <= 32'h0;
|
|
||||||
hartinfo <= 32'h0;
|
|
||||||
sbcs <= 32'h20040404;
|
|
||||||
dmcontrol <= 32'h0;
|
|
||||||
abstractcs <= 32'h1000003;
|
|
||||||
data0 <= 32'h0;
|
|
||||||
sbdata0 <= 32'h0;
|
|
||||||
command <= 32'h0;
|
|
||||||
dm_reg_wdata <= 32'h0;
|
|
||||||
dm_mem_wdata <= 32'h0;
|
|
||||||
dmstatus <= 32'h430c82;
|
|
||||||
is_read_reg <= 1'b0;
|
|
||||||
read_data <= 32'h0;
|
|
||||||
need_resp <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
if (rx_valid) begin
|
|
||||||
need_resp <= 1'b1;
|
|
||||||
case (op)
|
|
||||||
`DTM_OP_READ: begin
|
|
||||||
case (address)
|
|
||||||
DMSTATUS: begin
|
|
||||||
read_data <= dmstatus;
|
|
||||||
end
|
|
||||||
DMCONTROL: begin
|
|
||||||
read_data <= dmcontrol;
|
|
||||||
end
|
|
||||||
HARTINFO: begin
|
|
||||||
read_data <= hartinfo;
|
|
||||||
end
|
|
||||||
SBCS: begin
|
|
||||||
read_data <= sbcs;
|
|
||||||
end
|
|
||||||
ABSTRACTCS: begin
|
|
||||||
read_data <= abstractcs;
|
|
||||||
end
|
|
||||||
DATA0: begin
|
|
||||||
if (is_read_reg == 1'b1) begin
|
|
||||||
read_data <= dm_reg_rdata_i;
|
|
||||||
end else begin
|
|
||||||
read_data <= data0;
|
|
||||||
end
|
|
||||||
is_read_reg <= 1'b0;
|
|
||||||
end
|
|
||||||
SBDATA0: begin
|
|
||||||
read_data <= dm_mem_rdata_i;
|
|
||||||
if (sbcs[16] == 1'b1) begin
|
|
||||||
sbaddress0 <= sbaddress0_next;
|
|
||||||
end
|
|
||||||
if (sbcs[15] == 1'b1) begin
|
|
||||||
dm_mem_addr <= sbaddress0_next;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
read_data <= {(DMI_DATA_BITS){1'b0}};
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
`DTM_OP_WRITE: begin
|
|
||||||
read_data <= {(DMI_DATA_BITS){1'b0}};
|
|
||||||
case (address)
|
|
||||||
DMCONTROL: begin
|
|
||||||
// reset DM module
|
|
||||||
if (data[0] == 1'b0) begin
|
|
||||||
dcsr <= 32'hc0;
|
|
||||||
dmstatus <= 32'h430c82; // not halted, all running
|
|
||||||
hartinfo <= 32'h0;
|
|
||||||
sbcs <= 32'h20040404;
|
|
||||||
abstractcs <= 32'h1000003;
|
|
||||||
dmcontrol <= data;
|
|
||||||
dm_halt_req <= 1'b0;
|
|
||||||
dm_reset_req <= 1'b0;
|
|
||||||
// DM is active
|
|
||||||
end else begin
|
|
||||||
// we have only one hart
|
|
||||||
dmcontrol <= (data & ~(32'h3fffc0)) | 32'h10000;
|
|
||||||
// halt
|
|
||||||
if (data[31] == 1'b1) begin
|
|
||||||
dm_halt_req <= 1'b1;
|
|
||||||
// clear ALLRUNNING ANYRUNNING and set ALLHALTED
|
|
||||||
dmstatus <= {dmstatus[31:12], 4'h3, dmstatus[7:0]};
|
|
||||||
// resume
|
|
||||||
end else if (dm_halt_req == 1'b1 && data[30] == 1'b1) begin
|
|
||||||
dm_halt_req <= 1'b0;
|
|
||||||
// set ALLRUNNING ANYRUNNING and clear ALLHALTED
|
|
||||||
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
COMMAND: begin
|
|
||||||
// access reg
|
|
||||||
if (data[31:24] == 8'h0) begin
|
|
||||||
if (data[22:20] > 3'h2) begin
|
|
||||||
abstractcs <= abstractcs | (1'b1 << 9);
|
|
||||||
end else begin
|
|
||||||
abstractcs <= abstractcs & (~(3'h7 << 8));
|
|
||||||
// read or write
|
|
||||||
if (data[18] == 1'b0) begin
|
|
||||||
dm_reg_addr <= data[15:0] - 16'h1000;
|
|
||||||
// read
|
|
||||||
if (data[16] == 1'b0) begin
|
|
||||||
if (data[15:0] == DCSR) begin
|
|
||||||
data0 <= dcsr;
|
|
||||||
end else if (data[15:0] < 16'h1020) begin
|
|
||||||
is_read_reg <= 1'b1;
|
|
||||||
end
|
|
||||||
// write
|
|
||||||
end else begin
|
|
||||||
// when write dpc, we reset cpu here
|
|
||||||
if (data[15:0] == DPC) begin
|
|
||||||
dm_reset_req <= 1'b1;
|
|
||||||
dm_halt_req <= 1'b0;
|
|
||||||
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
|
|
||||||
end else if (data[15:0] < 16'h1020) begin
|
|
||||||
dm_reg_we <= 1'b1;
|
|
||||||
dm_reg_wdata <= data0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
DATA0: begin
|
|
||||||
data0 <= data;
|
|
||||||
end
|
|
||||||
SBCS: begin
|
|
||||||
sbcs <= data;
|
|
||||||
end
|
|
||||||
SBADDRESS0: begin
|
|
||||||
sbaddress0 <= data;
|
|
||||||
if (sbcs[20] == 1'b1) begin
|
|
||||||
dm_mem_addr <= data;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
SBDATA0: begin
|
|
||||||
sbdata0 <= data;
|
|
||||||
dm_mem_addr <= sbaddress0;
|
|
||||||
dm_mem_wdata <= data;
|
|
||||||
dm_mem_we <= 1'b1;
|
|
||||||
if (sbcs[16] == 1'b1) begin
|
|
||||||
sbaddress0 <= sbaddress0_next;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
`DTM_OP_NOP: begin
|
|
||||||
read_data <= {(DMI_DATA_BITS){1'b0}};
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end else begin
|
|
||||||
need_resp <= 1'b0;
|
|
||||||
dm_mem_we <= 1'b0;
|
|
||||||
dm_reg_we <= 1'b0;
|
|
||||||
dm_reset_req <= 1'b0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assign dm_reg_we_o = dm_reg_we;
|
|
||||||
assign dm_reg_addr_o = dm_reg_addr;
|
|
||||||
assign dm_reg_wdata_o = dm_reg_wdata;
|
|
||||||
assign dm_mem_we_o = dm_mem_we;
|
|
||||||
assign dm_mem_addr_o = dm_mem_addr;
|
|
||||||
assign dm_mem_wdata_o = dm_mem_wdata;
|
|
||||||
|
|
||||||
assign dm_op_req_o = (rx_valid & (~read_dmstatus)) | need_resp;
|
|
||||||
assign dm_halt_req_o = dm_halt_req;
|
|
||||||
assign dm_reset_req_o = dm_reset_req;
|
|
||||||
|
|
||||||
assign dm_resp_data = {address, read_data, OP_SUCC};
|
|
||||||
|
|
||||||
|
|
||||||
full_handshake_tx #(
|
|
||||||
.DW(DM_RESP_BITS)
|
|
||||||
) tx(
|
|
||||||
.clk(clk),
|
|
||||||
.rst_n(rst_n),
|
|
||||||
.ack_i(dtm_ack_i),
|
|
||||||
.req_i(need_resp),
|
|
||||||
.req_data_i(dm_resp_data),
|
|
||||||
.idle_o(tx_idle),
|
|
||||||
.req_o(dm_resp_valid_o),
|
|
||||||
.req_data_o(dm_resp_data_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
full_handshake_rx #(
|
|
||||||
.DW(DTM_REQ_BITS)
|
|
||||||
) rx(
|
|
||||||
.clk(clk),
|
|
||||||
.rst_n(rst_n),
|
|
||||||
.req_i(dtm_req_valid_i),
|
|
||||||
.req_data_i(dtm_req_data_i),
|
|
||||||
.ack_o(dm_ack_o),
|
|
||||||
.recv_data_o(rx_data),
|
|
||||||
.recv_rdy_o(rx_valid)
|
|
||||||
);
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
module jtag_dmi #(
|
||||||
|
parameter DATA_WIDTH = 41
|
||||||
|
)(
|
||||||
|
|
||||||
|
// JTAG side(master side)
|
||||||
|
input wire jtag_tck_i,
|
||||||
|
input wire jtag_trst_ni,
|
||||||
|
|
||||||
|
input wire [DATA_WIDTH-1:0] jtag_data_i,
|
||||||
|
input wire jtag_valid_i,
|
||||||
|
output wire jtag_ready_o,
|
||||||
|
|
||||||
|
output wire [DATA_WIDTH-1:0] jtag_data_o,
|
||||||
|
output wire jtag_valid_o,
|
||||||
|
input wire jtag_ready_i,
|
||||||
|
|
||||||
|
// Core side(slave side)
|
||||||
|
input wire clk_i,
|
||||||
|
input wire rst_ni,
|
||||||
|
|
||||||
|
input wire [DATA_WIDTH-1:0] core_data_i,
|
||||||
|
input wire core_valid_i,
|
||||||
|
output wire core_ready_o,
|
||||||
|
|
||||||
|
output wire [DATA_WIDTH-1:0] core_data_o,
|
||||||
|
output wire core_valid_o,
|
||||||
|
input wire core_ready_i
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
cdc_2phase #(.DATA_WIDTH(DATA_WIDTH)) u_cdc_req (
|
||||||
|
.src_rst_ni ( jtag_trst_ni ),
|
||||||
|
.src_clk_i ( jtag_tck_i ),
|
||||||
|
.src_data_i ( jtag_data_i ),
|
||||||
|
.src_valid_i ( jtag_valid_i ),
|
||||||
|
.src_ready_o ( jtag_ready_o ),
|
||||||
|
|
||||||
|
.dst_rst_ni ( rst_ni ),
|
||||||
|
.dst_clk_i ( clk_i ),
|
||||||
|
.dst_data_o ( core_data_o ),
|
||||||
|
.dst_valid_o ( core_valid_o ),
|
||||||
|
.dst_ready_i ( core_ready_i )
|
||||||
|
);
|
||||||
|
|
||||||
|
cdc_2phase #(.DATA_WIDTH(DATA_WIDTH)) u_cdc_resp (
|
||||||
|
.src_rst_ni ( rst_ni ),
|
||||||
|
.src_clk_i ( clk_i ),
|
||||||
|
.src_data_i ( core_data_i ),
|
||||||
|
.src_valid_i ( core_valid_i ),
|
||||||
|
.src_ready_o ( core_ready_o ),
|
||||||
|
|
||||||
|
.dst_rst_ni ( jtag_trst_ni ),
|
||||||
|
.dst_clk_i ( jtag_tck_i ),
|
||||||
|
.dst_data_o ( jtag_data_o ),
|
||||||
|
.dst_valid_o ( jtag_valid_o ),
|
||||||
|
.dst_ready_i ( jtag_ready_i )
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,295 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`define DM_RESP_VALID 1'b1
|
|
||||||
`define DM_RESP_INVALID 1'b0
|
|
||||||
`define DTM_REQ_VALID 1'b1
|
|
||||||
`define DTM_REQ_INVALID 1'b0
|
|
||||||
|
|
||||||
|
|
||||||
module jtag_driver #(
|
|
||||||
parameter DMI_ADDR_BITS = 6,
|
|
||||||
parameter DMI_DATA_BITS = 32,
|
|
||||||
parameter DMI_OP_BITS = 2)(
|
|
||||||
|
|
||||||
rst_n,
|
|
||||||
|
|
||||||
jtag_TCK,
|
|
||||||
jtag_TDI,
|
|
||||||
jtag_TMS,
|
|
||||||
jtag_TDO,
|
|
||||||
|
|
||||||
// rx
|
|
||||||
dm_resp_i,
|
|
||||||
dm_resp_data_i,
|
|
||||||
dtm_ack_o,
|
|
||||||
|
|
||||||
// tx
|
|
||||||
dm_ack_i,
|
|
||||||
dtm_req_valid_o,
|
|
||||||
dtm_req_data_o
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
parameter IDCODE_VERSION = 4'h1;
|
|
||||||
parameter IDCODE_PART_NUMBER = 16'he200;
|
|
||||||
parameter IDCODE_MANUFLD = 11'h537;
|
|
||||||
|
|
||||||
parameter DTM_VERSION = 4'h1;
|
|
||||||
parameter IR_BITS = 5;
|
|
||||||
|
|
||||||
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
|
||||||
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
|
||||||
parameter SHIFT_REG_BITS = DTM_REQ_BITS;
|
|
||||||
|
|
||||||
// input and output
|
|
||||||
input wire rst_n;
|
|
||||||
input wire jtag_TCK;
|
|
||||||
input wire jtag_TDI;
|
|
||||||
input wire jtag_TMS;
|
|
||||||
output reg jtag_TDO;
|
|
||||||
input wire dm_resp_i;
|
|
||||||
input wire[DM_RESP_BITS - 1:0] dm_resp_data_i;
|
|
||||||
output wire dtm_ack_o;
|
|
||||||
input wire dm_ack_i;
|
|
||||||
output wire dtm_req_valid_o;
|
|
||||||
output wire[DTM_REQ_BITS - 1:0] dtm_req_data_o;
|
|
||||||
|
|
||||||
// JTAG StateMachine
|
|
||||||
parameter TEST_LOGIC_RESET = 4'h0;
|
|
||||||
parameter RUN_TEST_IDLE = 4'h1;
|
|
||||||
parameter SELECT_DR = 4'h2;
|
|
||||||
parameter CAPTURE_DR = 4'h3;
|
|
||||||
parameter SHIFT_DR = 4'h4;
|
|
||||||
parameter EXIT1_DR = 4'h5;
|
|
||||||
parameter PAUSE_DR = 4'h6;
|
|
||||||
parameter EXIT2_DR = 4'h7;
|
|
||||||
parameter UPDATE_DR = 4'h8;
|
|
||||||
parameter SELECT_IR = 4'h9;
|
|
||||||
parameter CAPTURE_IR = 4'hA;
|
|
||||||
parameter SHIFT_IR = 4'hB;
|
|
||||||
parameter EXIT1_IR = 4'hC;
|
|
||||||
parameter PAUSE_IR = 4'hD;
|
|
||||||
parameter EXIT2_IR = 4'hE;
|
|
||||||
parameter UPDATE_IR = 4'hF;
|
|
||||||
|
|
||||||
// DTM regs
|
|
||||||
parameter REG_BYPASS = 5'b11111;
|
|
||||||
parameter REG_IDCODE = 5'b00001;
|
|
||||||
parameter REG_DMI = 5'b10001;
|
|
||||||
parameter REG_DTMCS = 5'b10000;
|
|
||||||
|
|
||||||
reg[IR_BITS - 1:0] ir_reg;
|
|
||||||
reg[SHIFT_REG_BITS - 1:0] shift_reg;
|
|
||||||
reg[3:0] jtag_state;
|
|
||||||
wire is_busy;
|
|
||||||
reg sticky_busy;
|
|
||||||
reg dtm_req_valid;
|
|
||||||
reg[DTM_REQ_BITS - 1:0] dtm_req_data;
|
|
||||||
reg[DM_RESP_BITS - 1:0] dm_resp_data;
|
|
||||||
reg dm_is_busy;
|
|
||||||
|
|
||||||
wire[5:0] addr_bits = DMI_ADDR_BITS[5:0];
|
|
||||||
wire [SHIFT_REG_BITS - 1:0] busy_response;
|
|
||||||
wire [SHIFT_REG_BITS - 1:0] none_busy_response;
|
|
||||||
wire[31:0] idcode;
|
|
||||||
wire[31:0] dtmcs;
|
|
||||||
wire[1:0] dmi_stat;
|
|
||||||
wire dtm_reset;
|
|
||||||
wire tx_idle;
|
|
||||||
wire rx_valid;
|
|
||||||
wire[DM_RESP_BITS - 1:0] rx_data;
|
|
||||||
wire tx_valid;
|
|
||||||
wire[DTM_REQ_BITS - 1:0] tx_data;
|
|
||||||
|
|
||||||
assign dtm_reset = shift_reg[16];
|
|
||||||
assign idcode = {IDCODE_VERSION, IDCODE_PART_NUMBER, IDCODE_MANUFLD, 1'h1};
|
|
||||||
assign dtmcs = {14'b0,
|
|
||||||
1'b0, // dmihardreset
|
|
||||||
1'b0, // dmireset
|
|
||||||
1'b0,
|
|
||||||
3'h5, // idle
|
|
||||||
dmi_stat, // dmistat
|
|
||||||
addr_bits, // abits
|
|
||||||
DTM_VERSION}; // version
|
|
||||||
|
|
||||||
assign busy_response = {{(DMI_ADDR_BITS + DMI_DATA_BITS){1'b0}}, {(DMI_OP_BITS){1'b1}}}; // op = 2'b11
|
|
||||||
assign none_busy_response = dm_resp_data;
|
|
||||||
assign is_busy = sticky_busy | dm_is_busy;
|
|
||||||
assign dmi_stat = is_busy ? 2'b01 : 2'b00;
|
|
||||||
|
|
||||||
// state switch
|
|
||||||
always @(posedge jtag_TCK or negedge rst_n) begin
|
|
||||||
if (!rst_n) begin
|
|
||||||
jtag_state <= TEST_LOGIC_RESET;
|
|
||||||
end else begin
|
|
||||||
case (jtag_state)
|
|
||||||
TEST_LOGIC_RESET : jtag_state <= jtag_TMS ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
|
|
||||||
RUN_TEST_IDLE : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
|
|
||||||
SELECT_DR : jtag_state <= jtag_TMS ? SELECT_IR : CAPTURE_DR;
|
|
||||||
CAPTURE_DR : jtag_state <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
|
|
||||||
SHIFT_DR : jtag_state <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
|
|
||||||
EXIT1_DR : jtag_state <= jtag_TMS ? UPDATE_DR : PAUSE_DR;
|
|
||||||
PAUSE_DR : jtag_state <= jtag_TMS ? EXIT2_DR : PAUSE_DR;
|
|
||||||
EXIT2_DR : jtag_state <= jtag_TMS ? UPDATE_DR : SHIFT_DR;
|
|
||||||
UPDATE_DR : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
|
|
||||||
SELECT_IR : jtag_state <= jtag_TMS ? TEST_LOGIC_RESET : CAPTURE_IR;
|
|
||||||
CAPTURE_IR : jtag_state <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
|
|
||||||
SHIFT_IR : jtag_state <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
|
|
||||||
EXIT1_IR : jtag_state <= jtag_TMS ? UPDATE_IR : PAUSE_IR;
|
|
||||||
PAUSE_IR : jtag_state <= jtag_TMS ? EXIT2_IR : PAUSE_IR;
|
|
||||||
EXIT2_IR : jtag_state <= jtag_TMS ? UPDATE_IR : SHIFT_IR;
|
|
||||||
UPDATE_IR : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// IR or DR shift
|
|
||||||
always @(posedge jtag_TCK) begin
|
|
||||||
case (jtag_state)
|
|
||||||
// IR
|
|
||||||
CAPTURE_IR: shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, 1'b1}; //JTAG spec says it must be b01
|
|
||||||
SHIFT_IR : shift_reg <= {{(SHIFT_REG_BITS - IR_BITS){1'b0}}, jtag_TDI, shift_reg[IR_BITS - 1:1]}; // right shift 1 bit
|
|
||||||
// DR
|
|
||||||
CAPTURE_DR: case (ir_reg)
|
|
||||||
REG_BYPASS : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
|
|
||||||
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, idcode};
|
|
||||||
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, dtmcs};
|
|
||||||
REG_DMI : shift_reg <= is_busy ? busy_response : none_busy_response;
|
|
||||||
default:
|
|
||||||
shift_reg <= {(SHIFT_REG_BITS){1'b0}};
|
|
||||||
endcase
|
|
||||||
SHIFT_DR : case (ir_reg)
|
|
||||||
REG_BYPASS : shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, jtag_TDI}; // in = out
|
|
||||||
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bit
|
|
||||||
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bit
|
|
||||||
REG_DMI : shift_reg <= {jtag_TDI, shift_reg[SHIFT_REG_BITS - 1:1]}; // right shift 1 bit
|
|
||||||
default:
|
|
||||||
shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}} , jtag_TDI};
|
|
||||||
endcase
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
// start access DM module
|
|
||||||
always @(posedge jtag_TCK or negedge rst_n) begin
|
|
||||||
if (!rst_n) begin
|
|
||||||
dtm_req_valid <= `DTM_REQ_INVALID;
|
|
||||||
dtm_req_data <= {DTM_REQ_BITS{1'b0}};
|
|
||||||
end else begin
|
|
||||||
if (jtag_state == UPDATE_DR) begin
|
|
||||||
if (ir_reg == REG_DMI) begin
|
|
||||||
// if DM can be access
|
|
||||||
if (!is_busy & tx_idle) begin
|
|
||||||
dtm_req_valid <= `DTM_REQ_VALID;
|
|
||||||
dtm_req_data <= shift_reg;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end else begin
|
|
||||||
dtm_req_valid <= `DTM_REQ_INVALID;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assign tx_valid = dtm_req_valid;
|
|
||||||
assign tx_data = dtm_req_data;
|
|
||||||
|
|
||||||
// DTM reset
|
|
||||||
always @ (posedge jtag_TCK or negedge rst_n) begin
|
|
||||||
if (!rst_n) begin
|
|
||||||
sticky_busy <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
if (jtag_state == UPDATE_DR) begin
|
|
||||||
if (ir_reg == REG_DTMCS & dtm_reset) begin
|
|
||||||
sticky_busy <= 1'b0;
|
|
||||||
end
|
|
||||||
end else if (jtag_state == CAPTURE_DR) begin
|
|
||||||
if (ir_reg == REG_DMI) begin
|
|
||||||
sticky_busy <= is_busy;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// receive DM response data
|
|
||||||
always @ (posedge jtag_TCK or negedge rst_n) begin
|
|
||||||
if (!rst_n) begin
|
|
||||||
dm_resp_data <= {DM_RESP_BITS{1'b0}};
|
|
||||||
end else begin
|
|
||||||
if (rx_valid) begin
|
|
||||||
dm_resp_data <= rx_data;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// tx busy
|
|
||||||
always @ (posedge jtag_TCK or negedge rst_n) begin
|
|
||||||
if (!rst_n) begin
|
|
||||||
dm_is_busy <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
if (dtm_req_valid) begin
|
|
||||||
dm_is_busy <= 1'b1;
|
|
||||||
end else if (rx_valid) begin
|
|
||||||
dm_is_busy <= 1'b0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// TAP reset
|
|
||||||
always @(negedge jtag_TCK) begin
|
|
||||||
if (jtag_state == TEST_LOGIC_RESET) begin
|
|
||||||
ir_reg <= REG_IDCODE;
|
|
||||||
end else if (jtag_state == UPDATE_IR) begin
|
|
||||||
ir_reg <= shift_reg[IR_BITS - 1:0];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// TDO output
|
|
||||||
always @(negedge jtag_TCK) begin
|
|
||||||
if (jtag_state == SHIFT_IR) begin
|
|
||||||
jtag_TDO <= shift_reg[0];
|
|
||||||
end else if (jtag_state == SHIFT_DR) begin
|
|
||||||
jtag_TDO <= shift_reg[0];
|
|
||||||
end else begin
|
|
||||||
jtag_TDO <= 1'b0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
full_handshake_tx #(
|
|
||||||
.DW(DTM_REQ_BITS)
|
|
||||||
) tx(
|
|
||||||
.clk(jtag_TCK),
|
|
||||||
.rst_n(rst_n),
|
|
||||||
.ack_i(dm_ack_i),
|
|
||||||
.req_i(tx_valid),
|
|
||||||
.req_data_i(tx_data),
|
|
||||||
.idle_o(tx_idle),
|
|
||||||
.req_o(dtm_req_valid_o),
|
|
||||||
.req_data_o(dtm_req_data_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
full_handshake_rx #(
|
|
||||||
.DW(DM_RESP_BITS)
|
|
||||||
) rx(
|
|
||||||
.clk(jtag_TCK),
|
|
||||||
.rst_n(rst_n),
|
|
||||||
.req_i(dm_resp_i),
|
|
||||||
.req_data_i(dm_resp_data_i),
|
|
||||||
.ack_o(dtm_ack_o),
|
|
||||||
.recv_data_o(rx_data),
|
|
||||||
.recv_rdy_o(rx_valid)
|
|
||||||
);
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "jtag_def.sv"
|
||||||
|
|
||||||
|
module jtag_dtm #(
|
||||||
|
parameter DMI_ADDR_BITS = 7,
|
||||||
|
parameter DMI_DATA_BITS = 32,
|
||||||
|
parameter DMI_OP_BITS = 2,
|
||||||
|
parameter TAP_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
|
||||||
|
parameter DTM_RESP_BITS = TAP_REQ_BITS,
|
||||||
|
parameter DTM_REQ_BITS = DTM_RESP_BITS,
|
||||||
|
parameter DMI_RESP_BITS = DTM_REQ_BITS
|
||||||
|
)(
|
||||||
|
|
||||||
|
input wire jtag_tck_i, // JTAG test clock pad
|
||||||
|
input wire jtag_trst_ni, // JTAG test reset pad
|
||||||
|
|
||||||
|
// to jtag_dmi
|
||||||
|
output wire [DTM_REQ_BITS-1:0] dtm_data_o,
|
||||||
|
output wire dtm_valid_o,
|
||||||
|
// from jtag_dmi
|
||||||
|
input wire dmi_ready_i,
|
||||||
|
|
||||||
|
// from jtag_dmi
|
||||||
|
input wire [DMI_RESP_BITS-1:0] dmi_data_i,
|
||||||
|
input wire dmi_valid_i,
|
||||||
|
// to jtag_dmi
|
||||||
|
output wire dtm_ready_o,
|
||||||
|
|
||||||
|
// from jtag_tap
|
||||||
|
input wire tap_req_i,
|
||||||
|
input wire [TAP_REQ_BITS-1:0] tap_data_i,
|
||||||
|
input wire dmireset_i,
|
||||||
|
|
||||||
|
// to jtag_tap
|
||||||
|
output wire [DTM_RESP_BITS-1:0] data_o,
|
||||||
|
output wire [31:0] idcode_o,
|
||||||
|
output wire [31:0] dtmcs_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam IDCODE_VERSION = 4'h1;
|
||||||
|
localparam IDCODE_PART_NUMBER = 16'he200;
|
||||||
|
localparam IDCODE_MANUFLD = 11'h537;
|
||||||
|
|
||||||
|
localparam DTM_VERSION = 4'h1;
|
||||||
|
|
||||||
|
localparam S_IDLE = 5'b00001;
|
||||||
|
localparam S_READ = 5'b00010;
|
||||||
|
localparam S_WAIT_READ = 5'b00100;
|
||||||
|
localparam S_WRITE = 5'b01000;
|
||||||
|
localparam S_WAIT_WRITE = 5'b10000;
|
||||||
|
|
||||||
|
reg[4:0] state_d;
|
||||||
|
reg[4:0] state_q;
|
||||||
|
reg dtm_valid;
|
||||||
|
reg dtm_ready;
|
||||||
|
reg[DTM_REQ_BITS-1:0] dtm_data_q;
|
||||||
|
reg[DTM_REQ_BITS-1:0] dtm_data_d;
|
||||||
|
reg[DTM_RESP_BITS-1:0] resp_tap_data_q;
|
||||||
|
reg is_busy;
|
||||||
|
reg stick_busy;
|
||||||
|
|
||||||
|
wire[DTM_RESP_BITS-1:0] busy_response;
|
||||||
|
wire dtm_busy;
|
||||||
|
wire[DMI_OP_BITS-1:0] op;
|
||||||
|
wire[1:0] dmistat;
|
||||||
|
wire[DMI_ADDR_BITS-1:0] abits = DMI_ADDR_BITS[6:0];
|
||||||
|
|
||||||
|
assign idcode_o = {IDCODE_VERSION, IDCODE_PART_NUMBER, IDCODE_MANUFLD, 1'h1};
|
||||||
|
assign dtmcs_o = {14'b0,
|
||||||
|
1'b0, // dmihardreset
|
||||||
|
1'b0, // dmireset
|
||||||
|
1'b0,
|
||||||
|
3'h1, // idle
|
||||||
|
dmistat, // dmistat
|
||||||
|
abits, // abits
|
||||||
|
DTM_VERSION}; // version
|
||||||
|
|
||||||
|
assign busy_response = {{(DMI_ADDR_BITS + DMI_DATA_BITS){1'b0}}, {(DMI_OP_BITS){1'b1}}}; // op = 2'b11
|
||||||
|
|
||||||
|
assign dmistat = (stick_busy | is_busy) ? 2'b11 : 2'b00;
|
||||||
|
|
||||||
|
assign op = tap_data_i[DMI_OP_BITS-1:0];
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
state_d = state_q;
|
||||||
|
dtm_valid = 1'b0;
|
||||||
|
dtm_ready = 1'b0;
|
||||||
|
dtm_data_d = dtm_data_q;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
if (tap_req_i) begin
|
||||||
|
if (op == `DMI_OP_READ) begin
|
||||||
|
state_d = S_READ;
|
||||||
|
dtm_data_d = tap_data_i;
|
||||||
|
end else if (op == `DMI_OP_WRITE) begin
|
||||||
|
state_d = S_WRITE;
|
||||||
|
dtm_data_d = tap_data_i;
|
||||||
|
end else begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_READ: begin
|
||||||
|
if (dmi_ready_i) begin
|
||||||
|
dtm_valid = 1'b1;
|
||||||
|
state_d = S_WAIT_READ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_WAIT_READ: begin
|
||||||
|
dtm_ready = 1'b1;
|
||||||
|
if (dmi_valid_i) begin
|
||||||
|
dtm_data_d = dmi_data_i;
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_WRITE: begin
|
||||||
|
if (dmi_ready_i) begin
|
||||||
|
dtm_valid = 1'b1;
|
||||||
|
state_d = S_WAIT_WRITE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_WAIT_WRITE: begin
|
||||||
|
dtm_ready = 1'b1;
|
||||||
|
if (dmi_valid_i) begin
|
||||||
|
dtm_data_d = dmi_data_i;
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin
|
||||||
|
dtm_data_d = {DTM_REQ_BITS{1'b0}};
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign dtm_valid_o = dtm_valid;
|
||||||
|
assign dtm_data_o = dtm_data_q;
|
||||||
|
assign dtm_ready_o = dtm_ready;
|
||||||
|
|
||||||
|
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
|
||||||
|
if (!jtag_trst_ni) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
dtm_data_q <= {DTM_REQ_BITS{1'b0}};
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
dtm_data_q <= dtm_data_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
|
||||||
|
if (!jtag_trst_ni) begin
|
||||||
|
is_busy <= 1'b0;
|
||||||
|
stick_busy <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
if (dmireset_i) begin
|
||||||
|
stick_busy <= 1'b0;
|
||||||
|
end else if ((state_q != S_IDLE) && tap_req_i) begin
|
||||||
|
stick_busy <= 1'b1;
|
||||||
|
end
|
||||||
|
if ((state_q != S_IDLE) | tap_req_i) begin
|
||||||
|
is_busy <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
is_busy <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_o = (stick_busy | is_busy | tap_req_i) ? busy_response : dtm_data_q;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,512 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "jtag_def.sv"
|
||||||
|
|
||||||
|
module jtag_mem(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
output wire halted_o,
|
||||||
|
output wire resumeack_o,
|
||||||
|
input wire clear_resumeack_i,
|
||||||
|
input wire resumereq_i,
|
||||||
|
input wire haltreq_i,
|
||||||
|
input wire ndmreset_i,
|
||||||
|
|
||||||
|
input wire [`ProgBufSize-1:0][31:0] progbuf_i,
|
||||||
|
input wire [31:0] data_i,
|
||||||
|
output wire [31:0] data_o,
|
||||||
|
output wire data_valid_o,
|
||||||
|
input wire cmd_valid_i,
|
||||||
|
input wire [31:0] cmd_i,
|
||||||
|
output wire cmderror_valid_o,
|
||||||
|
output wire [2:0] cmderror_o,
|
||||||
|
output wire cmdbusy_o,
|
||||||
|
|
||||||
|
input wire req_i,
|
||||||
|
input wire we_i,
|
||||||
|
input wire [31:0] addr_i,
|
||||||
|
input wire [3:0] be_i,
|
||||||
|
input wire [31:0] wdata_i,
|
||||||
|
output wire gnt_o,
|
||||||
|
output wire rvalid_o,
|
||||||
|
output wire [31:0] rdata_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
// 16KB
|
||||||
|
localparam DbgAddressBits = 12;
|
||||||
|
// x10/a0
|
||||||
|
localparam LoadBaseAddr = 5'd10;
|
||||||
|
|
||||||
|
localparam Data0Addr = `DataBaseAddr;
|
||||||
|
localparam Data1Addr = `DataBaseAddr + 4;
|
||||||
|
localparam Data2Addr = `DataBaseAddr + 8;
|
||||||
|
localparam Data3Addr = `DataBaseAddr + 12;
|
||||||
|
localparam Data4Addr = `DataBaseAddr + 16;
|
||||||
|
|
||||||
|
localparam Progbuf0Addr = `ProgbufBaseAddr;
|
||||||
|
localparam Progbuf1Addr = `ProgbufBaseAddr + 4;
|
||||||
|
localparam Progbuf2Addr = `ProgbufBaseAddr + 8;
|
||||||
|
localparam Progbuf3Addr = `ProgbufBaseAddr + 12;
|
||||||
|
localparam Progbuf4Addr = `ProgbufBaseAddr + 16;
|
||||||
|
localparam Progbuf5Addr = `ProgbufBaseAddr + 20;
|
||||||
|
localparam Progbuf6Addr = `ProgbufBaseAddr + 24;
|
||||||
|
localparam Progbuf7Addr = `ProgbufBaseAddr + 28;
|
||||||
|
localparam Progbuf8Addr = `ProgbufBaseAddr + 32;
|
||||||
|
localparam Progbuf9Addr = `ProgbufBaseAddr + 36;
|
||||||
|
|
||||||
|
localparam AbstractCmd0Addr = `AbstCmdBaseAddr;
|
||||||
|
localparam AbstractCmd1Addr = `AbstCmdBaseAddr + 4;
|
||||||
|
localparam AbstractCmd2Addr = `AbstCmdBaseAddr + 8;
|
||||||
|
localparam AbstractCmd3Addr = `AbstCmdBaseAddr + 12;
|
||||||
|
localparam AbstractCmd4Addr = `AbstCmdBaseAddr + 16;
|
||||||
|
localparam AbstractCmd5Addr = `AbstCmdBaseAddr + 20;
|
||||||
|
localparam AbstractCmd6Addr = `AbstCmdBaseAddr + 24;
|
||||||
|
localparam AbstractCmd7Addr = `AbstCmdBaseAddr + 28;
|
||||||
|
localparam AbstractCmd8Addr = `AbstCmdBaseAddr + 32;
|
||||||
|
localparam AbstractCmd9Addr = `AbstCmdBaseAddr + 36;
|
||||||
|
|
||||||
|
localparam WhereToAddr = 12'h300;
|
||||||
|
localparam FlagsBaseAddr = 12'h400;
|
||||||
|
localparam FlagsEndAddr = 12'h7FF;
|
||||||
|
|
||||||
|
localparam HaltedAddr = 12'h100;
|
||||||
|
localparam GoingAddr = 12'h104;
|
||||||
|
localparam ResumingAddr = 12'h108;
|
||||||
|
localparam ExceptionAddr = 12'h10C;
|
||||||
|
|
||||||
|
localparam CmdAccessRegister = 8'h0;
|
||||||
|
localparam CmdQuickAccess = 8'h1;
|
||||||
|
localparam CmdAccessMemory = 8'h2;
|
||||||
|
|
||||||
|
localparam CmdErrorNone = 3'h0;
|
||||||
|
localparam CmdErrorHaltResume = 3'h4;
|
||||||
|
localparam CmdErrorNotSupport = 3'h2;
|
||||||
|
localparam CmdErrorException = 3'h3;
|
||||||
|
|
||||||
|
localparam illegal = 32'h00000000;
|
||||||
|
localparam nop = 32'h00000013;
|
||||||
|
localparam ebreak = 32'h00100073;
|
||||||
|
|
||||||
|
localparam S_IDLE = 4'b0001;
|
||||||
|
localparam S_RESUME = 4'b0010;
|
||||||
|
localparam S_GO = 4'b0100;
|
||||||
|
localparam S_CMD_EXECUTING = 4'b1000;
|
||||||
|
|
||||||
|
|
||||||
|
function automatic [31:0] jal;
|
||||||
|
input [4:0] rd;
|
||||||
|
input [20:0] imm;
|
||||||
|
|
||||||
|
jal = {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h6f};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [31:0] slli;
|
||||||
|
input [4:0] rd;
|
||||||
|
input [4:0] rs1;
|
||||||
|
input [5:0] shamt;
|
||||||
|
|
||||||
|
slli = {6'b0, shamt[5:0], rs1, 3'h1, rd, 7'h13};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [31:0] srli;
|
||||||
|
input [4:0] rd;
|
||||||
|
input [4:0] rs1;
|
||||||
|
input [5:0] shamt;
|
||||||
|
|
||||||
|
srli = {6'b0, shamt[5:0], rs1, 3'h5, rd, 7'h13};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [31:0] load;
|
||||||
|
input [2:0] size;
|
||||||
|
input [4:0] dest;
|
||||||
|
input [4:0] base;
|
||||||
|
input [11:0] offset;
|
||||||
|
|
||||||
|
load = {offset[11:0], base, size, dest, 7'h03};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [31:0] auipc;
|
||||||
|
input [4:0] rd;
|
||||||
|
input [20:0] imm;
|
||||||
|
|
||||||
|
auipc = {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h17};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [31:0] store;
|
||||||
|
input [2:0] size;
|
||||||
|
input [4:0] src;
|
||||||
|
input [4:0] base;
|
||||||
|
input [11:0] offset;
|
||||||
|
|
||||||
|
store = {offset[11:5], src, base, size, offset[4:0], 7'h23};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [31:0] csrw;
|
||||||
|
input [11:0] csr;
|
||||||
|
input [4:0] rs1;
|
||||||
|
|
||||||
|
csrw = {csr, rs1, 3'h1, 5'h0, 7'h73};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [31:0] csrr;
|
||||||
|
input [11:0] csr;
|
||||||
|
input [4:0] dest;
|
||||||
|
|
||||||
|
csrr = {csr, 5'h0, 3'h2, dest, 7'h73};
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
reg[3:0] state_d, state_q;
|
||||||
|
reg[31:0] rdata_d, rdata_q;
|
||||||
|
reg halted_d, halted_q;
|
||||||
|
reg resuming_d, resuming_q;
|
||||||
|
reg resume, go, going;
|
||||||
|
reg fwd_rom_q;
|
||||||
|
reg data_valid;
|
||||||
|
reg cmdbusy;
|
||||||
|
reg halted_aligned;
|
||||||
|
reg rvalid_q;
|
||||||
|
wire fwd_rom_d;
|
||||||
|
wire[31:0] rom_rdata;
|
||||||
|
reg[31:0] data_bits;
|
||||||
|
reg[9:0][31:0] abstract_cmd;
|
||||||
|
reg unsupported_command;
|
||||||
|
reg cmderror_valid;
|
||||||
|
reg[2:0] cmderror;
|
||||||
|
reg exception;
|
||||||
|
wire[11:0] progbuf_baseaddr = Progbuf0Addr;
|
||||||
|
wire[11:0] abstractcmd_baseaddr = AbstractCmd0Addr;
|
||||||
|
wire[7:0] cmd_type = cmd_i[31:24];
|
||||||
|
wire cmd_postexec = cmd_i[18];
|
||||||
|
wire cmd_transfer = cmd_i[17];
|
||||||
|
wire cmd_write = cmd_i[16];
|
||||||
|
wire[15:0] cmd_regno = cmd_i[15:0];
|
||||||
|
wire[2:0] cmd_aarsize = cmd_i[22:20];
|
||||||
|
wire cmd_aarpostincrement = cmd_i[19];
|
||||||
|
|
||||||
|
wire[31:0] word_mux;
|
||||||
|
assign word_mux = fwd_rom_q ? rom_rdata : rdata_q;
|
||||||
|
assign rdata_o = word_mux;
|
||||||
|
|
||||||
|
assign halted_o = halted_q;
|
||||||
|
assign resumeack_o = resuming_q;
|
||||||
|
assign gnt_o = req_i;
|
||||||
|
assign rvalid_o = rvalid_q;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
state_d = state_q;
|
||||||
|
resume = 1'b0;
|
||||||
|
go = 1'b0;
|
||||||
|
cmdbusy = 1'b1;
|
||||||
|
cmderror_valid = 1'b0;
|
||||||
|
cmderror = CmdErrorNone;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
cmdbusy = 1'b0;
|
||||||
|
if (resumereq_i && (!resuming_q) &&
|
||||||
|
halted_q && (!haltreq_i)) begin
|
||||||
|
state_d = S_RESUME;
|
||||||
|
end
|
||||||
|
if (cmd_valid_i) begin
|
||||||
|
if (!halted_q) begin
|
||||||
|
cmderror_valid = 1'b1;
|
||||||
|
cmderror = CmdErrorHaltResume;
|
||||||
|
end else if (unsupported_command) begin
|
||||||
|
cmderror_valid = 1'b1;
|
||||||
|
cmderror = CmdErrorNotSupport;
|
||||||
|
end else begin
|
||||||
|
state_d = S_GO;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_GO: begin
|
||||||
|
cmdbusy = 1'b1;
|
||||||
|
go = 1'b1;
|
||||||
|
if (going) begin
|
||||||
|
state_d = S_CMD_EXECUTING;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_RESUME: begin
|
||||||
|
resume = 1'b1;
|
||||||
|
cmdbusy = 1'b1;
|
||||||
|
if (resuming_q) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_CMD_EXECUTING: begin
|
||||||
|
cmdbusy = 1'b1;
|
||||||
|
go = 1'b0;
|
||||||
|
if (halted_aligned) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default:;
|
||||||
|
endcase
|
||||||
|
|
||||||
|
if (exception) begin
|
||||||
|
cmderror_valid = 1'b1;
|
||||||
|
cmderror = CmdErrorException;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign cmderror_valid_o = cmderror_valid;
|
||||||
|
assign cmderror_o = cmderror;
|
||||||
|
assign cmdbusy_o = cmdbusy;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
rdata_d = rdata_q;
|
||||||
|
halted_d = halted_q;
|
||||||
|
resuming_d = resuming_q;
|
||||||
|
|
||||||
|
going = 1'b0;
|
||||||
|
exception = 1'b0;
|
||||||
|
halted_aligned = 1'b0;
|
||||||
|
|
||||||
|
data_valid = 1'b0;
|
||||||
|
data_bits = data_i;
|
||||||
|
|
||||||
|
if (clear_resumeack_i) begin
|
||||||
|
resuming_d = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (ndmreset_i & (!haltreq_i)) begin
|
||||||
|
halted_d = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// write
|
||||||
|
if (req_i & we_i) begin
|
||||||
|
case (addr_i[DbgAddressBits-1:0])
|
||||||
|
HaltedAddr: begin
|
||||||
|
halted_d = 1'b1;
|
||||||
|
halted_aligned = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
GoingAddr: begin
|
||||||
|
going = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
ResumingAddr: begin
|
||||||
|
halted_d = 1'b0;
|
||||||
|
resuming_d = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
ExceptionAddr: begin
|
||||||
|
exception = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
Data0Addr, Data1Addr, Data2Addr,
|
||||||
|
Data3Addr, Data4Addr: begin
|
||||||
|
data_valid = 1'b1;
|
||||||
|
if (be_i[0])
|
||||||
|
data_bits[7:0] = wdata_i[7:0];
|
||||||
|
if (be_i[1])
|
||||||
|
data_bits[15:8] = wdata_i[15:8];
|
||||||
|
if (be_i[2])
|
||||||
|
data_bits[23:16] = wdata_i[23:16];
|
||||||
|
if (be_i[3])
|
||||||
|
data_bits[31:24] = wdata_i[31:24];
|
||||||
|
end
|
||||||
|
|
||||||
|
default:;
|
||||||
|
endcase
|
||||||
|
// read
|
||||||
|
end else if (req_i & (!we_i)) begin
|
||||||
|
case (addr_i[DbgAddressBits-1:0])
|
||||||
|
WhereToAddr: begin
|
||||||
|
if (cmdbusy & (cmd_type == CmdAccessRegister)) begin
|
||||||
|
// execute program buf
|
||||||
|
if (cmd_postexec) begin
|
||||||
|
rdata_d = jal(5'h0, {9'h0, progbuf_baseaddr-WhereToAddr});
|
||||||
|
// execute command
|
||||||
|
end else begin
|
||||||
|
rdata_d = jal(5'h0, {9'h0, abstractcmd_baseaddr-WhereToAddr});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// harts are polling for flags here
|
||||||
|
FlagsBaseAddr: begin
|
||||||
|
rdata_d = {30'b0, resume, go};
|
||||||
|
end
|
||||||
|
|
||||||
|
Data0Addr, Data1Addr, Data2Addr, Data3Addr,
|
||||||
|
Data4Addr: begin
|
||||||
|
rdata_d = data_i;
|
||||||
|
end
|
||||||
|
|
||||||
|
Progbuf0Addr, Progbuf1Addr, Progbuf2Addr, Progbuf3Addr,
|
||||||
|
Progbuf4Addr, Progbuf5Addr, Progbuf6Addr, Progbuf7Addr,
|
||||||
|
Progbuf8Addr, Progbuf9Addr: begin
|
||||||
|
rdata_d = progbuf_i[addr_i[DbgAddressBits-1:2] -
|
||||||
|
progbuf_baseaddr[DbgAddressBits-1:2]];
|
||||||
|
end
|
||||||
|
|
||||||
|
AbstractCmd0Addr, AbstractCmd1Addr, AbstractCmd2Addr, AbstractCmd3Addr,
|
||||||
|
AbstractCmd4Addr, AbstractCmd5Addr, AbstractCmd6Addr, AbstractCmd7Addr,
|
||||||
|
AbstractCmd8Addr, AbstractCmd9Addr: begin
|
||||||
|
rdata_d = abstract_cmd[addr_i[DbgAddressBits-1:2] -
|
||||||
|
abstractcmd_baseaddr[DbgAddressBits-1:2]];
|
||||||
|
end
|
||||||
|
|
||||||
|
default:;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_valid_o = data_valid;
|
||||||
|
assign data_o = data_bits;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
unsupported_command = 1'b0;
|
||||||
|
|
||||||
|
abstract_cmd[0] = illegal;
|
||||||
|
abstract_cmd[1] = auipc(5'd10, 21'd0); // auipc a0, 0
|
||||||
|
abstract_cmd[2] = srli(5'd10, 5'd10, 6'd12); // srli a0, a0, 12
|
||||||
|
abstract_cmd[3] = slli(5'd10, 5'd10, 6'd12); // slli a0, a0, 12
|
||||||
|
abstract_cmd[4] = nop;
|
||||||
|
abstract_cmd[5] = nop;
|
||||||
|
abstract_cmd[6] = nop;
|
||||||
|
abstract_cmd[7] = nop;
|
||||||
|
abstract_cmd[8] = csrr(`CSR_DSCRATCH1, 5'd10); // csrr dscratch1, a0 恢复a0寄存器的值
|
||||||
|
abstract_cmd[9] = ebreak;
|
||||||
|
|
||||||
|
case (cmd_type)
|
||||||
|
CmdAccessRegister: begin
|
||||||
|
// unsupported reg size
|
||||||
|
if (cmd_aarsize > 3'h2 || cmd_aarpostincrement || cmd_regno >= 16'h1020) begin
|
||||||
|
abstract_cmd[0] = ebreak;
|
||||||
|
unsupported_command = 1'b1;
|
||||||
|
end else begin
|
||||||
|
// store a0 in dscratch1
|
||||||
|
abstract_cmd[0] = csrw(`CSR_DSCRATCH1, 5'd10); // csrw dscratch1, a0 保存a0寄存器的值
|
||||||
|
// write regs
|
||||||
|
if (cmd_transfer && cmd_write) begin
|
||||||
|
// a0
|
||||||
|
if (cmd_regno[12] && (cmd_regno[4:0] == 5'd10)) begin
|
||||||
|
// store s0 in dscratch
|
||||||
|
abstract_cmd[4] = csrw(`CSR_DSCRATCH0, 5'd8);
|
||||||
|
// load from data register
|
||||||
|
abstract_cmd[5] = load(cmd_aarsize, 5'd8, LoadBaseAddr, `DataBaseAddr);
|
||||||
|
// and store it in the corresponding CSR
|
||||||
|
abstract_cmd[6] = csrw(`CSR_DSCRATCH1, 5'd8);
|
||||||
|
// restore s0 again from dscratch
|
||||||
|
abstract_cmd[7] = csrr(`CSR_DSCRATCH0, 5'd8);
|
||||||
|
// GPR access
|
||||||
|
end else if (cmd_regno[12]) begin
|
||||||
|
abstract_cmd[4] = load(cmd_aarsize, cmd_regno[4:0], LoadBaseAddr, `DataBaseAddr);
|
||||||
|
// CSR access
|
||||||
|
end else begin
|
||||||
|
// data register to CSR
|
||||||
|
// store s0 in dscratch
|
||||||
|
abstract_cmd[4] = csrw(`CSR_DSCRATCH0, 5'd8);
|
||||||
|
// load from data register
|
||||||
|
abstract_cmd[5] = load(cmd_aarsize, 5'd8, LoadBaseAddr, `DataBaseAddr);
|
||||||
|
// and store it in the corresponding CSR
|
||||||
|
abstract_cmd[6] = csrw(cmd_regno[11:0], 5'd8);
|
||||||
|
// restore s0 again from dscratch
|
||||||
|
abstract_cmd[7] = csrr(`CSR_DSCRATCH0, 5'd8);
|
||||||
|
end
|
||||||
|
// read regs
|
||||||
|
end else if (cmd_transfer && (!cmd_write)) begin
|
||||||
|
// a0
|
||||||
|
if (cmd_regno[12] && (cmd_regno[4:0] == 5'd10)) begin
|
||||||
|
// store s0 in dscratch
|
||||||
|
abstract_cmd[4] = csrw(`CSR_DSCRATCH0, 5'd8);
|
||||||
|
// read value from CSR into s0
|
||||||
|
abstract_cmd[5] = csrr(`CSR_DSCRATCH1, 5'd8);
|
||||||
|
// and store s0 into data section
|
||||||
|
abstract_cmd[6] = store(cmd_aarsize, 5'd8, LoadBaseAddr, `DataBaseAddr);
|
||||||
|
// restore s0 again from dscratch
|
||||||
|
abstract_cmd[7] = csrr(`CSR_DSCRATCH0, 5'd8);
|
||||||
|
// GPR access
|
||||||
|
end else if (cmd_regno[12]) begin
|
||||||
|
abstract_cmd[4] = store(cmd_aarsize, cmd_regno[4:0], LoadBaseAddr, `DataBaseAddr);
|
||||||
|
// CSR access
|
||||||
|
end else begin
|
||||||
|
// CSR register to data
|
||||||
|
// store s0 in dscratch
|
||||||
|
abstract_cmd[4] = csrw(`CSR_DSCRATCH0, 5'd8);
|
||||||
|
// read value from CSR into s0
|
||||||
|
abstract_cmd[5] = csrr(cmd_regno[11:0], 5'd8);
|
||||||
|
// and store s0 into data section
|
||||||
|
abstract_cmd[6] = store(cmd_aarsize, 5'd8, LoadBaseAddr, `DataBaseAddr);
|
||||||
|
// restore s0 again from dscratch
|
||||||
|
abstract_cmd[7] = csrr(`CSR_DSCRATCH0, 5'd8);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (cmd_postexec && (!unsupported_command)) begin
|
||||||
|
// issue a nop, we will automatically run into the program buffer
|
||||||
|
abstract_cmd[9] = nop;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// not supported at the moment:
|
||||||
|
// CmdQuickAccess:;
|
||||||
|
// CmdAccessMemory:;
|
||||||
|
default: begin
|
||||||
|
unsupported_command = 1'b1;
|
||||||
|
abstract_cmd[0] = ebreak;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
wire[31:0] rom_addr;
|
||||||
|
assign rom_addr = addr_i;
|
||||||
|
assign fwd_rom_d = addr_i[DbgAddressBits-1:0] >= `HaltAddress;
|
||||||
|
|
||||||
|
debug_rom u_debug_rom (
|
||||||
|
.clk_i ( clk ),
|
||||||
|
.req_i ( req_i ),
|
||||||
|
.addr_i ( rom_addr ),
|
||||||
|
.rdata_o ( rom_rdata )
|
||||||
|
);
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
rdata_q <= 32'h0;
|
||||||
|
fwd_rom_q <= 1'b0;
|
||||||
|
halted_q <= 1'b0;
|
||||||
|
resuming_q <= 1'b0;
|
||||||
|
rvalid_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
rdata_q <= rdata_d;
|
||||||
|
fwd_rom_q <= fwd_rom_d;
|
||||||
|
halted_q <= halted_d;
|
||||||
|
resuming_q <= resuming_d;
|
||||||
|
rvalid_q <= req_i;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
module jtag_sba(
|
||||||
|
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n,
|
||||||
|
|
||||||
|
input wire [31:0] sbaddress_i,
|
||||||
|
input wire sbaddress_write_valid_i,
|
||||||
|
|
||||||
|
input wire sbreadonaddr_i,
|
||||||
|
output wire [31:0] sbaddress_o,
|
||||||
|
input wire sbautoincrement_i,
|
||||||
|
input wire [2:0] sbaccess_i,
|
||||||
|
|
||||||
|
input wire sbreadondata_i,
|
||||||
|
input wire [31:0] sbdata_i,
|
||||||
|
input wire sbdata_read_valid_i,
|
||||||
|
input wire sbdata_write_valid_i,
|
||||||
|
|
||||||
|
output wire [31:0] sbdata_o,
|
||||||
|
output wire sbdata_valid_o,
|
||||||
|
|
||||||
|
output wire sbbusy_o,
|
||||||
|
output wire [2:0] sberror_o,
|
||||||
|
|
||||||
|
output wire master_req_o,
|
||||||
|
input wire master_gnt_i,
|
||||||
|
input wire master_rvalid_i,
|
||||||
|
output wire master_we_o,
|
||||||
|
output wire [3:0] master_be_o,
|
||||||
|
output wire [31:0] master_addr_o,
|
||||||
|
output wire [31:0] master_wdata_o,
|
||||||
|
input wire [31:0] master_rdata_i,
|
||||||
|
input wire master_err_i
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam S_IDLE = 4'b0001;
|
||||||
|
localparam S_READ = 4'b0010;
|
||||||
|
localparam S_WAIT = 4'b0100;
|
||||||
|
localparam S_WRITE = 4'b1000;
|
||||||
|
|
||||||
|
reg[3:0] state_d, state_q;
|
||||||
|
reg[2:0] sberror;
|
||||||
|
reg[3:0] be_mask;
|
||||||
|
reg[1:0] be_index;
|
||||||
|
|
||||||
|
reg master_req;
|
||||||
|
reg master_we;
|
||||||
|
reg[3:0] master_be;
|
||||||
|
reg[31:0] master_addr;
|
||||||
|
reg[31:0] master_wdata;
|
||||||
|
reg[31:0] sbaddress;
|
||||||
|
|
||||||
|
wire[31:0] sbaddress_new;
|
||||||
|
|
||||||
|
assign sbaddress_new = sbaddress_i + (32'h1 << sbaccess_i);
|
||||||
|
|
||||||
|
assign sbbusy_o = (state_q != S_IDLE);
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
be_mask = 4'b0;
|
||||||
|
be_index = sbaddress_i[1:0];
|
||||||
|
|
||||||
|
// generate byte enable mask
|
||||||
|
case (sbaccess_i)
|
||||||
|
3'b000: begin
|
||||||
|
be_mask[be_index] = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
3'b001: begin
|
||||||
|
if (be_index == 2'h0) begin
|
||||||
|
be_mask[1:0] = 2'b11;
|
||||||
|
end else if (be_index == 2'h2) begin
|
||||||
|
be_mask[3:2] = 2'b11;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
3'b010: begin
|
||||||
|
be_mask = 4'b1111;
|
||||||
|
end
|
||||||
|
|
||||||
|
default:;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
// 访存状态机
|
||||||
|
always @ (*) begin
|
||||||
|
state_d = state_q;
|
||||||
|
|
||||||
|
sbaddress = sbaddress_i;
|
||||||
|
|
||||||
|
master_addr = sbaddress_i;
|
||||||
|
master_wdata = sbdata_i;
|
||||||
|
master_req = 1'b0;
|
||||||
|
master_be = 4'b0;
|
||||||
|
master_we = 1'b0;
|
||||||
|
|
||||||
|
sberror = 3'b0;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
// debugger requested a read
|
||||||
|
if (sbaddress_write_valid_i && sbreadonaddr_i) begin
|
||||||
|
state_d = S_READ;
|
||||||
|
end
|
||||||
|
// debugger requested a write
|
||||||
|
if (sbdata_write_valid_i) begin
|
||||||
|
state_d = S_WRITE;
|
||||||
|
end
|
||||||
|
// perform another read
|
||||||
|
if (sbdata_read_valid_i && sbreadondata_i) begin
|
||||||
|
state_d = S_READ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// 读内存
|
||||||
|
S_READ: begin
|
||||||
|
master_req = 1'b1;
|
||||||
|
master_be = 4'b1111;
|
||||||
|
if (master_gnt_i) begin
|
||||||
|
state_d = S_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// 写内存
|
||||||
|
S_WRITE: begin
|
||||||
|
master_req = 1'b1;
|
||||||
|
master_be = be_mask;
|
||||||
|
master_we = 1'b1;
|
||||||
|
if (master_gnt_i) begin
|
||||||
|
state_d = S_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// 等待读写完成
|
||||||
|
S_WAIT: begin
|
||||||
|
if (master_rvalid_i) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
if (sbautoincrement_i) begin
|
||||||
|
sbaddress = sbaddress_new;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: state_d = S_IDLE;
|
||||||
|
endcase
|
||||||
|
|
||||||
|
if ((sbaccess_i > 3'h2) & (state_q != S_IDLE)) begin
|
||||||
|
master_req = 1'b0;
|
||||||
|
state_d = S_IDLE;
|
||||||
|
sberror = 3'h3;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign master_req_o = master_req;
|
||||||
|
assign master_we_o = master_we;
|
||||||
|
assign master_be_o = master_be;
|
||||||
|
assign master_addr_o = master_addr;
|
||||||
|
assign master_wdata_o = master_wdata;
|
||||||
|
|
||||||
|
assign sbdata_valid_o = master_rvalid_i & (state_q == S_WAIT);
|
||||||
|
assign sbdata_o = master_rdata_i;
|
||||||
|
assign sberror_o = sberror;
|
||||||
|
assign sbaddress_o = sbaddress;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rst_n) begin
|
||||||
|
if (!rst_n) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
module jtag_tap #(
|
||||||
|
parameter DMI_ADDR_BITS = 7,
|
||||||
|
parameter DMI_DATA_BITS = 32,
|
||||||
|
parameter DMI_OP_BITS = 2,
|
||||||
|
parameter IR_BITS = 5,
|
||||||
|
parameter TAP_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
|
||||||
|
parameter DTM_RESP_BITS = TAP_REQ_BITS
|
||||||
|
)(
|
||||||
|
|
||||||
|
input wire jtag_tck_i, // JTAG test clock pad
|
||||||
|
input wire jtag_tdi_i, // JTAG test data input pad
|
||||||
|
input wire jtag_tms_i, // JTAG test mode select pad
|
||||||
|
input wire jtag_trst_ni, // JTAG test reset pad
|
||||||
|
output wire jtag_tdo_o, // JTAG test data output pad
|
||||||
|
|
||||||
|
output wire tap_req_o,
|
||||||
|
output wire[TAP_REQ_BITS-1:0] tap_data_o,
|
||||||
|
output wire dmireset_o,
|
||||||
|
|
||||||
|
input wire[DTM_RESP_BITS-1:0] dtm_data_i,
|
||||||
|
input wire[31:0] idcode_i,
|
||||||
|
input wire[31:0] dtmcs_i
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam SHIFT_REG_BITS = TAP_REQ_BITS;
|
||||||
|
|
||||||
|
localparam TEST_LOGIC_RESET = 16'h0001;
|
||||||
|
localparam RUN_TEST_IDLE = 16'h0002;
|
||||||
|
localparam SELECT_DR = 16'h0004;
|
||||||
|
localparam CAPTURE_DR = 16'h0008;
|
||||||
|
localparam SHIFT_DR = 16'h0010;
|
||||||
|
localparam EXIT1_DR = 16'h0020;
|
||||||
|
localparam PAUSE_DR = 16'h0040;
|
||||||
|
localparam EXIT2_DR = 16'h0080;
|
||||||
|
localparam UPDATE_DR = 16'h0100;
|
||||||
|
localparam SELECT_IR = 16'h0200;
|
||||||
|
localparam CAPTURE_IR = 16'h0400;
|
||||||
|
localparam SHIFT_IR = 16'h0800;
|
||||||
|
localparam EXIT1_IR = 16'h1000;
|
||||||
|
localparam PAUSE_IR = 16'h2000;
|
||||||
|
localparam EXIT2_IR = 16'h4000;
|
||||||
|
localparam UPDATE_IR = 16'h8000;
|
||||||
|
|
||||||
|
// DTM regs
|
||||||
|
localparam REG_BYPASS = 5'b11111;
|
||||||
|
localparam REG_IDCODE = 5'b00001;
|
||||||
|
localparam REG_DMI = 5'b10001;
|
||||||
|
localparam REG_DTMCS = 5'b10000;
|
||||||
|
|
||||||
|
reg[IR_BITS-1:0] ir_reg;
|
||||||
|
reg[SHIFT_REG_BITS-1:0] shift_reg;
|
||||||
|
|
||||||
|
reg[15:0] tap_state;
|
||||||
|
reg[15:0] next_state;
|
||||||
|
|
||||||
|
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
|
||||||
|
if (!jtag_trst_ni) begin
|
||||||
|
tap_state <= TEST_LOGIC_RESET;
|
||||||
|
end else begin
|
||||||
|
tap_state <= next_state;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// state switch
|
||||||
|
always @ (*) begin
|
||||||
|
case (tap_state)
|
||||||
|
TEST_LOGIC_RESET : next_state = jtag_tms_i ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
|
||||||
|
RUN_TEST_IDLE : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
|
||||||
|
SELECT_DR : next_state = jtag_tms_i ? SELECT_IR : CAPTURE_DR;
|
||||||
|
CAPTURE_DR : next_state = jtag_tms_i ? EXIT1_DR : SHIFT_DR;
|
||||||
|
SHIFT_DR : next_state = jtag_tms_i ? EXIT1_DR : SHIFT_DR;
|
||||||
|
EXIT1_DR : next_state = jtag_tms_i ? UPDATE_DR : PAUSE_DR;
|
||||||
|
PAUSE_DR : next_state = jtag_tms_i ? EXIT2_DR : PAUSE_DR;
|
||||||
|
EXIT2_DR : next_state = jtag_tms_i ? UPDATE_DR : SHIFT_DR;
|
||||||
|
UPDATE_DR : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
|
||||||
|
SELECT_IR : next_state = jtag_tms_i ? TEST_LOGIC_RESET : CAPTURE_IR;
|
||||||
|
CAPTURE_IR : next_state = jtag_tms_i ? EXIT1_IR : SHIFT_IR;
|
||||||
|
SHIFT_IR : next_state = jtag_tms_i ? EXIT1_IR : SHIFT_IR;
|
||||||
|
EXIT1_IR : next_state = jtag_tms_i ? UPDATE_IR : PAUSE_IR;
|
||||||
|
PAUSE_IR : next_state = jtag_tms_i ? EXIT2_IR : PAUSE_IR;
|
||||||
|
EXIT2_IR : next_state = jtag_tms_i ? UPDATE_IR : SHIFT_IR;
|
||||||
|
UPDATE_IR : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
|
||||||
|
default : next_state = TEST_LOGIC_RESET;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
// IR or DR shift
|
||||||
|
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
|
||||||
|
if (!jtag_trst_ni) begin
|
||||||
|
shift_reg <= {SHIFT_REG_BITS{1'b0}};
|
||||||
|
end else begin
|
||||||
|
case (tap_state)
|
||||||
|
// IR
|
||||||
|
CAPTURE_IR: shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}}, 1'b1}; //JTAG spec says it must be 2'b01
|
||||||
|
SHIFT_IR : shift_reg <= {{(SHIFT_REG_BITS-IR_BITS){1'b0}}, jtag_tdi_i, shift_reg[IR_BITS-1:1]}; // right shift 1 bit
|
||||||
|
// DR
|
||||||
|
CAPTURE_DR: case (ir_reg)
|
||||||
|
REG_BYPASS : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
|
||||||
|
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, idcode_i};
|
||||||
|
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, dtmcs_i};
|
||||||
|
REG_DMI : shift_reg <= dtm_data_i;
|
||||||
|
default : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
|
||||||
|
endcase
|
||||||
|
SHIFT_DR : case (ir_reg)
|
||||||
|
REG_BYPASS : shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}}, jtag_tdi_i}; // in = out
|
||||||
|
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, jtag_tdi_i, shift_reg[31:1]}; // right shift 1 bit
|
||||||
|
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, jtag_tdi_i, shift_reg[31:1]}; // right shift 1 bit
|
||||||
|
REG_DMI : shift_reg <= {jtag_tdi_i, shift_reg[SHIFT_REG_BITS-1:1]}; // right shift 1 bit
|
||||||
|
default : shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}} , jtag_tdi_i};
|
||||||
|
endcase
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg tap_req_q;
|
||||||
|
reg[TAP_REQ_BITS-1:0] tap_data_q;
|
||||||
|
|
||||||
|
// send request to DTM module
|
||||||
|
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
|
||||||
|
if (!jtag_trst_ni) begin
|
||||||
|
tap_req_q <= 1'b0;
|
||||||
|
tap_data_q <= {TAP_REQ_BITS{1'b0}};
|
||||||
|
end else begin
|
||||||
|
if ((tap_state == UPDATE_DR) && (ir_reg == REG_DMI)) begin
|
||||||
|
tap_req_q <= 1'b1;
|
||||||
|
tap_data_q <= shift_reg;
|
||||||
|
end else begin
|
||||||
|
tap_req_q <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign tap_req_o = tap_req_q;
|
||||||
|
assign tap_data_o = tap_data_q;
|
||||||
|
|
||||||
|
// ir_reg
|
||||||
|
always @ (negedge jtag_tck_i) begin
|
||||||
|
if (tap_state == TEST_LOGIC_RESET) begin
|
||||||
|
ir_reg <= REG_IDCODE;
|
||||||
|
end else if (tap_state == UPDATE_IR) begin
|
||||||
|
ir_reg <= shift_reg[IR_BITS-1:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg jtag_tdo_q;
|
||||||
|
|
||||||
|
// TDO output
|
||||||
|
always @ (negedge jtag_tck_i) begin
|
||||||
|
if ((tap_state == SHIFT_IR) || (tap_state == SHIFT_DR)) begin
|
||||||
|
jtag_tdo_q <= shift_reg[0];
|
||||||
|
end else begin
|
||||||
|
jtag_tdo_q <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign jtag_tdo_o = jtag_tdo_q;
|
||||||
|
|
||||||
|
reg dmireset_q;
|
||||||
|
|
||||||
|
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
|
||||||
|
if (!jtag_trst_ni) begin
|
||||||
|
dmireset_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
if ((tap_state == UPDATE_DR) && (ir_reg == REG_DTMCS)) begin
|
||||||
|
dmireset_q <= shift_reg[16];
|
||||||
|
end else begin
|
||||||
|
dmireset_q <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign dmireset_o = dmireset_q;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
module jtag_top(
|
||||||
|
|
||||||
|
input wire clk_i,
|
||||||
|
input wire rst_ni,
|
||||||
|
|
||||||
|
output wire debug_req_o,
|
||||||
|
output wire ndmreset_o,
|
||||||
|
output wire halted_o,
|
||||||
|
|
||||||
|
input wire jtag_tck_i, // JTAG test clock pad
|
||||||
|
input wire jtag_tdi_i, // JTAG test data input pad
|
||||||
|
input wire jtag_tms_i, // JTAG test mode select pad
|
||||||
|
input wire jtag_trst_ni, // JTAG test reset pad
|
||||||
|
output wire jtag_tdo_o, // JTAG test data output pad
|
||||||
|
|
||||||
|
output wire master_req_o,
|
||||||
|
input wire master_gnt_i,
|
||||||
|
input wire master_rvalid_i,
|
||||||
|
output wire master_we_o,
|
||||||
|
output wire [3:0] master_be_o,
|
||||||
|
output wire [31:0] master_addr_o,
|
||||||
|
output wire [31:0] master_wdata_o,
|
||||||
|
input wire [31:0] master_rdata_i,
|
||||||
|
input wire master_err_i,
|
||||||
|
|
||||||
|
input wire slave_req_i,
|
||||||
|
input wire slave_we_i,
|
||||||
|
input wire [31:0] slave_addr_i,
|
||||||
|
input wire [3:0] slave_be_i,
|
||||||
|
input wire [31:0] slave_wdata_i,
|
||||||
|
output wire slave_gnt_o,
|
||||||
|
output wire slave_rvalid_o,
|
||||||
|
output wire [31:0] slave_rdata_o
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
// addr + data + op = 7 + 32 + 2 = 41
|
||||||
|
localparam DMI_DATA_WIDTH = 41;
|
||||||
|
|
||||||
|
|
||||||
|
wire [DMI_DATA_WIDTH-1:0] dm_to_dmi_data;
|
||||||
|
wire dm_to_dmi_valid;
|
||||||
|
wire dm_to_dmi_ready;
|
||||||
|
wire [DMI_DATA_WIDTH-1:0] dmi_to_dm_data;
|
||||||
|
wire dmi_to_dm_valid;
|
||||||
|
wire dmi_to_dm_ready;
|
||||||
|
|
||||||
|
jtag_dm #(
|
||||||
|
|
||||||
|
) u_jtag_dm (
|
||||||
|
.clk (clk_i),
|
||||||
|
.rst_n (rst_ni),
|
||||||
|
.dmi_data_i (dmi_to_dm_data),
|
||||||
|
.dmi_valid_i (dmi_to_dm_valid),
|
||||||
|
.dm_ready_o (dm_to_dmi_ready),
|
||||||
|
.dm_data_o (dm_to_dmi_data),
|
||||||
|
.dm_valid_o (dm_to_dmi_valid),
|
||||||
|
.dmi_ready_i (dmi_to_dm_ready),
|
||||||
|
.debug_req_o (debug_req_o),
|
||||||
|
.ndmreset_o (ndmreset_o),
|
||||||
|
.halted_o (halted_o),
|
||||||
|
.master_req_o (master_req_o),
|
||||||
|
.master_gnt_i (master_gnt_i),
|
||||||
|
.master_rvalid_i(master_rvalid_i),
|
||||||
|
.master_we_o (master_we_o),
|
||||||
|
.master_be_o (master_be_o),
|
||||||
|
.master_addr_o (master_addr_o),
|
||||||
|
.master_wdata_o (master_wdata_o),
|
||||||
|
.master_rdata_i (master_rdata_i),
|
||||||
|
.master_err_i (master_err_i),
|
||||||
|
.slave_req_i (slave_req_i),
|
||||||
|
.slave_we_i (slave_we_i),
|
||||||
|
.slave_addr_i (slave_addr_i),
|
||||||
|
.slave_be_i (slave_be_i),
|
||||||
|
.slave_wdata_i (slave_wdata_i),
|
||||||
|
.slave_gnt_o (slave_gnt_o),
|
||||||
|
.slave_rvalid_o (slave_rvalid_o),
|
||||||
|
.slave_rdata_o (slave_rdata_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
wire [DMI_DATA_WIDTH-1:0] dtm_to_dmi_data;
|
||||||
|
wire dtm_to_dmi_valid;
|
||||||
|
wire dtm_to_dmi_ready;
|
||||||
|
wire [DMI_DATA_WIDTH-1:0] dmi_to_dtm_data;
|
||||||
|
wire dmi_to_dtm_valid;
|
||||||
|
wire dmi_to_dtm_ready;
|
||||||
|
|
||||||
|
jtag_dmi #(
|
||||||
|
|
||||||
|
) u_jtag_dmi (
|
||||||
|
.jtag_tck_i (jtag_tck_i),
|
||||||
|
.jtag_trst_ni (jtag_trst_ni),
|
||||||
|
.jtag_data_i (dtm_to_dmi_data),
|
||||||
|
.jtag_valid_i (dtm_to_dmi_valid),
|
||||||
|
.jtag_ready_o (dmi_to_dtm_ready),
|
||||||
|
.jtag_data_o (dmi_to_dtm_data),
|
||||||
|
.jtag_valid_o (dmi_to_dtm_valid),
|
||||||
|
.jtag_ready_i (dtm_to_dmi_ready),
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.core_data_i (dm_to_dmi_data),
|
||||||
|
.core_valid_i (dm_to_dmi_valid),
|
||||||
|
.core_ready_o (dmi_to_dm_ready),
|
||||||
|
.core_data_o (dmi_to_dm_data),
|
||||||
|
.core_valid_o (dmi_to_dm_valid),
|
||||||
|
.core_ready_i (dm_to_dmi_ready)
|
||||||
|
);
|
||||||
|
|
||||||
|
wire tap_to_dtm_req;
|
||||||
|
wire [DMI_DATA_WIDTH-1:0] tap_to_dtm_data;
|
||||||
|
wire [DMI_DATA_WIDTH-1:0] dtm_to_tap_data;
|
||||||
|
wire [31:0] idcode;
|
||||||
|
wire [31:0] dtmcs;
|
||||||
|
wire dmireset;
|
||||||
|
|
||||||
|
jtag_dtm #(
|
||||||
|
|
||||||
|
) u_jtag_dtm (
|
||||||
|
.jtag_tck_i (jtag_tck_i),
|
||||||
|
.jtag_trst_ni (jtag_trst_ni),
|
||||||
|
.dtm_data_o (dtm_to_dmi_data),
|
||||||
|
.dtm_valid_o (dtm_to_dmi_valid),
|
||||||
|
.dmi_ready_i (dmi_to_dtm_ready),
|
||||||
|
.dmi_data_i (dmi_to_dtm_data),
|
||||||
|
.dmi_valid_i (dmi_to_dtm_valid),
|
||||||
|
.dtm_ready_o (dtm_to_dmi_ready),
|
||||||
|
.tap_req_i (tap_to_dtm_req),
|
||||||
|
.tap_data_i (tap_to_dtm_data),
|
||||||
|
.dmireset_i (dmireset),
|
||||||
|
.data_o (dtm_to_tap_data),
|
||||||
|
.idcode_o (idcode),
|
||||||
|
.dtmcs_o (dtmcs)
|
||||||
|
);
|
||||||
|
|
||||||
|
jtag_tap #(
|
||||||
|
|
||||||
|
) u_jtag_tap (
|
||||||
|
.jtag_tck_i (jtag_tck_i),
|
||||||
|
.jtag_tdi_i (jtag_tdi_i),
|
||||||
|
.jtag_tms_i (jtag_tms_i),
|
||||||
|
.jtag_trst_ni (jtag_trst_ni),
|
||||||
|
.jtag_tdo_o (jtag_tdo_o),
|
||||||
|
.tap_req_o (tap_to_dtm_req),
|
||||||
|
.tap_data_o (tap_to_dtm_data),
|
||||||
|
.dmireset_o (dmireset),
|
||||||
|
.dtm_data_i (dtm_to_tap_data),
|
||||||
|
.idcode_i (idcode),
|
||||||
|
.dtmcs_i (dtmcs)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "../core/defines.v"
|
|
||||||
|
|
||||||
// JTAG顶层模块
|
|
||||||
module jtag_top #(
|
|
||||||
parameter DMI_ADDR_BITS = 6,
|
|
||||||
parameter DMI_DATA_BITS = 32,
|
|
||||||
parameter DMI_OP_BITS = 2)(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire jtag_rst_n,
|
|
||||||
|
|
||||||
input wire jtag_pin_TCK,
|
|
||||||
input wire jtag_pin_TMS,
|
|
||||||
input wire jtag_pin_TDI,
|
|
||||||
output wire jtag_pin_TDO,
|
|
||||||
|
|
||||||
output wire reg_we_o,
|
|
||||||
output wire[4:0] reg_addr_o,
|
|
||||||
output wire[31:0] reg_wdata_o,
|
|
||||||
input wire[31:0] reg_rdata_i,
|
|
||||||
output wire mem_we_o,
|
|
||||||
output wire[31:0] mem_addr_o,
|
|
||||||
output wire[31:0] mem_wdata_o,
|
|
||||||
input wire[31:0] mem_rdata_i,
|
|
||||||
output wire op_req_o,
|
|
||||||
|
|
||||||
output wire halt_req_o,
|
|
||||||
output wire reset_req_o
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
|
||||||
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
|
||||||
|
|
||||||
// jtag_driver
|
|
||||||
wire dtm_ack_o;
|
|
||||||
wire dtm_req_valid_o;
|
|
||||||
wire[DTM_REQ_BITS - 1:0] dtm_req_data_o;
|
|
||||||
|
|
||||||
// jtag_dm
|
|
||||||
wire dm_ack_o;
|
|
||||||
wire[DM_RESP_BITS-1:0] dm_resp_data_o;
|
|
||||||
wire dm_resp_valid_o;
|
|
||||||
wire dm_op_req_o;
|
|
||||||
wire dm_halt_req_o;
|
|
||||||
wire dm_reset_req_o;
|
|
||||||
|
|
||||||
jtag_driver #(
|
|
||||||
.DMI_ADDR_BITS(DMI_ADDR_BITS),
|
|
||||||
.DMI_DATA_BITS(DMI_DATA_BITS),
|
|
||||||
.DMI_OP_BITS(DMI_OP_BITS)
|
|
||||||
) u_jtag_driver(
|
|
||||||
.rst_n(jtag_rst_n),
|
|
||||||
.jtag_TCK(jtag_pin_TCK),
|
|
||||||
.jtag_TDI(jtag_pin_TDI),
|
|
||||||
.jtag_TMS(jtag_pin_TMS),
|
|
||||||
.jtag_TDO(jtag_pin_TDO),
|
|
||||||
.dm_resp_i(dm_resp_valid_o),
|
|
||||||
.dm_resp_data_i(dm_resp_data_o),
|
|
||||||
.dtm_ack_o(dtm_ack_o),
|
|
||||||
.dm_ack_i(dm_ack_o),
|
|
||||||
.dtm_req_valid_o(dtm_req_valid_o),
|
|
||||||
.dtm_req_data_o(dtm_req_data_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
jtag_dm #(
|
|
||||||
.DMI_ADDR_BITS(DMI_ADDR_BITS),
|
|
||||||
.DMI_DATA_BITS(DMI_DATA_BITS),
|
|
||||||
.DMI_OP_BITS(DMI_OP_BITS)
|
|
||||||
) u_jtag_dm(
|
|
||||||
.clk(clk),
|
|
||||||
.rst_n(jtag_rst_n),
|
|
||||||
.dm_ack_o(dm_ack_o),
|
|
||||||
.dtm_req_valid_i(dtm_req_valid_o),
|
|
||||||
.dtm_req_data_i(dtm_req_data_o),
|
|
||||||
.dtm_ack_i(dtm_ack_o),
|
|
||||||
.dm_resp_data_o(dm_resp_data_o),
|
|
||||||
.dm_resp_valid_o(dm_resp_valid_o),
|
|
||||||
.dm_reg_we_o(reg_we_o),
|
|
||||||
.dm_reg_addr_o(reg_addr_o),
|
|
||||||
.dm_reg_wdata_o(reg_wdata_o),
|
|
||||||
.dm_reg_rdata_i(reg_rdata_i),
|
|
||||||
.dm_mem_we_o(mem_we_o),
|
|
||||||
.dm_mem_addr_o(mem_addr_o),
|
|
||||||
.dm_mem_wdata_o(mem_wdata_o),
|
|
||||||
.dm_mem_rdata_i(mem_rdata_i),
|
|
||||||
.dm_op_req_o(op_req_o),
|
|
||||||
.dm_halt_req_o(halt_req_o),
|
|
||||||
.dm_reset_req_o(reset_req_o)
|
|
||||||
);
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -1,436 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// clk = 50MHz时对应的波特率分频系数
|
|
||||||
`define UART_BAUD_115200 32'h1B8
|
|
||||||
|
|
||||||
// 串口寄存器地址
|
|
||||||
`define UART_CTRL_REG 32'h30000000
|
|
||||||
`define UART_STATUS_REG 32'h30000004
|
|
||||||
`define UART_BAUD_REG 32'h30000008
|
|
||||||
`define UART_TX_REG 32'h3000000c
|
|
||||||
`define UART_RX_REG 32'h30000010
|
|
||||||
|
|
||||||
`define UART_TX_BUSY_FLAG 32'h1
|
|
||||||
`define UART_RX_OVER_FLAG 32'h2
|
|
||||||
|
|
||||||
// 第一个包的大小
|
|
||||||
`define UART_FIRST_PACKET_LEN 8'd131
|
|
||||||
// 其他包的大小(每次烧写的字节数)
|
|
||||||
`define UART_REMAIN_PACKET_LEN 8'd131
|
|
||||||
|
|
||||||
`define UART_RESP_ACK 32'h6
|
|
||||||
`define UART_RESP_NAK 32'h15
|
|
||||||
|
|
||||||
// 烧写起始地址
|
|
||||||
`define ROM_START_ADDR 32'h0
|
|
||||||
|
|
||||||
|
|
||||||
// 串口更新固件模块
|
|
||||||
module uart_debug(
|
|
||||||
|
|
||||||
input wire clk, // 时钟信号
|
|
||||||
input wire rst, // 复位信号
|
|
||||||
|
|
||||||
input wire debug_en_i, // 模块使能信号
|
|
||||||
|
|
||||||
output wire req_o,
|
|
||||||
output reg mem_we_o,
|
|
||||||
output reg[31:0] mem_addr_o,
|
|
||||||
output reg[31:0] mem_wdata_o,
|
|
||||||
input wire[31:0] mem_rdata_i
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// 状态
|
|
||||||
localparam S_IDLE = 14'h0001;
|
|
||||||
localparam S_INIT_UART_BAUD = 14'h0002;
|
|
||||||
localparam S_CLEAR_UART_RX_OVER_FLAG = 14'h0004;
|
|
||||||
localparam S_WAIT_BYTE = 14'h0008;
|
|
||||||
localparam S_WAIT_BYTE2 = 14'h0010;
|
|
||||||
localparam S_GET_BYTE = 14'h0020;
|
|
||||||
localparam S_REC_FIRST_PACKET = 14'h0040;
|
|
||||||
localparam S_REC_REMAIN_PACKET = 14'h0080;
|
|
||||||
localparam S_SEND_ACK = 14'h0100;
|
|
||||||
localparam S_SEND_NAK = 14'h0200;
|
|
||||||
localparam S_CRC_START = 14'h0400;
|
|
||||||
localparam S_CRC_CALC = 14'h0800;
|
|
||||||
localparam S_CRC_END = 14'h1000;
|
|
||||||
localparam S_WRITE_MEM = 14'h2000;
|
|
||||||
|
|
||||||
reg[13:0] state;
|
|
||||||
|
|
||||||
// 存放串口接收到的数据
|
|
||||||
reg[7:0] rx_data[0:131];
|
|
||||||
reg[7:0] rec_bytes_index;
|
|
||||||
reg[7:0] need_to_rec_bytes;
|
|
||||||
reg[15:0] remain_packet_count;
|
|
||||||
reg[31:0] fw_file_size;
|
|
||||||
reg[31:0] write_mem_addr;
|
|
||||||
reg[31:0] write_mem_data;
|
|
||||||
reg[7:0] write_mem_byte_index0;
|
|
||||||
reg[7:0] write_mem_byte_index1;
|
|
||||||
reg[7:0] write_mem_byte_index2;
|
|
||||||
reg[7:0] write_mem_byte_index3;
|
|
||||||
|
|
||||||
reg[15:0] crc_result;
|
|
||||||
reg[3:0] crc_bit_index;
|
|
||||||
reg[7:0] crc_byte_index;
|
|
||||||
|
|
||||||
|
|
||||||
// 向总线请求信号
|
|
||||||
assign req_o = (rst == 1'b1 && debug_en_i == 1'b1)? 1'b1: 1'b0;
|
|
||||||
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
mem_addr_o <= 32'h0;
|
|
||||||
mem_we_o <= 1'b0;
|
|
||||||
mem_wdata_o <= 32'h0;
|
|
||||||
state <= S_IDLE;
|
|
||||||
remain_packet_count <= 16'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_IDLE: begin
|
|
||||||
mem_addr_o <= `UART_CTRL_REG;
|
|
||||||
mem_wdata_o <= 32'h3;
|
|
||||||
mem_we_o <= 1'b1;
|
|
||||||
state <= S_INIT_UART_BAUD;
|
|
||||||
end
|
|
||||||
S_INIT_UART_BAUD: begin
|
|
||||||
mem_addr_o <= `UART_BAUD_REG;
|
|
||||||
mem_wdata_o <= `UART_BAUD_115200;
|
|
||||||
mem_we_o <= 1'b1;
|
|
||||||
state <= S_REC_FIRST_PACKET;
|
|
||||||
end
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
remain_packet_count <= 16'h0;
|
|
||||||
mem_addr_o <= 32'h0;
|
|
||||||
mem_we_o <= 1'b0;
|
|
||||||
mem_wdata_o <= 32'h0;
|
|
||||||
state <= S_CLEAR_UART_RX_OVER_FLAG;
|
|
||||||
end
|
|
||||||
S_REC_REMAIN_PACKET: begin
|
|
||||||
mem_addr_o <= 32'h0;
|
|
||||||
mem_we_o <= 1'b0;
|
|
||||||
mem_wdata_o <= 32'h0;
|
|
||||||
state <= S_CLEAR_UART_RX_OVER_FLAG;
|
|
||||||
end
|
|
||||||
S_CLEAR_UART_RX_OVER_FLAG: begin
|
|
||||||
mem_addr_o <= `UART_STATUS_REG;
|
|
||||||
mem_wdata_o <= 32'h0;
|
|
||||||
mem_we_o <= 1'b1;
|
|
||||||
state <= S_WAIT_BYTE;
|
|
||||||
end
|
|
||||||
S_WAIT_BYTE: begin
|
|
||||||
mem_addr_o <= `UART_STATUS_REG;
|
|
||||||
mem_wdata_o <= 32'h0;
|
|
||||||
mem_we_o <= 1'b0;
|
|
||||||
state <= S_WAIT_BYTE2;
|
|
||||||
end
|
|
||||||
S_WAIT_BYTE2: begin
|
|
||||||
if ((mem_rdata_i & `UART_RX_OVER_FLAG) == `UART_RX_OVER_FLAG) begin
|
|
||||||
mem_addr_o <= `UART_RX_REG;
|
|
||||||
mem_wdata_o <= 32'h0;
|
|
||||||
mem_we_o <= 1'b0;
|
|
||||||
state <= S_GET_BYTE;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S_GET_BYTE: begin
|
|
||||||
if (rec_bytes_index == (need_to_rec_bytes - 1'b1)) begin
|
|
||||||
state <= S_CRC_START;
|
|
||||||
end else begin
|
|
||||||
state <= S_CLEAR_UART_RX_OVER_FLAG;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S_CRC_START: begin
|
|
||||||
state <= S_CRC_CALC;
|
|
||||||
end
|
|
||||||
S_CRC_CALC: begin
|
|
||||||
if ((crc_byte_index == need_to_rec_bytes - 2) && crc_bit_index == 4'h8) begin
|
|
||||||
state <= S_CRC_END;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S_CRC_END: begin
|
|
||||||
if (crc_result == {rx_data[need_to_rec_bytes - 1], rx_data[need_to_rec_bytes - 2]}) begin
|
|
||||||
if (need_to_rec_bytes == `UART_FIRST_PACKET_LEN && remain_packet_count == 16'h0) begin
|
|
||||||
remain_packet_count <= {7'h0, fw_file_size[31:7]} + 1'b1;
|
|
||||||
state <= S_SEND_ACK;
|
|
||||||
end else begin
|
|
||||||
remain_packet_count <= remain_packet_count - 1'b1;
|
|
||||||
state <= S_WRITE_MEM;
|
|
||||||
end
|
|
||||||
end else begin
|
|
||||||
state <= S_SEND_NAK;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S_WRITE_MEM: begin
|
|
||||||
if (write_mem_byte_index0 == (need_to_rec_bytes + 2)) begin
|
|
||||||
state <= S_SEND_ACK;
|
|
||||||
end else begin
|
|
||||||
mem_addr_o <= write_mem_addr;
|
|
||||||
mem_wdata_o <= write_mem_data;
|
|
||||||
mem_we_o <= 1'b1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S_SEND_ACK: begin
|
|
||||||
mem_addr_o <= `UART_TX_REG;
|
|
||||||
mem_wdata_o <= `UART_RESP_ACK;
|
|
||||||
mem_we_o <= 1'b1;
|
|
||||||
if (remain_packet_count > 0) begin
|
|
||||||
state <= S_REC_REMAIN_PACKET;
|
|
||||||
end else begin
|
|
||||||
state <= S_REC_FIRST_PACKET;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S_SEND_NAK: begin
|
|
||||||
mem_addr_o <= `UART_TX_REG;
|
|
||||||
mem_wdata_o <= `UART_RESP_NAK;
|
|
||||||
mem_we_o <= 1'b1;
|
|
||||||
if (remain_packet_count > 0) begin
|
|
||||||
state <= S_REC_REMAIN_PACKET;
|
|
||||||
end else begin
|
|
||||||
state <= S_REC_FIRST_PACKET;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 数据包的大小
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
need_to_rec_bytes <= 8'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
need_to_rec_bytes <= `UART_FIRST_PACKET_LEN;
|
|
||||||
end
|
|
||||||
S_REC_REMAIN_PACKET: begin
|
|
||||||
need_to_rec_bytes <= `UART_REMAIN_PACKET_LEN;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 读接收到的串口数据
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
rec_bytes_index <= 8'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_GET_BYTE: begin
|
|
||||||
rx_data[rec_bytes_index] <= mem_rdata_i[7:0];
|
|
||||||
rec_bytes_index <= rec_bytes_index + 1'b1;
|
|
||||||
end
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
rec_bytes_index <= 8'h0;
|
|
||||||
end
|
|
||||||
S_REC_REMAIN_PACKET: begin
|
|
||||||
rec_bytes_index <= 8'h0;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 固件大小
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
fw_file_size <= 32'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_CRC_START: begin
|
|
||||||
fw_file_size <= {rx_data[61], rx_data[62], rx_data[63], rx_data[64]};
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 烧写固件
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
write_mem_addr <= 32'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
write_mem_addr <= `ROM_START_ADDR;
|
|
||||||
end
|
|
||||||
S_CRC_END: begin
|
|
||||||
if (write_mem_addr > 0)
|
|
||||||
write_mem_addr <= write_mem_addr - 4;
|
|
||||||
end
|
|
||||||
S_WRITE_MEM: begin
|
|
||||||
write_mem_addr <= write_mem_addr + 4;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
write_mem_data <= 32'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
write_mem_data <= 32'h0;
|
|
||||||
end
|
|
||||||
S_CRC_END: begin
|
|
||||||
write_mem_data <= {rx_data[4], rx_data[3], rx_data[2], rx_data[1]};
|
|
||||||
end
|
|
||||||
S_WRITE_MEM: begin
|
|
||||||
write_mem_data <= {rx_data[write_mem_byte_index3], rx_data[write_mem_byte_index2], rx_data[write_mem_byte_index1], rx_data[write_mem_byte_index0]};
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
write_mem_byte_index0 <= 8'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
write_mem_byte_index0 <= 8'h0;
|
|
||||||
end
|
|
||||||
S_CRC_END: begin
|
|
||||||
write_mem_byte_index0 <= 8'h5;
|
|
||||||
end
|
|
||||||
S_WRITE_MEM: begin
|
|
||||||
write_mem_byte_index0 <= write_mem_byte_index0 + 4;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
write_mem_byte_index1 <= 8'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
write_mem_byte_index1 <= 8'h0;
|
|
||||||
end
|
|
||||||
S_CRC_END: begin
|
|
||||||
write_mem_byte_index1 <= 8'h6;
|
|
||||||
end
|
|
||||||
S_WRITE_MEM: begin
|
|
||||||
write_mem_byte_index1 <= write_mem_byte_index1 + 4;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
write_mem_byte_index2 <= 8'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
write_mem_byte_index2 <= 8'h0;
|
|
||||||
end
|
|
||||||
S_CRC_END: begin
|
|
||||||
write_mem_byte_index2 <= 8'h7;
|
|
||||||
end
|
|
||||||
S_WRITE_MEM: begin
|
|
||||||
write_mem_byte_index2 <= write_mem_byte_index2 + 4;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
write_mem_byte_index3 <= 8'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_REC_FIRST_PACKET: begin
|
|
||||||
write_mem_byte_index3 <= 8'h0;
|
|
||||||
end
|
|
||||||
S_CRC_END: begin
|
|
||||||
write_mem_byte_index3 <= 8'h8;
|
|
||||||
end
|
|
||||||
S_WRITE_MEM: begin
|
|
||||||
write_mem_byte_index3 <= write_mem_byte_index3 + 4;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// CRC计算
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
crc_result <= 16'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_CRC_START: begin
|
|
||||||
crc_result <= 16'hffff;
|
|
||||||
end
|
|
||||||
S_CRC_CALC: begin
|
|
||||||
if (crc_bit_index == 4'h0) begin
|
|
||||||
crc_result <= crc_result ^ rx_data[crc_byte_index];
|
|
||||||
end else begin
|
|
||||||
if (crc_bit_index < 4'h9) begin
|
|
||||||
if (crc_result[0] == 1'b1) begin
|
|
||||||
crc_result <= {1'b0, crc_result[15:1]} ^ 16'ha001;
|
|
||||||
end else begin
|
|
||||||
crc_result <= {1'b0, crc_result[15:1]};
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
crc_bit_index <= 4'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_CRC_START: begin
|
|
||||||
crc_bit_index <= 4'h0;
|
|
||||||
end
|
|
||||||
S_CRC_CALC: begin
|
|
||||||
if (crc_bit_index < 4'h9) begin
|
|
||||||
crc_bit_index <= crc_bit_index + 1'b1;
|
|
||||||
end else begin
|
|
||||||
crc_bit_index <= 4'h0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0 || debug_en_i == 1'b0) begin
|
|
||||||
crc_byte_index <= 8'h0;
|
|
||||||
end else begin
|
|
||||||
case (state)
|
|
||||||
S_CRC_START: begin
|
|
||||||
crc_byte_index <= 8'h1;
|
|
||||||
end
|
|
||||||
S_CRC_CALC: begin
|
|
||||||
if (crc_bit_index == 4'h0) begin
|
|
||||||
crc_byte_index <= crc_byte_index + 1'b1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
module bootrom_top(
|
||||||
|
input wire clk_i,
|
||||||
|
input wire rst_ni,
|
||||||
|
|
||||||
|
input wire req_i,
|
||||||
|
input wire we_i,
|
||||||
|
input wire [ 3:0] be_i,
|
||||||
|
input wire [31:0] addr_i,
|
||||||
|
input wire [31:0] data_i,
|
||||||
|
output wire gnt_o,
|
||||||
|
output wire rvalid_o,
|
||||||
|
output wire [31:0] data_o
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam RomSize = 5;
|
||||||
|
|
||||||
|
wire [RomSize-1:0][31:0] mem;
|
||||||
|
|
||||||
|
assign mem = {
|
||||||
|
32'h0000006f,
|
||||||
|
32'h000500e7,
|
||||||
|
32'h02000537,
|
||||||
|
32'h0005a023,
|
||||||
|
32'h02c005b7
|
||||||
|
};
|
||||||
|
|
||||||
|
reg [5:0] addr_q;
|
||||||
|
|
||||||
|
always @(posedge clk_i) begin
|
||||||
|
if (req_i) begin
|
||||||
|
addr_q <= addr_i[7:2];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg rvalid_q;
|
||||||
|
|
||||||
|
always @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
rvalid_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
rvalid_q <= req_i;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg[31:0] rdata;
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
rdata = 32'h0;
|
||||||
|
if (addr_q < 6'd38) begin
|
||||||
|
rdata = mem[addr_q];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign gnt_o = req_i;
|
||||||
|
assign data_o = rdata;
|
||||||
|
assign rvalid_o = rvalid_q;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// GPIO模块
|
|
||||||
module gpio(
|
|
||||||
|
|
||||||
input wire clk,
|
|
||||||
input wire rst,
|
|
||||||
|
|
||||||
input wire we_i,
|
|
||||||
input wire[31:0] addr_i,
|
|
||||||
input wire[31:0] data_i,
|
|
||||||
|
|
||||||
output reg[31:0] data_o,
|
|
||||||
|
|
||||||
input wire[1:0] io_pin_i,
|
|
||||||
output wire[31:0] reg_ctrl,
|
|
||||||
output wire[31:0] reg_data
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// GPIO控制寄存器
|
|
||||||
localparam GPIO_CTRL = 4'h0;
|
|
||||||
// GPIO数据寄存器
|
|
||||||
localparam GPIO_DATA = 4'h4;
|
|
||||||
|
|
||||||
// 每2位控制1个IO的模式,最多支持16个IO
|
|
||||||
// 0: 高阻,1:输出,2:输入
|
|
||||||
reg[31:0] gpio_ctrl;
|
|
||||||
// 输入输出数据
|
|
||||||
reg[31:0] gpio_data;
|
|
||||||
|
|
||||||
|
|
||||||
assign reg_ctrl = gpio_ctrl;
|
|
||||||
assign reg_data = gpio_data;
|
|
||||||
|
|
||||||
|
|
||||||
// 写寄存器
|
|
||||||
always @ (posedge clk) begin
|
|
||||||
if (rst == 1'b0) begin
|
|
||||||
gpio_data <= 32'h0;
|
|
||||||
gpio_ctrl <= 32'h0;
|
|
||||||
end else begin
|
|
||||||
if (we_i == 1'b1) begin
|
|
||||||
case (addr_i[3:0])
|
|
||||||
GPIO_CTRL: begin
|
|
||||||
gpio_ctrl <= data_i;
|
|
||||||
end
|
|
||||||
GPIO_DATA: begin
|
|
||||||
gpio_data <= data_i;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end else begin
|
|
||||||
if (gpio_ctrl[1:0] == 2'b10) begin
|
|
||||||
gpio_data[0] <= io_pin_i[0];
|
|
||||||
end
|
|
||||||
if (gpio_ctrl[3:2] == 2'b10) begin
|
|
||||||
gpio_data[1] <= io_pin_i[1];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// 读寄存器
|
|
||||||
always @ (*) begin
|
|
||||||
if (rst == 1'b0) begin
|
|
||||||
data_o = 32'h0;
|
|
||||||
end else begin
|
|
||||||
case (addr_i[3:0])
|
|
||||||
GPIO_CTRL: begin
|
|
||||||
data_o = gpio_ctrl;
|
|
||||||
end
|
|
||||||
GPIO_DATA: begin
|
|
||||||
data_o = gpio_data;
|
|
||||||
end
|
|
||||||
default: begin
|
|
||||||
data_o = 32'h0;
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
{ name: "gpio",
|
||||||
|
clocking: [{clock: "clk_i", reset: "rst_ni"}],
|
||||||
|
bus_interfaces: [
|
||||||
|
{ protocol: "tlul", direction: "device" }
|
||||||
|
],
|
||||||
|
regwidth: "32",
|
||||||
|
registers: [
|
||||||
|
{ name: "IO_MODE",
|
||||||
|
desc: "gpio input/output mode register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hro",
|
||||||
|
fields: [
|
||||||
|
{ bits: "31:0",
|
||||||
|
desc: "gpio input or output mode, 2 bits for each gpio",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "INT_MODE",
|
||||||
|
desc: "gpio interrupt mode register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hro",
|
||||||
|
fields: [
|
||||||
|
{ bits: "31:0",
|
||||||
|
desc: "gpio interrupt mode, 2 bits for each gpio",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "INT_PENDING",
|
||||||
|
desc: "gpio interrupt pending register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
fields: [
|
||||||
|
{ bits: "15:0",
|
||||||
|
name: "GPIO_INT_PENDING",
|
||||||
|
swaccess: "rw1c",
|
||||||
|
desc: "gpio interrupt pending, 1 bits for each gpio",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "DATA",
|
||||||
|
desc: "gpio data register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
fields: [
|
||||||
|
{ bits: "15:0",
|
||||||
|
desc: "gpio input or output data, 1 bits for each gpio",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "FILTER",
|
||||||
|
desc: "gpio input filter enable register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hro",
|
||||||
|
fields: [
|
||||||
|
{ bits: "15:0",
|
||||||
|
desc: "gpio input filter enable, 1 bits for each gpio",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 目前最多支持16个GPIO
|
||||||
|
module gpio_core #(
|
||||||
|
parameter int GPIO_NUM = 2
|
||||||
|
)(
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
output logic [GPIO_NUM-1:0] gpio_oe_o,
|
||||||
|
output logic [GPIO_NUM-1:0] gpio_data_o,
|
||||||
|
input logic [GPIO_NUM-1:0] gpio_data_i,
|
||||||
|
output logic irq_gpio0_o,
|
||||||
|
output logic irq_gpio1_o,
|
||||||
|
output logic irq_gpio2_4_o,
|
||||||
|
output logic irq_gpio5_7_o,
|
||||||
|
output logic irq_gpio8_o,
|
||||||
|
output logic irq_gpio9_o,
|
||||||
|
output logic irq_gpio10_12_o,
|
||||||
|
output logic irq_gpio13_15_o,
|
||||||
|
|
||||||
|
input logic reg_we_i,
|
||||||
|
input logic reg_re_i,
|
||||||
|
input logic [31:0] reg_wdata_i,
|
||||||
|
input logic [ 3:0] reg_be_i,
|
||||||
|
input logic [31:0] reg_addr_i,
|
||||||
|
output logic [31:0] reg_rdata_o
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam logic [1:0] INTR_MODE_NONE = 2'd0;
|
||||||
|
localparam logic [1:0] INTR_MODE_RAISE_EDGE = 2'd1;
|
||||||
|
localparam logic [1:0] INTR_MODE_FALL_EDGE = 2'd2;
|
||||||
|
localparam logic [1:0] INTR_MODE_DOUBLE_EDGE = 2'd3;
|
||||||
|
|
||||||
|
localparam logic [1:0] GPIO_MODE_NONE = 2'd0;
|
||||||
|
localparam logic [1:0] GPIO_MODE_INPUT = 2'd1;
|
||||||
|
localparam logic [1:0] GPIO_MODE_OUTPUT = 2'd2;
|
||||||
|
|
||||||
|
import gpio_reg_pkg::*;
|
||||||
|
|
||||||
|
gpio_reg_pkg::gpio_reg2hw_t reg2hw;
|
||||||
|
gpio_reg_pkg::gpio_hw2reg_t hw2reg;
|
||||||
|
|
||||||
|
logic [GPIO_NUM-1:0] gpio_oe;
|
||||||
|
logic [GPIO_NUM-1:0] gpio_ie;
|
||||||
|
logic [GPIO_NUM-1:0] gpio_data;
|
||||||
|
logic [GPIO_NUM-1:0] gpio_filter_enable;
|
||||||
|
logic [GPIO_NUM-1:0] gpio_filter_data;
|
||||||
|
logic [GPIO_NUM-1:0] gpio_raise_detect;
|
||||||
|
logic [GPIO_NUM-1:0] gpio_fall_detect;
|
||||||
|
logic [GPIO_NUM-1:0] gpio_intr_trigge;
|
||||||
|
|
||||||
|
// 输入滤波使能
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_filter_enable
|
||||||
|
assign gpio_filter_enable[i] = reg2hw.filter.q[i];
|
||||||
|
end
|
||||||
|
|
||||||
|
// 输出使能
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_oe
|
||||||
|
assign gpio_oe[i] = reg2hw.io_mode.q[i*2+1:i*2] == GPIO_MODE_OUTPUT;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign gpio_oe_o = gpio_oe;
|
||||||
|
|
||||||
|
// 输出数据
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_data
|
||||||
|
assign gpio_data[i] = reg2hw.data.q[i];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign gpio_data_o = gpio_data;
|
||||||
|
|
||||||
|
// 输入使能
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_ie
|
||||||
|
assign gpio_ie[i] = reg2hw.io_mode.q[i*2+1:i*2] == GPIO_MODE_INPUT;
|
||||||
|
end
|
||||||
|
|
||||||
|
// 硬件写data数据
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_h2r_data
|
||||||
|
assign hw2reg.data.d[i] = gpio_ie[i] ? gpio_filter_data[i] : reg2hw.data.q[i];
|
||||||
|
end
|
||||||
|
// 硬件写data使能
|
||||||
|
assign hw2reg.data.de = |gpio_ie;
|
||||||
|
|
||||||
|
// 中断有效
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_intr_trigge
|
||||||
|
assign gpio_intr_trigge[i] = ((reg2hw.int_mode.q[i*2+1:i*2] == INTR_MODE_RAISE_EDGE) & gpio_raise_detect[i]) |
|
||||||
|
((reg2hw.int_mode.q[i*2+1:i*2] == INTR_MODE_FALL_EDGE) & gpio_fall_detect[i]) |
|
||||||
|
((reg2hw.int_mode.q[i*2+1:i*2] == INTR_MODE_DOUBLE_EDGE) & (gpio_raise_detect[i] | gpio_fall_detect[i]));
|
||||||
|
end
|
||||||
|
|
||||||
|
// 硬件写中断pending数据
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_intr_pending
|
||||||
|
assign hw2reg.int_pending.d[i] = gpio_intr_trigge[i] ? 1'b1 : reg2hw.int_pending.q[i];
|
||||||
|
end
|
||||||
|
// 硬件写中断pending使能
|
||||||
|
assign hw2reg.int_pending.de = |gpio_intr_trigge;
|
||||||
|
|
||||||
|
// 中断输出信号
|
||||||
|
if (GPIO_NUM >= 1) begin : g_num_ge_1
|
||||||
|
assign irq_gpio0_o = reg2hw.int_pending.q[0];
|
||||||
|
end
|
||||||
|
if (GPIO_NUM >= 2) begin : g_num_ge_2
|
||||||
|
assign irq_gpio1_o = reg2hw.int_pending.q[1];
|
||||||
|
end
|
||||||
|
if (GPIO_NUM >= 5) begin : g_num_ge_5
|
||||||
|
assign irq_gpio2_4_o = reg2hw.int_pending.q[2] | reg2hw.int_pending.q[3] | reg2hw.int_pending.q[4];
|
||||||
|
end
|
||||||
|
if (GPIO_NUM >= 8) begin : g_num_ge_8
|
||||||
|
assign irq_gpio5_7_o = reg2hw.int_pending.q[5] | reg2hw.int_pending.q[6] | reg2hw.int_pending.q[7];
|
||||||
|
end
|
||||||
|
if (GPIO_NUM >= 9) begin : g_num_ge_9
|
||||||
|
assign irq_gpio8_o = reg2hw.int_pending.q[8];
|
||||||
|
end
|
||||||
|
if (GPIO_NUM >= 10) begin : g_num_ge_10
|
||||||
|
assign irq_gpio9_o = reg2hw.int_pending.q[9];
|
||||||
|
end
|
||||||
|
if (GPIO_NUM >= 13) begin : g_num_ge_13
|
||||||
|
assign irq_gpio10_12_o = reg2hw.int_pending.q[10] | reg2hw.int_pending.q[11] | reg2hw.int_pending.q[12];
|
||||||
|
end
|
||||||
|
if (GPIO_NUM >= 16) begin : g_num_ge_16
|
||||||
|
assign irq_gpio13_15_o = reg2hw.int_pending.q[13] | reg2hw.int_pending.q[14] | reg2hw.int_pending.q[15];
|
||||||
|
end
|
||||||
|
|
||||||
|
// 沿检测
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_edge_detect
|
||||||
|
edge_detect u_edge_detect(
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.sig_i (gpio_filter_data[i]),
|
||||||
|
.sig_o (),
|
||||||
|
.re_o (gpio_raise_detect[i]),
|
||||||
|
.fe_o (gpio_fall_detect[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
// 输入信号滤波
|
||||||
|
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_filter
|
||||||
|
prim_filter #(
|
||||||
|
.Cycles(8)
|
||||||
|
) gpio_filter (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.enable_i (gpio_filter_enable[i]),
|
||||||
|
.filter_i (gpio_data_i[i]),
|
||||||
|
.filter_o (gpio_filter_data[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
gpio_reg_top u_gpio_reg_top (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.reg2hw (reg2hw),
|
||||||
|
.hw2reg (hw2reg),
|
||||||
|
.reg_we (reg_we_i),
|
||||||
|
.reg_re (reg_re_i),
|
||||||
|
.reg_wdata (reg_wdata_i),
|
||||||
|
.reg_be (reg_be_i),
|
||||||
|
.reg_addr (reg_addr_i),
|
||||||
|
.reg_rdata (reg_rdata_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Register Package auto-generated by `reggen` containing data structure
|
||||||
|
|
||||||
|
package gpio_reg_pkg;
|
||||||
|
|
||||||
|
// Address widths within the block
|
||||||
|
parameter int BlockAw = 5;
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
// Typedefs for registers //
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [31:0] q;
|
||||||
|
} gpio_reg2hw_io_mode_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [31:0] q;
|
||||||
|
} gpio_reg2hw_int_mode_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [15:0] q;
|
||||||
|
} gpio_reg2hw_int_pending_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [15:0] q;
|
||||||
|
} gpio_reg2hw_data_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [15:0] q;
|
||||||
|
} gpio_reg2hw_filter_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [15:0] d;
|
||||||
|
logic de;
|
||||||
|
} gpio_hw2reg_int_pending_reg_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [15:0] d;
|
||||||
|
logic de;
|
||||||
|
} gpio_hw2reg_data_reg_t;
|
||||||
|
|
||||||
|
// Register -> HW type
|
||||||
|
typedef struct packed {
|
||||||
|
gpio_reg2hw_io_mode_reg_t io_mode; // [111:80]
|
||||||
|
gpio_reg2hw_int_mode_reg_t int_mode; // [79:48]
|
||||||
|
gpio_reg2hw_int_pending_reg_t int_pending; // [47:32]
|
||||||
|
gpio_reg2hw_data_reg_t data; // [31:16]
|
||||||
|
gpio_reg2hw_filter_reg_t filter; // [15:0]
|
||||||
|
} gpio_reg2hw_t;
|
||||||
|
|
||||||
|
// HW -> register type
|
||||||
|
typedef struct packed {
|
||||||
|
gpio_hw2reg_int_pending_reg_t int_pending; // [33:17]
|
||||||
|
gpio_hw2reg_data_reg_t data; // [16:0]
|
||||||
|
} gpio_hw2reg_t;
|
||||||
|
|
||||||
|
// Register offsets
|
||||||
|
parameter logic [BlockAw-1:0] GPIO_IO_MODE_OFFSET = 5'h0;
|
||||||
|
parameter logic [BlockAw-1:0] GPIO_INT_MODE_OFFSET = 5'h4;
|
||||||
|
parameter logic [BlockAw-1:0] GPIO_INT_PENDING_OFFSET = 5'h8;
|
||||||
|
parameter logic [BlockAw-1:0] GPIO_DATA_OFFSET = 5'hc;
|
||||||
|
parameter logic [BlockAw-1:0] GPIO_FILTER_OFFSET = 5'h10;
|
||||||
|
|
||||||
|
// Register index
|
||||||
|
typedef enum int {
|
||||||
|
GPIO_IO_MODE,
|
||||||
|
GPIO_INT_MODE,
|
||||||
|
GPIO_INT_PENDING,
|
||||||
|
GPIO_DATA,
|
||||||
|
GPIO_FILTER
|
||||||
|
} gpio_id_e;
|
||||||
|
|
||||||
|
// Register width information to check illegal writes
|
||||||
|
parameter logic [3:0] GPIO_PERMIT [5] = '{
|
||||||
|
4'b1111, // index[0] GPIO_IO_MODE
|
||||||
|
4'b1111, // index[1] GPIO_INT_MODE
|
||||||
|
4'b0011, // index[2] GPIO_INT_PENDING
|
||||||
|
4'b0011, // index[3] GPIO_DATA
|
||||||
|
4'b0011 // index[4] GPIO_FILTER
|
||||||
|
};
|
||||||
|
|
||||||
|
endpackage
|
||||||
|
|
|
@ -0,0 +1,270 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
// Register Top module auto-generated by `reggen`
|
||||||
|
|
||||||
|
|
||||||
|
module gpio_reg_top (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
// To HW
|
||||||
|
output gpio_reg_pkg::gpio_reg2hw_t reg2hw, // Write
|
||||||
|
input gpio_reg_pkg::gpio_hw2reg_t hw2reg, // Read
|
||||||
|
|
||||||
|
input logic reg_we,
|
||||||
|
input logic reg_re,
|
||||||
|
input logic [31:0] reg_wdata,
|
||||||
|
input logic [ 3:0] reg_be,
|
||||||
|
input logic [31:0] reg_addr,
|
||||||
|
output logic [31:0] reg_rdata
|
||||||
|
);
|
||||||
|
|
||||||
|
import gpio_reg_pkg::* ;
|
||||||
|
|
||||||
|
localparam int AW = 5;
|
||||||
|
localparam int DW = 32;
|
||||||
|
localparam int DBW = DW/8; // Byte Width
|
||||||
|
|
||||||
|
logic reg_error;
|
||||||
|
logic addrmiss, wr_err;
|
||||||
|
|
||||||
|
logic [DW-1:0] reg_rdata_next;
|
||||||
|
|
||||||
|
assign reg_rdata = reg_rdata_next;
|
||||||
|
assign reg_error = wr_err;
|
||||||
|
|
||||||
|
// Define SW related signals
|
||||||
|
// Format: <reg>_<field>_{wd|we|qs}
|
||||||
|
// or <reg>_{wd|we|qs} if field == 1 or 0
|
||||||
|
logic io_mode_we;
|
||||||
|
logic [31:0] io_mode_qs;
|
||||||
|
logic [31:0] io_mode_wd;
|
||||||
|
logic int_mode_we;
|
||||||
|
logic [31:0] int_mode_qs;
|
||||||
|
logic [31:0] int_mode_wd;
|
||||||
|
logic int_pending_we;
|
||||||
|
logic [15:0] int_pending_qs;
|
||||||
|
logic [15:0] int_pending_wd;
|
||||||
|
logic data_we;
|
||||||
|
logic [15:0] data_qs;
|
||||||
|
logic [15:0] data_wd;
|
||||||
|
logic filter_we;
|
||||||
|
logic [15:0] filter_qs;
|
||||||
|
logic [15:0] filter_wd;
|
||||||
|
|
||||||
|
// Register instances
|
||||||
|
// R[io_mode]: V(False)
|
||||||
|
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (32),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (32'h0)
|
||||||
|
) u_io_mode (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (io_mode_we),
|
||||||
|
.wd (io_mode_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (1'b0),
|
||||||
|
.d ('0),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.io_mode.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (io_mode_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[int_mode]: V(False)
|
||||||
|
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (32),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (32'h0)
|
||||||
|
) u_int_mode (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (int_mode_we),
|
||||||
|
.wd (int_mode_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (1'b0),
|
||||||
|
.d ('0),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.int_mode.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (int_mode_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[int_pending]: V(False)
|
||||||
|
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (16),
|
||||||
|
.SWACCESS("W1C"),
|
||||||
|
.RESVAL (16'h0)
|
||||||
|
) u_int_pending (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (int_pending_we),
|
||||||
|
.wd (int_pending_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.int_pending.de),
|
||||||
|
.d (hw2reg.int_pending.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.int_pending.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (int_pending_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[data]: V(False)
|
||||||
|
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (16),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (16'h0)
|
||||||
|
) u_data (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (data_we),
|
||||||
|
.wd (data_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (hw2reg.data.de),
|
||||||
|
.d (hw2reg.data.d),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.data.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (data_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// R[filter]: V(False)
|
||||||
|
|
||||||
|
prim_subreg #(
|
||||||
|
.DW (16),
|
||||||
|
.SWACCESS("RW"),
|
||||||
|
.RESVAL (16'h0)
|
||||||
|
) u_filter (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
|
||||||
|
// from register interface
|
||||||
|
.we (filter_we),
|
||||||
|
.wd (filter_wd),
|
||||||
|
|
||||||
|
// from internal hardware
|
||||||
|
.de (1'b0),
|
||||||
|
.d ('0),
|
||||||
|
|
||||||
|
// to internal hardware
|
||||||
|
.qe (),
|
||||||
|
.q (reg2hw.filter.q),
|
||||||
|
|
||||||
|
// to register interface (read)
|
||||||
|
.qs (filter_qs)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
logic [4:0] addr_hit;
|
||||||
|
always_comb begin
|
||||||
|
addr_hit = '0;
|
||||||
|
addr_hit[0] = (reg_addr == GPIO_IO_MODE_OFFSET);
|
||||||
|
addr_hit[1] = (reg_addr == GPIO_INT_MODE_OFFSET);
|
||||||
|
addr_hit[2] = (reg_addr == GPIO_INT_PENDING_OFFSET);
|
||||||
|
addr_hit[3] = (reg_addr == GPIO_DATA_OFFSET);
|
||||||
|
addr_hit[4] = (reg_addr == GPIO_FILTER_OFFSET);
|
||||||
|
end
|
||||||
|
|
||||||
|
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
|
||||||
|
|
||||||
|
// Check sub-word write is permitted
|
||||||
|
always_comb begin
|
||||||
|
wr_err = (reg_we &
|
||||||
|
((addr_hit[0] & (|(GPIO_PERMIT[0] & ~reg_be))) |
|
||||||
|
(addr_hit[1] & (|(GPIO_PERMIT[1] & ~reg_be))) |
|
||||||
|
(addr_hit[2] & (|(GPIO_PERMIT[2] & ~reg_be))) |
|
||||||
|
(addr_hit[3] & (|(GPIO_PERMIT[3] & ~reg_be))) |
|
||||||
|
(addr_hit[4] & (|(GPIO_PERMIT[4] & ~reg_be)))));
|
||||||
|
end
|
||||||
|
|
||||||
|
assign io_mode_we = addr_hit[0] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
assign io_mode_wd = reg_wdata[31:0];
|
||||||
|
assign int_mode_we = addr_hit[1] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
assign int_mode_wd = reg_wdata[31:0];
|
||||||
|
assign int_pending_we = addr_hit[2] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
assign int_pending_wd = reg_wdata[15:0];
|
||||||
|
assign data_we = addr_hit[3] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
assign data_wd = reg_wdata[15:0];
|
||||||
|
assign filter_we = addr_hit[4] & reg_we & !reg_error;
|
||||||
|
|
||||||
|
assign filter_wd = reg_wdata[15:0];
|
||||||
|
|
||||||
|
// Read data return
|
||||||
|
always_comb begin
|
||||||
|
reg_rdata_next = '0;
|
||||||
|
unique case (1'b1)
|
||||||
|
addr_hit[0]: begin
|
||||||
|
reg_rdata_next[31:0] = io_mode_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[1]: begin
|
||||||
|
reg_rdata_next[31:0] = int_mode_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[2]: begin
|
||||||
|
reg_rdata_next[15:0] = int_pending_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[3]: begin
|
||||||
|
reg_rdata_next[15:0] = data_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
addr_hit[4]: begin
|
||||||
|
reg_rdata_next[15:0] = filter_qs;
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin
|
||||||
|
reg_rdata_next = '1;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
// Unused signal tieoff
|
||||||
|
|
||||||
|
// wdata / byte enable are not always fully used
|
||||||
|
// add a blanket unused statement to handle lint waivers
|
||||||
|
logic unused_wdata;
|
||||||
|
logic unused_be;
|
||||||
|
assign unused_wdata = ^reg_wdata;
|
||||||
|
assign unused_be = ^reg_be;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module gpio_top #(
|
||||||
|
parameter int GPIO_NUM = 2
|
||||||
|
)(
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
output logic [GPIO_NUM-1:0] gpio_oe_o,
|
||||||
|
output logic [GPIO_NUM-1:0] gpio_data_o,
|
||||||
|
input logic [GPIO_NUM-1:0] gpio_data_i,
|
||||||
|
output logic irq_gpio0_o,
|
||||||
|
output logic irq_gpio1_o,
|
||||||
|
output logic irq_gpio2_4_o,
|
||||||
|
output logic irq_gpio5_7_o,
|
||||||
|
output logic irq_gpio8_o,
|
||||||
|
output logic irq_gpio9_o,
|
||||||
|
output logic irq_gpio10_12_o,
|
||||||
|
output logic irq_gpio13_15_o,
|
||||||
|
|
||||||
|
// OBI总线接口信号
|
||||||
|
input logic req_i,
|
||||||
|
input logic we_i,
|
||||||
|
input logic [ 3:0] be_i,
|
||||||
|
input logic [31:0] addr_i,
|
||||||
|
input logic [31:0] data_i,
|
||||||
|
output logic gnt_o,
|
||||||
|
output logic rvalid_o,
|
||||||
|
output logic [31:0] data_o
|
||||||
|
);
|
||||||
|
|
||||||
|
logic re;
|
||||||
|
logic we;
|
||||||
|
logic [31:0] addr;
|
||||||
|
logic [31:0] reg_rdata;
|
||||||
|
|
||||||
|
assign gnt_o = req_i;
|
||||||
|
|
||||||
|
// 读信号
|
||||||
|
assign re = req_i & (!we_i);
|
||||||
|
// 写信号
|
||||||
|
assign we = req_i & we_i;
|
||||||
|
// 去掉基地址
|
||||||
|
assign addr = {16'h0, addr_i[15:0]};
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
rvalid_o <= '0;
|
||||||
|
data_o <= '0;
|
||||||
|
end else begin
|
||||||
|
rvalid_o <= req_i;
|
||||||
|
data_o <= reg_rdata;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
gpio_core #(
|
||||||
|
.GPIO_NUM(GPIO_NUM)
|
||||||
|
) u_gpio_core (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.gpio_oe_o (gpio_oe_o),
|
||||||
|
.gpio_data_o(gpio_data_o),
|
||||||
|
.gpio_data_i(gpio_data_i),
|
||||||
|
.irq_gpio0_o(irq_gpio0_o),
|
||||||
|
.irq_gpio1_o(irq_gpio1_o),
|
||||||
|
.irq_gpio2_4_o(irq_gpio2_4_o),
|
||||||
|
.irq_gpio5_7_o(irq_gpio5_7_o),
|
||||||
|
.irq_gpio8_o(irq_gpio8_o),
|
||||||
|
.irq_gpio9_o(irq_gpio9_o),
|
||||||
|
.irq_gpio10_12_o(irq_gpio10_12_o),
|
||||||
|
.irq_gpio13_15_o(irq_gpio13_15_o),
|
||||||
|
.reg_we_i (we),
|
||||||
|
.reg_re_i (re),
|
||||||
|
.reg_wdata_i(data_i),
|
||||||
|
.reg_be_i (be_i),
|
||||||
|
.reg_addr_i (addr),
|
||||||
|
.reg_rdata_o(reg_rdata)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,138 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
{ name: "i2c",
|
||||||
|
clocking: [{clock: "clk_i", reset: "rst_ni"}],
|
||||||
|
bus_interfaces: [
|
||||||
|
{ protocol: "tlul", direction: "device" }
|
||||||
|
],
|
||||||
|
regwidth: "32",
|
||||||
|
registers: [
|
||||||
|
{ name: "CTRL",
|
||||||
|
desc: "I2C control register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
hwqe: "true",
|
||||||
|
fields: [
|
||||||
|
{ bits: "0",
|
||||||
|
name: "START",
|
||||||
|
desc: "I2C start",
|
||||||
|
}
|
||||||
|
{ bits: "1",
|
||||||
|
name: "INT_EN",
|
||||||
|
desc: "I2C interrupt enable",
|
||||||
|
}
|
||||||
|
{ bits: "2",
|
||||||
|
name: "INT_PENDING",
|
||||||
|
swaccess: "rw1c",
|
||||||
|
desc: "I2C interrupt pending",
|
||||||
|
}
|
||||||
|
{ bits: "3",
|
||||||
|
name: "MODE",
|
||||||
|
desc: "I2C mode, 0: master, 1: slave",
|
||||||
|
}
|
||||||
|
{ bits: "4",
|
||||||
|
name: "WRITE",
|
||||||
|
desc: "0: write, 1: read",
|
||||||
|
}
|
||||||
|
{ bits: "5",
|
||||||
|
name: "ERROR",
|
||||||
|
swaccess: "ro",
|
||||||
|
desc: "0: no error, 1: error",
|
||||||
|
}
|
||||||
|
{ bits: "6",
|
||||||
|
name: "SLAVE_WR",
|
||||||
|
swaccess: "ro",
|
||||||
|
desc: "0: write, 1: read",
|
||||||
|
}
|
||||||
|
{ bits: "7",
|
||||||
|
name: "SLAVE_RDY",
|
||||||
|
desc: "0: not ready, 1: ready",
|
||||||
|
}
|
||||||
|
{ bits: "15:8",
|
||||||
|
name: "SLAVE_ADDR",
|
||||||
|
desc: "I2C slave address",
|
||||||
|
}
|
||||||
|
{ bits: "31:16",
|
||||||
|
name: "CLK_DIV",
|
||||||
|
desc: "I2C clock divider count",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "MASTER_DATA",
|
||||||
|
desc: "I2C master transfer data register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
fields: [
|
||||||
|
{ bits: "7:0",
|
||||||
|
name: "ADDRESS",
|
||||||
|
desc: "I2C slave address",
|
||||||
|
}
|
||||||
|
{ bits: "15:8",
|
||||||
|
name: "REGREG",
|
||||||
|
desc: "I2C write or read reg",
|
||||||
|
}
|
||||||
|
{ bits: "23:16",
|
||||||
|
name: "DATA",
|
||||||
|
desc: "I2C write or read data",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "SLAVE_ADDR",
|
||||||
|
desc: "I2C slave read or write address register",
|
||||||
|
swaccess: "ro",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
fields: [
|
||||||
|
{ bits: "7:0",
|
||||||
|
name: "ADDR0",
|
||||||
|
desc: "I2C slave read or write address[7:0]",
|
||||||
|
}
|
||||||
|
{ bits: "15:8",
|
||||||
|
name: "ADDR1",
|
||||||
|
desc: "I2C slave read or write address[15:8]",
|
||||||
|
}
|
||||||
|
{ bits: "23:16",
|
||||||
|
name: "ADDR2",
|
||||||
|
desc: "I2C slave read or write address[23:16]",
|
||||||
|
}
|
||||||
|
{ bits: "31:24",
|
||||||
|
name: "ADDR3",
|
||||||
|
desc: "I2C slave read or write address[31:24]",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "SLAVE_WDATA",
|
||||||
|
desc: "I2C slave write data register",
|
||||||
|
swaccess: "ro",
|
||||||
|
hwaccess: "hrw",
|
||||||
|
fields: [
|
||||||
|
{ bits: "7:0",
|
||||||
|
name: "WDATA0",
|
||||||
|
desc: "I2C slave write data[7:0]",
|
||||||
|
}
|
||||||
|
{ bits: "15:8",
|
||||||
|
name: "WDATA1",
|
||||||
|
desc: "I2C slave write data[15:8]",
|
||||||
|
}
|
||||||
|
{ bits: "23:16",
|
||||||
|
name: "WDATA2",
|
||||||
|
desc: "I2C slave write data[23:16]",
|
||||||
|
}
|
||||||
|
{ bits: "31:24",
|
||||||
|
name: "WDATA3",
|
||||||
|
desc: "I2C slave write data[31:24]",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{ name: "SLAVE_RDATA",
|
||||||
|
desc: "I2C slave read data register",
|
||||||
|
swaccess: "rw",
|
||||||
|
hwaccess: "hro",
|
||||||
|
fields: [
|
||||||
|
{ bits: "31:0",
|
||||||
|
desc: "I2C slave read data",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|