Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
liangkangnan | 5c87fc09ef | |
liangkangnan | fdc776ab5e | |
liangkangnan | f03f42fc9b | |
liangkangnan | ceddc1af24 | |
liangkangnan | 5c9f1a140e | |
Blue Liang | 60a4f7d6df | |
liangkangnan | eb5647915a | |
liangkangnan | 2b44f1e8f3 |
|
@ -2,3 +2,5 @@
|
|||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
||||
|
|
251
README.md
251
README.md
|
@ -1,251 +1,2 @@
|
|||
本项目目前一共有3个分支,分别是master、bram和verilator,分别对应入门、进阶和高级三个级别,大家可以根据自身情况选择。
|
||||
|
||||
**本项目是一直在更新的,verilator分支持续开发中**,如果哪天不再更新了,我会特别说明的。
|
||||
|
||||
如果对本项目有疑问或者建议的话,优先通过邮件交流,谢谢。
|
||||
|
||||
配套的设计文档在doc目录下(目前还没完成)。
|
||||
|
||||
# 1.初衷
|
||||
|
||||
本开源项目的初衷是本人想入门RISC-V,熟悉RISC-V的指令内容和汇编语法。
|
||||
|
||||
本人对RISC-V很感兴趣,很看好RISC-V的发展前景,觉得RISC-V就是CPU中的Linux。由于RISC-V是这两年才开始迅速发展的,因此关于RISC-V的学习参考资料目前还很少,特别是适合入门的资料,因此学习起来进度很缓慢,于是萌生了自己从零开始写RISC-V处理器核的想法。
|
||||
|
||||
本人是一名FPGA小白,为了快速入门、深入掌握RISC-V,我开始了学习FPGA和verilog的"艰难"历程。我工作的内容是和嵌入式软件相关的,平时根本不会接触到FPGA,也不会用到RISC-V,因此只能用业余时间来学习RISC-V。
|
||||
|
||||
网上有不少关于RISC-V的开源项目,但是大多都写得很"高深",对于我这种小白来说学习起来是非常吃力的,不太适合入门。本项目目前的代码量非常少,是很简单易懂的,对于想入门RISC-V的同学来说是一个很好的参考,希望能够吸引更多的同学参与到RISC-V的学习中来,促进RISC-V的发展,如果能起到抛砖引玉的作用的话那就更好了,也许说是砖的话就有点夸大了,但哪怕是起到一颗沙子的作用,也就足矣。
|
||||
|
||||
# 2.介绍
|
||||
|
||||
本项目实现的是一个单核32位的小型RISC-V处理器核(tinyriscv),采用verilog语言编写。设计目标是对标ARM Cortex-M3系列处理器。tinyriscv有以下特点:
|
||||
|
||||
1. 支持RV32IM指令集,通过RISC-V指令兼容性测试;
|
||||
3. 采用三级流水线,即取指,译码,执行;
|
||||
4. 可以运行C语言程序;
|
||||
5. 支持JTAG,可以通过openocd读写内存(在线更新程序);
|
||||
6. 支持中断;
|
||||
6. 支持总线;
|
||||
7. 支持FreeRTOS;
|
||||
8. 支持通过串口更新程序;
|
||||
9. 容易移植到任何FPGA平台(如果资源足够的话);
|
||||
|
||||
项目中的各目录说明:
|
||||
|
||||
**rtl**:该目录包含tinyriscv的所有verilog源码;
|
||||
|
||||
**sim**:该目录包含仿真批处理bat文件和脚本;
|
||||
|
||||
**tests**:该目录包含测试程序源码,其中example目录为C语言程序例程源码,isa目录为RV32指令测试源码;
|
||||
|
||||
**tools**:该目录包含编译汇编和C语言程序所需GNU工具链和将二进制文件转成仿真所需的mem格式文件的脚本,还有通过串口下载程序的脚本。
|
||||
|
||||
**pic**:存放图片;
|
||||
|
||||
**tb**:该目录包含仿真的testbench文件;
|
||||
|
||||
**fpga**:存放FPGA相关文件,比如约束文件;
|
||||
|
||||
tinyriscv的整体框架如下:
|
||||
|
||||
![tinyriscv整体框架](./pic/arch.jpg)
|
||||
|
||||
tinyriscv目前外挂了6个外设,每个外设的空间大小为256MB,地址空间分配如下图所示:
|
||||
|
||||
<img src="./pic/addr_alloc.jpg" alt="地址空间分配" style="zoom:70%;" />
|
||||
|
||||
# 3.CoreMark测试
|
||||
|
||||
目前tinyriscv在Xilinx Artix-7 35T FPGA平台(时钟50MHz)上运行CoreMark跑分程序的结果如下图所示:
|
||||
|
||||
![tinyriscv跑分](./pic/tinyriscv_coremark.png)
|
||||
|
||||
可知,tinyriscv的跑分成绩为2.4。
|
||||
|
||||
选了几款其他MCU的跑分结果如下图所示:
|
||||
|
||||
![其他MCU跑分结果](./pic/other_coremark.png)
|
||||
|
||||
更多MCU的跑分结果,可以到[coremark](https://www.eembc.org/coremark/scores.php)官网查询。
|
||||
|
||||
# 4.如何使用
|
||||
|
||||
本项目可以运行在Windows和Linux平台(macOS平台理论上也是可以的),编译仿真工具使用的是iverilog和vpp,波形查看工具使用的是gtkwave。
|
||||
|
||||
## 4.1Windows平台环境搭建
|
||||
|
||||
在使用之前需要安装以下工具:
|
||||
|
||||
1. 安装iverilog工具
|
||||
|
||||
可以在这里[http://bleyer.org/icarus/](http://bleyer.org/icarus/)下载,安装过程中记得同意把iverilog添加到环境变量中,当然也可以在安装完成后手动进行添加。安装完成后iverilog、vvp和gtkwave等工具也就安装好了。
|
||||
|
||||
2. 安装GNU工具链
|
||||
|
||||
可以通过百度网盘下载(链接: https://pan.baidu.com/s/1bYgslKxHMjtiZtIPsB2caQ 提取码: 9n3c),或者通过微云下载[https://share.weiyun.com/5bMOsu9](https://share.weiyun.com/5bMOsu9),下载完成后将压缩包解压到本项目的tools目录下。注意目录的层次结构,解压后的工具路径应该如下所示:
|
||||
|
||||
`tinyriscv\tools\gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64\bin\riscv-none-embed-gcc`
|
||||
|
||||
3. 安装make工具
|
||||
|
||||
可以通过百度网盘下载(链接: https://pan.baidu.com/s/1nFaUIwv171PDXuF7TziDFg 提取码: 9ntc),或者通过微云下载[https://share.weiyun.com/59xtmWR](https://share.weiyun.com/59xtmWR),下载完成后直接解压,然后将make所在的路径添加到环境变量里。
|
||||
|
||||
4. 安装python3
|
||||
|
||||
到[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添加到环境变量里。
|
||||
|
||||
5. 下载tinyriscv代码
|
||||
|
||||
**使用git clone命令下载,不要使用zip方式下载**,否则有些文件会有格式问题。
|
||||
|
||||
`git clone https://gitee.com/liangkangnan/tinyriscv.git`
|
||||
|
||||
## 4.2Linux平台环境搭建
|
||||
|
||||
这里以Ubuntu系统为例进行说明。
|
||||
|
||||
1. 下载iverilog源码
|
||||
|
||||
`git clone https://github.com/steveicarus/iverilog.git`
|
||||
|
||||
2. 切换到v11分支(必须用V11或以上的版本)
|
||||
|
||||
`git checkout v11-branch`
|
||||
|
||||
3. 安装依赖
|
||||
|
||||
`sudo apt-get install autoconf gperf flex bison build-essential`
|
||||
|
||||
4. 编译、安装iverilog和vvp
|
||||
|
||||
```
|
||||
sh autoconf.sh
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
5. 创建python软链接
|
||||
|
||||
`sudo ln -s /usr/bin/python3.8 /usr/bin/python`
|
||||
|
||||
其中/usr/bin/python3.8对应你实际安装的python版本。
|
||||
|
||||
6. 安装gtkwave
|
||||
|
||||
`sudo apt-get install gtkwave`
|
||||
|
||||
7. 安装GNU工具链
|
||||
|
||||
可以从百度网盘下载(链接:https://pan.baidu.com/s/10uLZYf_cgtH94kZI_N6JhQ
|
||||
提取码:uk0w)或者自行下载其他版本的,下载后解压到tools目录下。
|
||||
|
||||
最后,需要确认tests/example/common.mk文件里的这几行内容要与你安装的工具链对应得上。
|
||||
|
||||
![toolchain](./pic/toolchain.png)
|
||||
|
||||
## 4.3运行指令测试程序
|
||||
|
||||
这里以Windows平台为例进行说明,Linux平台是类似的。
|
||||
|
||||
### 4.3.1 运行旧的指令测试程序
|
||||
|
||||
旧的指令测试程序属于比较早的指令兼容性测试方法,虽然目前RISC-V官方已经不更新了,但仍然是一个比较好的测试参考。
|
||||
|
||||
下面以add指令为例,说明如何运行旧的指令测试程序。
|
||||
|
||||
打开CMD窗口,进入到sim目录,执行以下命令:
|
||||
|
||||
```python .\sim_new_nowave.py ..\tests\isa\generated\rv32ui-p-add.bin inst.data```
|
||||
|
||||
如果运行成功的话就可以看到"PASS"的打印。其他指令使用方法类似。
|
||||
|
||||
![](./pic/test_output.png)
|
||||
|
||||
也可以一次性对所有指令进行测试,方法如下。
|
||||
|
||||
打开CMD窗口进入到sim目录下,执行以下命令:
|
||||
|
||||
`python .\test_all_isa.py`
|
||||
|
||||
### 4.3.2运行新的指令测试程序
|
||||
|
||||
新的指令兼容性([riscv-compliance](https://github.com/riscv/riscv-compliance))测试项相对于旧的指令兼容性测试项来说对指令的测试更加严谨,可以精确到每一条指令的运行结果,而且RISC-V官方一直在更新。
|
||||
|
||||
下面以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.4运行C语言程序
|
||||
|
||||
C语言程序例程位于tests\example目录里。
|
||||
|
||||
下面以simple程序为例进行说明。
|
||||
|
||||
打开CMD窗口,进入到tests\example\simple目录,执行以下命令编译:
|
||||
|
||||
`make`
|
||||
|
||||
编译成功之后,进入到sim目录,执行以下命令开始测试:
|
||||
|
||||
` python .\sim_new_nowave.py ..\tests\example\simple\simple.bin inst.data`
|
||||
|
||||
# 5.移植到FPGA
|
||||
|
||||
详细的移植方法请查看本项目下的fpga目录中的README.md文件。
|
||||
|
||||
# 6.未来计划
|
||||
|
||||
1. 写设计文档;
|
||||
2. 优化资源和功耗(主要是译码和执行部分);
|
||||
3. 支持硬件中断嵌套和快速实时中断;
|
||||
4. ......
|
||||
|
||||
# 7.更新记录
|
||||
|
||||
2020-10-25:支持Linux平台编译、仿真。新建bram分支,使用BRAM代替LUTRAM(DRAM),节省一半以上的LUT资源,并且可以运行更大的程序。
|
||||
|
||||
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)给我。
|
||||
本分支(bram)是在master分支的基础上,将指令和数据存储器由LUTRAM(DRAM)改为BRAM,以便可以运行更大的(C语言)程序。
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -156,7 +156,7 @@
|
|||
|
||||
打开一个CMD窗口,然后cd进入到tinyriscv项目的tools/openocd目录,执行命令:
|
||||
|
||||
`openocd.exe -f tinyriscv.cfg`
|
||||
`openocd.exe -f tinyriscv_cmsisdap.cfg`
|
||||
|
||||
如果执行成功的话则会如下图所示:
|
||||
|
||||
|
@ -182,22 +182,6 @@
|
|||
|
||||
**注意:每次下载程序前记得先执行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,如下图所示:
|
||||
|
@ -213,7 +197,7 @@ tinyriscv_fw_downloader.py脚本使用方法:
|
|||
```
|
||||
// read mem data
|
||||
initial begin
|
||||
$readmemh ("F://yourpath/inst.data", tinyriscv_soc_top_0.u_rom._rom);
|
||||
$readmemh ("F://yourpath/inst.data", tinyriscv_soc_top_0.u_rom.u_gen_ram.ram);
|
||||
end
|
||||
```
|
||||
|
||||
|
|
|
@ -7,25 +7,13 @@ 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]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports rst_ext_i]
|
||||
set_property PACKAGE_PIN L13 [get_ports rst_ext_i]
|
||||
|
||||
# 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]
|
||||
|
@ -60,22 +48,6 @@ set_property PACKAGE_PIN N2 [get_ports jtag_TDI]
|
|||
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]
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 68 KiB |
Binary file not shown.
Before Width: | Height: | Size: 33 KiB |
233
rtl/core/clint.v
233
rtl/core/clint.v
|
@ -16,53 +16,41 @@
|
|||
|
||||
`include "defines.v"
|
||||
|
||||
|
||||
// core local interruptor module
|
||||
// 核心中断管理、仲裁模块
|
||||
module clint(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
|
||||
// from core
|
||||
input wire[`INT_BUS] int_flag_i, // 中断输入信号
|
||||
input wire[`INT_WIDTH-1:0] int_flag_i, // 中断输入信号
|
||||
|
||||
// from id
|
||||
input wire[`InstBus] inst_i, // 指令内容
|
||||
input wire[`InstAddrBus] inst_addr_i, // 指令地址
|
||||
|
||||
// from ex
|
||||
// from exu
|
||||
input wire inst_ecall_i, // ecall指令
|
||||
input wire inst_ebreak_i, // ebreak指令
|
||||
input wire inst_mret_i, // mret指令
|
||||
input wire[31:0] inst_addr_i, // 指令地址
|
||||
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, // 流水线暂停标志
|
||||
input wire mem_access_misaligned_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, // 流水线暂停标志
|
||||
input wire[31:0] csr_mtvec_i, // mtvec寄存器
|
||||
input wire[31:0] csr_mepc_i, // mepc寄存器
|
||||
input wire[31:0] csr_mstatus_i, // mstatus寄存器
|
||||
|
||||
// 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寄存器数据
|
||||
output reg csr_we_o, // 写CSR寄存器标志
|
||||
output reg[31:0] csr_waddr_o, // 写CSR寄存器地址
|
||||
output reg[31:0] csr_wdata_o, // 写CSR寄存器数据
|
||||
|
||||
// to ex
|
||||
output reg[`InstAddrBus] int_addr_o, // 中断入口地址
|
||||
output reg int_assert_o // 中断标志
|
||||
// to pipe_ctrl
|
||||
output wire stall_flag_o, // 流水线暂停标志
|
||||
output wire[31:0] int_addr_o, // 中断入口地址
|
||||
output wire int_assert_o // 中断标志
|
||||
|
||||
);
|
||||
|
||||
|
||||
// 中断状态定义
|
||||
localparam S_INT_IDLE = 4'b0001;
|
||||
localparam S_INT_SYNC_ASSERT = 4'b0010;
|
||||
|
@ -78,81 +66,80 @@ module clint(
|
|||
|
||||
reg[3:0] int_state;
|
||||
reg[4:0] csr_state;
|
||||
reg[`InstAddrBus] inst_addr;
|
||||
reg[31:0] inst_addr;
|
||||
reg[31:0] cause;
|
||||
|
||||
wire global_int_en = csr_mstatus_i[3];
|
||||
|
||||
assign hold_flag_o = ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? `HoldEnable: `HoldDisable;
|
||||
assign stall_flag_o = ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? 1'b1: 1'b0;
|
||||
|
||||
// 将跳转标志放在流水线上传递
|
||||
wire pc_state_jump_flag;
|
||||
gen_rst_0_dff #(1) pc_state_dff(clk, rst_n, jump_flag_i, pc_state_jump_flag);
|
||||
|
||||
wire if_state_jump_flag;
|
||||
gen_rst_0_dff #(1) if_state_dff(clk, rst_n, pc_state_jump_flag, if_state_jump_flag);
|
||||
|
||||
wire id_state_jump_flag;
|
||||
gen_rst_0_dff #(1) id_state_dff(clk, rst_n, if_state_jump_flag, id_state_jump_flag);
|
||||
|
||||
wire ex_state_jump_flag;
|
||||
gen_rst_0_dff #(1) ex_state_dff(clk, rst_n, id_state_jump_flag, ex_state_jump_flag);
|
||||
|
||||
wire[3:0] state_jump_flag = {pc_state_jump_flag, if_state_jump_flag, id_state_jump_flag, ex_state_jump_flag};
|
||||
// 如果流水线没有冲刷完成则不响应中断
|
||||
wire inst_addr_valid = (~(|state_jump_flag)) | ex_state_jump_flag;
|
||||
|
||||
|
||||
// 中断仲裁逻辑
|
||||
always @ (*) begin
|
||||
if (rst == `RstEnable) begin
|
||||
int_state = S_INT_IDLE;
|
||||
// 同步中断
|
||||
if (inst_ecall_i | inst_ebreak_i | mem_access_misaligned_i) begin
|
||||
int_state = S_INT_SYNC_ASSERT;
|
||||
// 异步中断
|
||||
end else if ((int_flag_i != `INT_NONE) & global_int_en & inst_addr_valid) begin
|
||||
int_state = S_INT_ASYNC_ASSERT;
|
||||
// 中断返回
|
||||
end else if (inst_mret_i) begin
|
||||
int_state = S_INT_MRET;
|
||||
// 无中断响应
|
||||
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
|
||||
int_state = S_INT_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
// 写CSR寄存器状态切换
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
csr_state <= S_CSR_IDLE;
|
||||
cause <= `ZeroWord;
|
||||
inst_addr <= `ZeroWord;
|
||||
cause <= 32'h0;
|
||||
inst_addr <= 32'h0;
|
||||
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
|
||||
case (int_state)
|
||||
// 同步中断
|
||||
S_INT_SYNC_ASSERT: begin
|
||||
csr_state <= S_CSR_MEPC;
|
||||
// 在中断处理函数里会将中断返回地址加4
|
||||
inst_addr <= inst_addr_i;
|
||||
cause <= inst_ebreak_i? 32'd3:
|
||||
inst_ecall_i? 32'd11:
|
||||
mem_access_misaligned_i? 32'd4:
|
||||
32'd10;
|
||||
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
|
||||
// 异步中断
|
||||
S_INT_ASYNC_ASSERT: begin
|
||||
csr_state <= S_CSR_MEPC;
|
||||
inst_addr <= inst_addr_i;
|
||||
// 定时器中断
|
||||
cause <= 32'h80000004;
|
||||
end
|
||||
// 中断返回
|
||||
end else if (int_state == S_INT_MRET) begin
|
||||
csr_state <= S_CSR_MSTATUS_MRET;
|
||||
end
|
||||
// 中断返回
|
||||
S_INT_MRET: begin
|
||||
csr_state <= S_CSR_MSTATUS_MRET;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
S_CSR_MEPC: begin
|
||||
csr_state <= S_CSR_MSTATUS;
|
||||
|
@ -174,69 +161,63 @@ module clint(
|
|||
end
|
||||
|
||||
// 发出中断信号前,先写几个CSR寄存器
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
we_o <= `WriteDisable;
|
||||
waddr_o <= `ZeroWord;
|
||||
data_o <= `ZeroWord;
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
csr_we_o <= 1'b0;
|
||||
csr_waddr_o <= 32'h0;
|
||||
csr_wdata_o <= 32'h0;
|
||||
end else begin
|
||||
case (csr_state)
|
||||
// 将mepc寄存器的值设为当前指令地址
|
||||
S_CSR_MEPC: begin
|
||||
we_o <= `WriteEnable;
|
||||
waddr_o <= {20'h0, `CSR_MEPC};
|
||||
data_o <= inst_addr;
|
||||
csr_we_o <= 1'b1;
|
||||
csr_waddr_o <= {20'h0, `CSR_MEPC};
|
||||
csr_wdata_o <= inst_addr;
|
||||
end
|
||||
// 写中断产生的原因
|
||||
S_CSR_MCAUSE: begin
|
||||
we_o <= `WriteEnable;
|
||||
waddr_o <= {20'h0, `CSR_MCAUSE};
|
||||
data_o <= cause;
|
||||
csr_we_o <= 1'b1;
|
||||
csr_waddr_o <= {20'h0, `CSR_MCAUSE};
|
||||
csr_wdata_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]};
|
||||
csr_we_o <= 1'b1;
|
||||
csr_waddr_o <= {20'h0, `CSR_MSTATUS};
|
||||
csr_wdata_o <= {csr_mstatus_i[31:4], 1'b0, csr_mstatus_i[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]};
|
||||
csr_we_o <= 1'b1;
|
||||
csr_waddr_o <= {20'h0, `CSR_MSTATUS};
|
||||
csr_wdata_o <= {csr_mstatus_i[31:4], csr_mstatus_i[7], csr_mstatus_i[2:0]};
|
||||
end
|
||||
default: begin
|
||||
we_o <= `WriteDisable;
|
||||
waddr_o <= `ZeroWord;
|
||||
data_o <= `ZeroWord;
|
||||
csr_we_o <= 1'b0;
|
||||
csr_waddr_o <= 32'h0;
|
||||
csr_wdata_o <= 32'h0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// 发出中断信号给ex模块
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
int_assert_o <= `INT_DEASSERT;
|
||||
int_addr_o <= `ZeroWord;
|
||||
reg in_int_context;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
in_int_context <= 1'b0;
|
||||
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
|
||||
if (csr_state == S_CSR_MSTATUS_MRET) begin
|
||||
in_int_context <= 1'b0;
|
||||
end else if (csr_state != S_CSR_IDLE) begin
|
||||
in_int_context <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign int_assert_o = (csr_state == S_CSR_MCAUSE) | (csr_state == S_CSR_MSTATUS_MRET);
|
||||
assign int_addr_o = (csr_state == S_CSR_MCAUSE)? csr_mtvec_i:
|
||||
(csr_state == S_CSR_MSTATUS_MRET)? csr_mepc_i:
|
||||
32'h0;
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -20,196 +20,121 @@
|
|||
module csr_reg(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
|
||||
// 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模块写寄存器数据
|
||||
// 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模块读寄存器数据
|
||||
|
||||
// from clint
|
||||
// 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模块读寄存器数据
|
||||
input wire[31:0] clint_waddr_i, // clint模块写寄存器地址
|
||||
input wire[31:0] clint_wdata_i, // clint模块写寄存器数据
|
||||
output wire[31:0] mtvec_o, // mtvec寄存器值
|
||||
output wire[31:0] mepc_o, // mepc寄存器值
|
||||
output wire[31:0] mstatus_o // mstatus寄存器值
|
||||
|
||||
);
|
||||
|
||||
reg[`DoubleRegBus] cycle;
|
||||
reg[`RegBus] mtvec;
|
||||
reg[`RegBus] mcause;
|
||||
reg[`RegBus] mepc;
|
||||
reg[`RegBus] mie;
|
||||
reg[`RegBus] mstatus;
|
||||
reg[`RegBus] mscratch;
|
||||
reg[63:0] cycle;
|
||||
reg[31:0] mtvec;
|
||||
reg[31:0] mcause;
|
||||
reg[31:0] mepc;
|
||||
reg[31:0] mie;
|
||||
reg[31:0] mstatus;
|
||||
reg[31:0] 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;
|
||||
assign mtvec_o = mtvec;
|
||||
assign mepc_o = mepc;
|
||||
assign mstatus_o = mstatus;
|
||||
|
||||
// cycle counter
|
||||
// 复位撤销后就一直计数
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
cycle <= {`ZeroWord, `ZeroWord};
|
||||
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
|
||||
|
||||
// write reg
|
||||
// 写寄存器操作
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
mtvec <= `ZeroWord;
|
||||
mcause <= `ZeroWord;
|
||||
mepc <= `ZeroWord;
|
||||
mie <= `ZeroWord;
|
||||
mstatus <= `ZeroWord;
|
||||
mscratch <= `ZeroWord;
|
||||
wire we = exu_we_i | clint_we_i;
|
||||
wire[31:0] waddr = exu_we_i? exu_waddr_i: clint_waddr_i;
|
||||
wire[31:0] wdata = exu_we_i? exu_wdata_i: clint_wdata_i;
|
||||
|
||||
// 写寄存器
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
mtvec <= 32'h0;
|
||||
mcause <= 32'h0;
|
||||
mepc <= 32'h0;
|
||||
mie <= 32'h0;
|
||||
mstatus <= 32'h0;
|
||||
mscratch <= 32'h0;
|
||||
end else begin
|
||||
// 优先响应ex模块的写操作
|
||||
if (we_i == `WriteEnable) begin
|
||||
case (waddr_i[11:0])
|
||||
if (we) begin
|
||||
case (waddr[11:0])
|
||||
`CSR_MTVEC: begin
|
||||
mtvec <= data_i;
|
||||
mtvec <= wdata;
|
||||
end
|
||||
`CSR_MCAUSE: begin
|
||||
mcause <= data_i;
|
||||
mcause <= wdata;
|
||||
end
|
||||
`CSR_MEPC: begin
|
||||
mepc <= data_i;
|
||||
mepc <= wdata;
|
||||
end
|
||||
`CSR_MIE: begin
|
||||
mie <= data_i;
|
||||
mie <= wdata;
|
||||
end
|
||||
`CSR_MSTATUS: begin
|
||||
mstatus <= data_i;
|
||||
mstatus <= wdata;
|
||||
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
|
||||
|
||||
mscratch <= wdata;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// read reg
|
||||
// ex模块读CSR寄存器
|
||||
reg[31:0] exu_rdata;
|
||||
|
||||
// exu模块读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
|
||||
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;
|
||||
end
|
||||
`CSR_MCAUSE: begin
|
||||
exu_rdata = mcause;
|
||||
end
|
||||
`CSR_MEPC: begin
|
||||
exu_rdata = mepc;
|
||||
end
|
||||
`CSR_MIE: begin
|
||||
exu_rdata = mie;
|
||||
end
|
||||
`CSR_MSTATUS: begin
|
||||
exu_rdata = mstatus;
|
||||
end
|
||||
`CSR_MSCRATCH: begin
|
||||
exu_rdata = mscratch;
|
||||
end
|
||||
default: begin
|
||||
exu_rdata = 32'h0;
|
||||
end
|
||||
endcase
|
||||
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
|
||||
assign exu_rdata_o = exu_rdata;
|
||||
|
||||
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
|
|
@ -14,151 +14,109 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
`define CpuResetAddr 32'h0
|
||||
`define CPU_RESET_ADDR 32'h0 // CPU复位地址
|
||||
`define CPU_CLOCK_HZ 50000000 // CPU时钟(50MHZ)
|
||||
`define INST_MEM_START_ADDR 32'h0 // 指令存储器起始地址
|
||||
`define INST_MEM_END_ADDR 32'h0fffffff // 指令存储器结束地址
|
||||
`define JTAG_RESET_FF_LEVELS 5
|
||||
|
||||
`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 ROM_DEPTH 8192 // 指令存储器深度,单位为word(4字节)
|
||||
`define RAM_DEPTH 4096 // 数据存储器深度,单位为word(4字节)
|
||||
|
||||
`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 INT_WIDTH 8
|
||||
`define INT_NONE 8'h0
|
||||
|
||||
`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
|
||||
`define STALL_WIDTH 4
|
||||
`define STALL_PC 2'd0
|
||||
`define STALL_IF 2'd1
|
||||
`define STALL_ID 2'd2
|
||||
`define STALL_EX 2'd3
|
||||
|
||||
// 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
|
||||
`define INST_NOP 32'h00000013
|
||||
`define INST_MRET 32'h30200073
|
||||
`define INST_ECALL 32'h00000073
|
||||
`define INST_EBREAK 32'h00100073
|
||||
|
||||
// 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
|
||||
// 指令译码信息
|
||||
`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
|
||||
|
||||
// S type inst
|
||||
`define INST_TYPE_S 7'b0100011
|
||||
`define INST_SB 3'b000
|
||||
`define INST_SH 3'b001
|
||||
`define INST_SW 3'b010
|
||||
`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)
|
||||
|
||||
// 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
|
||||
`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)
|
||||
|
||||
// J type inst
|
||||
`define INST_JAL 7'b1101111
|
||||
`define INST_JALR 7'b1100111
|
||||
`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 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 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 INST_FENCE 7'b0001111
|
||||
`define INST_ECALL 32'h73
|
||||
`define INST_EBREAK 32'h00100073
|
||||
`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)
|
||||
|
||||
// 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
|
||||
`define DECINFO_SYS_BUS_WIDTH (`DECINFO_GRP_WIDTH+5)
|
||||
`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)
|
||||
|
||||
// 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
|
||||
// 最长的那组
|
||||
`define DECINFO_WIDTH `DECINFO_CSR_BUS_WIDTH
|
||||
|
||||
// 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
|
||||
// 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 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
|
||||
|
|
|
@ -19,23 +19,18 @@
|
|||
// 除法模块
|
||||
// 试商法实现32位整数除法
|
||||
// 每次除法运算至少需要33个时钟周期才能完成
|
||||
module div(
|
||||
module divider(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
|
||||
// from ex
|
||||
input wire[`RegBus] dividend_i, // 被除数
|
||||
input wire[`RegBus] divisor_i, // 除数
|
||||
input wire start_i, // 开始信号,运算期间这个信号需要一直保持有效
|
||||
input wire[2:0] op_i, // 具体是哪一条指令
|
||||
input wire[`RegAddrBus] reg_waddr_i, // 运算结束后需要写的寄存器
|
||||
input wire[31:0] dividend_i, // 被除数
|
||||
input wire[31:0] divisor_i, // 除数
|
||||
input wire start_i, // 开始信号,运算期间这个信号需要一直保持有效
|
||||
input wire[3:0] op_i, // 具体是哪一条指令
|
||||
|
||||
// to ex
|
||||
output reg[`RegBus] result_o, // 除法结果,高32位是余数,低32位是商
|
||||
output reg ready_o, // 运算结束信号
|
||||
output reg busy_o, // 正在运算信号
|
||||
output reg[`RegAddrBus] reg_waddr_o // 运算结束后需要写的寄存器
|
||||
output reg[31:0] result_o, // 除法结果,高32位是余数,低32位是商
|
||||
output reg ready_o // 运算结束信号
|
||||
|
||||
);
|
||||
|
||||
|
@ -45,20 +40,20 @@ module div(
|
|||
localparam STATE_CALC = 4'b0100;
|
||||
localparam STATE_END = 4'b1000;
|
||||
|
||||
reg[`RegBus] dividend_r;
|
||||
reg[`RegBus] divisor_r;
|
||||
reg[2:0] op_r;
|
||||
reg[31:0] dividend_r;
|
||||
reg[31:0] divisor_r;
|
||||
reg[3:0] op_r;
|
||||
reg[3:0] state;
|
||||
reg[31:0] count;
|
||||
reg[`RegBus] div_result;
|
||||
reg[`RegBus] div_remain;
|
||||
reg[`RegBus] minuend;
|
||||
reg[31:0] div_result;
|
||||
reg[31:0] div_remain;
|
||||
reg[31:0] minuend;
|
||||
reg invert_result;
|
||||
|
||||
wire op_div = (op_r == `INST_DIV);
|
||||
wire op_divu = (op_r == `INST_DIVU);
|
||||
wire op_rem = (op_r == `INST_REM);
|
||||
wire op_remu = (op_r == `INST_REMU);
|
||||
wire op_div = op_r[3];
|
||||
wire op_divu = op_r[2];
|
||||
wire op_rem = op_r[1];
|
||||
wire op_remu = op_r[0];
|
||||
|
||||
wire[31:0] dividend_invert = (-dividend_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];
|
||||
|
||||
// 状态机实现
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
state <= STATE_IDLE;
|
||||
ready_o <= `DivResultNotReady;
|
||||
result_o <= `ZeroWord;
|
||||
div_result <= `ZeroWord;
|
||||
div_remain <= `ZeroWord;
|
||||
ready_o <= 1'b0;
|
||||
result_o <= 32'h0;
|
||||
div_result <= 32'h0;
|
||||
div_remain <= 32'h0;
|
||||
op_r <= 3'h0;
|
||||
reg_waddr_o <= `ZeroWord;
|
||||
dividend_r <= `ZeroWord;
|
||||
divisor_r <= `ZeroWord;
|
||||
minuend <= `ZeroWord;
|
||||
dividend_r <= 32'h0;
|
||||
divisor_r <= 32'h0;
|
||||
minuend <= 32'h0;
|
||||
invert_result <= 1'b0;
|
||||
busy_o <= `False;
|
||||
count <= `ZeroWord;
|
||||
count <= 32'h0;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_IDLE: begin
|
||||
if (start_i == `DivStart) begin
|
||||
if (start_i) begin
|
||||
op_r <= op_i;
|
||||
dividend_r <= dividend_i;
|
||||
divisor_r <= divisor_i;
|
||||
reg_waddr_o <= reg_waddr_i;
|
||||
state <= STATE_START;
|
||||
busy_o <= `True;
|
||||
end else begin
|
||||
op_r <= 3'h0;
|
||||
reg_waddr_o <= `ZeroWord;
|
||||
dividend_r <= `ZeroWord;
|
||||
divisor_r <= `ZeroWord;
|
||||
ready_o <= `DivResultNotReady;
|
||||
result_o <= `ZeroWord;
|
||||
busy_o <= `False;
|
||||
dividend_r <= 32'h0;
|
||||
divisor_r <= 32'h0;
|
||||
ready_o <= 1'b0;
|
||||
result_o <= 32'h0;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_START: begin
|
||||
if (start_i == `DivStart) begin
|
||||
if (start_i) begin
|
||||
// 除数为0
|
||||
if (divisor_r == `ZeroWord) begin
|
||||
if (divisor_r == 32'h0) begin
|
||||
if (op_div | op_divu) begin
|
||||
result_o <= 32'hffffffff;
|
||||
end else begin
|
||||
result_o <= dividend_r;
|
||||
end
|
||||
ready_o <= `DivResultReady;
|
||||
ready_o <= 1'b1;
|
||||
state <= STATE_IDLE;
|
||||
busy_o <= `False;
|
||||
// 除数不为0
|
||||
end else begin
|
||||
busy_o <= `True;
|
||||
count <= 32'h40000000;
|
||||
state <= STATE_CALC;
|
||||
div_result <= `ZeroWord;
|
||||
div_remain <= `ZeroWord;
|
||||
div_result <= 32'h0;
|
||||
div_remain <= 32'h0;
|
||||
|
||||
// DIV和REM这两条指令是有符号数运算指令
|
||||
if (op_div | op_rem) begin
|
||||
|
@ -151,14 +138,13 @@ module div(
|
|||
end
|
||||
end else begin
|
||||
state <= STATE_IDLE;
|
||||
result_o <= `ZeroWord;
|
||||
ready_o <= `DivResultNotReady;
|
||||
busy_o <= `False;
|
||||
result_o <= 32'h0;
|
||||
ready_o <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_CALC: begin
|
||||
if (start_i == `DivStart) begin
|
||||
if (start_i) begin
|
||||
dividend_r <= {dividend_r[30:0], 1'b0};
|
||||
div_result <= div_result_tmp;
|
||||
count <= {1'b0, count[31:1]};
|
||||
|
@ -174,17 +160,15 @@ module div(
|
|||
end
|
||||
end else begin
|
||||
state <= STATE_IDLE;
|
||||
result_o <= `ZeroWord;
|
||||
ready_o <= `DivResultNotReady;
|
||||
busy_o <= `False;
|
||||
result_o <= 32'h0;
|
||||
ready_o <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_END: begin
|
||||
if (start_i == `DivStart) begin
|
||||
ready_o <= `DivResultReady;
|
||||
if (start_i) begin
|
||||
ready_o <= 1'b1;
|
||||
state <= STATE_IDLE;
|
||||
busy_o <= `False;
|
||||
if (op_div | op_divu) begin
|
||||
if (invert_result) begin
|
||||
result_o <= (-div_result);
|
||||
|
@ -200,9 +184,8 @@ module div(
|
|||
end
|
||||
end else begin
|
||||
state <= STATE_IDLE;
|
||||
result_o <= `ZeroWord;
|
||||
ready_o <= `DivResultNotReady;
|
||||
busy_o <= `False;
|
||||
result_o <= 32'h0;
|
||||
ready_o <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
875
rtl/core/ex.v
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,378 @@
|
|||
/*
|
||||
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 exu(
|
||||
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
|
||||
// clint
|
||||
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指令
|
||||
|
||||
// mem
|
||||
input wire[31:0] mem_rdata_i, // 内存输入数据
|
||||
input wire mem_req_ready_i,
|
||||
input wire mem_rsp_valid_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_sel_o, // 字节位
|
||||
output wire mem_req_valid_o,
|
||||
output wire mem_rsp_ready_o,
|
||||
output wire mem_access_misaligned_o,
|
||||
|
||||
// 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,
|
||||
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, // 跳转目的地址
|
||||
|
||||
// from idu_exu
|
||||
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
|
||||
|
||||
);
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
|
||||
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),
|
||||
// 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)
|
||||
);
|
||||
|
||||
assign inst_ecall_o = sys_op_ecall_o;
|
||||
assign inst_ebreak_o = sys_op_ebreak_o;
|
||||
assign inst_mret_o = sys_op_mret_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_req_ready_i(mem_req_ready_i),
|
||||
.mem_rsp_valid_i(mem_rsp_valid_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_sel_o(mem_sel_o),
|
||||
.mem_req_valid_o(mem_req_valid_o),
|
||||
.mem_rsp_ready_o(mem_rsp_ready_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),
|
||||
.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_i),
|
||||
.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;
|
||||
|
||||
assign jump_flag_o = bjp_cmp_res_o | bjp_op_jump_o | sys_op_fence_o | int_assert_i;
|
||||
assign jump_addr_o = int_assert_i? int_addr_i:
|
||||
sys_op_fence_o? next_pc_i:
|
||||
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;
|
||||
assign csr_wdata_o = alu_res_o;
|
||||
|
||||
assign mem_we_o = mem_mem_we_o;
|
||||
assign mem_wdata_o = mem_wdata;
|
||||
|
||||
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.v"
|
||||
|
||||
|
||||
`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.v"
|
||||
|
||||
|
||||
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,210 @@
|
|||
/*
|
||||
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 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,
|
||||
|
||||
// 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
|
||||
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
// 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];
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
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 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_req_ready_i,
|
||||
input wire mem_rsp_valid_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_sel_o,
|
||||
output wire mem_req_valid_o,
|
||||
output wire mem_rsp_ready_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_sel_o[0] = mem_addr_index00 | mem_op_sw_i;
|
||||
assign mem_sel_o[1] = mem_addr_index01 | (mem_op_sh_i & mem_addr_index00) | mem_op_sw_i;
|
||||
assign mem_sel_o[2] = mem_addr_index10 | mem_op_sw_i;
|
||||
assign mem_sel_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 mem_req_hsked = (mem_req_valid_o & mem_req_ready_i);
|
||||
wire mem_rsp_hsked = (mem_rsp_valid_i & mem_rsp_ready_o);
|
||||
|
||||
reg mem_rsp_hsked_r;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
mem_rsp_hsked_r <= 1'b0;
|
||||
end else begin
|
||||
mem_rsp_hsked_r <= mem_rsp_hsked & (~mem_rsp_hsked_r);
|
||||
end
|
||||
end
|
||||
|
||||
assign mem_rsp_ready_o = 1'b1;
|
||||
|
||||
// 请求访问总线
|
||||
assign mem_req_valid_o = req_mem_i;
|
||||
// 暂停流水线
|
||||
assign mem_stall_o = req_mem_i & (~mem_rsp_hsked_r);
|
||||
// 读、写内存地址
|
||||
assign mem_addr_o = mem_addr_i;
|
||||
|
||||
// 写寄存器使能,收到ack时数据才有效
|
||||
assign mem_reg_we_o = (mem_op_lb_i | mem_op_lh_i | mem_op_lw_i | mem_op_lbu_i | mem_op_lhu_i) & mem_rsp_hsked_r;
|
||||
|
||||
// 写内存使能
|
||||
assign mem_mem_we_o = (mem_op_sb_i | mem_op_sh_i | mem_op_sw_i) & mem_rsp_hsked_r;
|
||||
|
||||
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;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
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 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,
|
||||
|
||||
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);
|
||||
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.v"
|
||||
|
||||
// 通用寄存器模块
|
||||
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
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
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,303 @@
|
|||
/*
|
||||
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 idu(
|
||||
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
|
||||
// from if_id
|
||||
input wire[31:0] inst_i, // 指令内容
|
||||
input wire[31:0] inst_addr_i, // 指令地址
|
||||
|
||||
// from gpr_reg
|
||||
input wire[31:0] rs1_rdata_i, // 通用寄存器1输入数据
|
||||
input wire[31:0] rs2_rdata_i, // 通用寄存器2输入数据
|
||||
|
||||
output wire stall_o,
|
||||
|
||||
// to id_ex
|
||||
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[4:0] rs1_raddr_o,
|
||||
output wire[4:0] rs2_raddr_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
|
||||
|
||||
);
|
||||
|
||||
assign inst_o = inst_i;
|
||||
assign rs1_rdata_o = rs1_rdata_i;
|
||||
assign rs2_rdata_o = rs2_rdata_i;
|
||||
|
||||
// 取出指令中的每一个域
|
||||
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];
|
||||
wire[11:0] type_i_imm_11_0 = inst_i[31:20];
|
||||
wire[6:0] type_s_imm_11_5 = inst_i[31:25];
|
||||
wire[4:0] type_s_imm_4_0 = inst_i[11:7];
|
||||
wire[6:0] type_b_imm_12_10_5 = inst_i[31:25];
|
||||
wire[4:0] type_b_imm_4_1_11 = inst_i[11:7];
|
||||
wire[19:0] type_u_imm_31_12 = inst_i[31:12];
|
||||
wire[19:0] type_j_imm_31_12 = inst_i[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_i == `INST_ECALL);
|
||||
wire inst_ebreak = (inst_i == `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_i == `INST_NOP);
|
||||
wire inst_mret = (inst_i == `INST_MRET);
|
||||
|
||||
// 将指令分类
|
||||
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_i[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_FENCE] = inst_fence | inst_fence_i;
|
||||
|
||||
// 指令中的立即数
|
||||
wire[31:0] inst_u_type_imm = {inst_i[31:12], 12'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[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_s_type_imm = {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]};
|
||||
wire[31:0] inst_i_type_imm = {{20{inst_i[31]}}, inst_i[31:20]};
|
||||
wire[31:0] inst_csr_type_imm = {27'h0, inst_i[19:15]};
|
||||
wire[31:0] inst_shift_type_imm = {27'h0, inst_i[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;
|
||||
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;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
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 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[`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[`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? 32'h0: inst_i;
|
||||
wire[31:0] inst;
|
||||
gen_en_dff #(32) inst_ff(clk, rst_n, en, i_inst, inst);
|
||||
assign inst_o = inst;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
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 ifu(
|
||||
|
||||
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 jtag_halt_i,
|
||||
|
||||
output wire[31:0] inst_o,
|
||||
output wire[31:0] pc_o,
|
||||
output wire inst_valid_o,
|
||||
|
||||
output wire[31:0] ibus_addr_o,
|
||||
input wire[31:0] ibus_data_i,
|
||||
output wire[31:0] ibus_data_o,
|
||||
output wire[3:0] ibus_sel_o,
|
||||
output wire ibus_we_o,
|
||||
output wire req_valid_o,
|
||||
input wire req_ready_i,
|
||||
input wire rsp_valid_i,
|
||||
output wire rsp_ready_o
|
||||
|
||||
);
|
||||
|
||||
assign req_valid_o = (~rst_n)? 1'b0:
|
||||
(flush_i)? 1'b0:
|
||||
stall_i[`STALL_PC]? 1'b0:
|
||||
jtag_halt_i? 1'b0:
|
||||
1'b1;
|
||||
assign rsp_ready_o = (~rst_n)? 1'b0: 1'b1;
|
||||
|
||||
wire ifu_req_hsked = (req_valid_o & req_ready_i);
|
||||
wire ifu_rsp_hsked = (rsp_valid_i & rsp_ready_o);
|
||||
|
||||
// 在执行多周期指令或者请求不到总线时需要暂停
|
||||
wire stall = stall_i[`STALL_PC] | (~ifu_req_hsked);
|
||||
|
||||
reg[31:0] pc;
|
||||
reg[31:0] pc_prev;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
// 复位
|
||||
if (!rst_n) begin
|
||||
pc <= `CPU_RESET_ADDR;
|
||||
pc_prev <= 32'h0;
|
||||
// 冲刷
|
||||
end else if (flush_i) begin
|
||||
pc <= flush_addr_i;
|
||||
// 暂停,取上一条指令
|
||||
end else if (stall) begin
|
||||
pc <= pc_prev;
|
||||
// 取下一条指令
|
||||
end else begin
|
||||
pc <= pc + 32'h4;
|
||||
pc_prev <= pc;
|
||||
end
|
||||
end
|
||||
|
||||
wire[31:0] pc_r;
|
||||
// 将PC打一拍
|
||||
wire pc_ena = (~stall);
|
||||
gen_en_dff #(32) pc_dff(clk, rst_n, pc_ena, pc, pc_r);
|
||||
|
||||
reg req_hasked_r;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
req_hasked_r <= 1'b1;
|
||||
end else begin
|
||||
req_hasked_r <= ifu_req_hsked;
|
||||
end
|
||||
end
|
||||
|
||||
wire req_switched = ifu_req_hsked & (~req_hasked_r);
|
||||
|
||||
reg rsp_hasked_r;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rsp_hasked_r <= 1'b1;
|
||||
end else begin
|
||||
rsp_hasked_r <= ifu_rsp_hsked;
|
||||
end
|
||||
end
|
||||
|
||||
wire rsp_switched = ifu_rsp_hsked & (~rsp_hasked_r);
|
||||
|
||||
// 总线切换有两种情况:
|
||||
// 1.访存地址位于指令存储器:当访存完成后,ifu_req_hsked和ifu_rsp_hsked信号会同时从0变为1
|
||||
// 2.访存地址不位于指令存储器:当访存完成后,ifu_req_hsked先从0变为1和ifu_rsp_hsked后从0变为1
|
||||
// 只有第2种情况下取出来的指令是有效的,这里要把这两种情况识别出来
|
||||
wire bus_switched = req_switched & rsp_switched;
|
||||
|
||||
// 取指地址
|
||||
assign ibus_addr_o = pc;
|
||||
assign pc_o = pc_r;
|
||||
wire inst_valid = ifu_rsp_hsked & (~flush_i) & (~bus_switched);
|
||||
assign inst_o = inst_valid? ibus_data_i: `INST_NOP;
|
||||
|
||||
assign ibus_sel_o = 4'b1111;
|
||||
assign ibus_we_o = 1'b0;
|
||||
assign ibus_data_o = 32'h0;
|
||||
|
||||
endmodule
|
|
@ -17,36 +17,32 @@
|
|||
`include "defines.v"
|
||||
|
||||
// 将指令向译码模块传递
|
||||
module if_id(
|
||||
module ifu_idu(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
|
||||
input wire[`InstBus] inst_i, // 指令内容
|
||||
input wire[`InstAddrBus] inst_addr_i, // 指令地址
|
||||
input wire[31:0] inst_i, // 指令内容
|
||||
input wire[31:0] inst_addr_i, // 指令地址
|
||||
input wire[`STALL_WIDTH-1:0] stall_i, // 流水线暂停
|
||||
input wire flush_i, // 流水线冲刷
|
||||
input wire inst_valid_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 // 指令地址
|
||||
output wire[31:0] inst_o, // 指令内容
|
||||
output wire[31:0] inst_addr_o // 指令地址
|
||||
|
||||
);
|
||||
|
||||
wire hold_en = (hold_flag_i >= `Hold_If);
|
||||
wire en = !stall_i[`STALL_ID] | flush_i;
|
||||
|
||||
wire[`InstBus] inst;
|
||||
gen_pipe_dff #(32) inst_ff(clk, rst, hold_en, `INST_NOP, inst_i, inst);
|
||||
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[`InstAddrBus] inst_addr;
|
||||
gen_pipe_dff #(32) inst_addr_ff(clk, rst, hold_en, `ZeroWord, inst_addr_i, inst_addr);
|
||||
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[`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,65 @@
|
|||
/*
|
||||
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 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 | stall_from_clint_i;
|
||||
|
||||
reg[`STALL_WIDTH-1:0] stall;
|
||||
|
||||
always @ (*) begin
|
||||
if (stall_from_ex_i | 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 else if (stall_from_id_i) begin
|
||||
stall[`STALL_EX] = 1'b0;
|
||||
stall[`STALL_ID] = 1'b0;
|
||||
stall[`STALL_IF] = 1'b1;
|
||||
stall[`STALL_PC] = 1'b1;
|
||||
end else begin
|
||||
stall[`STALL_EX] = 1'b0;
|
||||
stall[`STALL_ID] = 1'b0;
|
||||
stall[`STALL_IF] = 1'b0;
|
||||
stall[`STALL_PC] = 1'b0;
|
||||
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
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
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||
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.
|
||||
|
@ -16,36 +16,44 @@
|
|||
|
||||
`include "defines.v"
|
||||
|
||||
// PC寄存器模块
|
||||
module pc_reg(
|
||||
// 复位控制模块
|
||||
module rst_ctrl(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
input wire jump_flag_i, // 跳转标志
|
||||
input wire[`InstAddrBus] jump_addr_i, // 跳转地址
|
||||
input wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志
|
||||
input wire jtag_reset_flag_i, // 复位标志
|
||||
input wire rst_ext_i,
|
||||
input wire rst_jtag_i,
|
||||
|
||||
output reg[`InstAddrBus] pc_o // PC指针
|
||||
output wire core_rst_n_o,
|
||||
output wire jtag_rst_n_o
|
||||
|
||||
);
|
||||
|
||||
wire ext_rst_r;
|
||||
|
||||
gen_ticks_sync #(
|
||||
.DP(2),
|
||||
.DW(1)
|
||||
) ext_rst_sync(
|
||||
.rst_n(rst_ext_i),
|
||||
.clk(clk),
|
||||
.din(1'b1),
|
||||
.dout(ext_rst_r)
|
||||
);
|
||||
|
||||
reg[`JTAG_RESET_FF_LEVELS-1:0] jtag_rst_r;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
// 复位
|
||||
if (rst == `RstEnable || jtag_reset_flag_i == 1'b1) begin
|
||||
pc_o <= `CpuResetAddr;
|
||||
// 跳转
|
||||
end else if (jump_flag_i == `JumpEnable) begin
|
||||
pc_o <= jump_addr_i;
|
||||
// 暂停
|
||||
end else if (hold_flag_i >= `Hold_Pc) begin
|
||||
pc_o <= pc_o;
|
||||
// 地址加4
|
||||
if (!rst_ext_i) begin
|
||||
jtag_rst_r[`JTAG_RESET_FF_LEVELS-1:0] <= {`JTAG_RESET_FF_LEVELS{1'b1}};
|
||||
end if (rst_jtag_i) begin
|
||||
jtag_rst_r[`JTAG_RESET_FF_LEVELS-1:0] <= {`JTAG_RESET_FF_LEVELS{1'b0}};
|
||||
end else begin
|
||||
pc_o <= pc_o + 4'h4;
|
||||
jtag_rst_r[`JTAG_RESET_FF_LEVELS-1:0] <= {jtag_rst_r[`JTAG_RESET_FF_LEVELS-2:0], 1'b1};
|
||||
end
|
||||
end
|
||||
|
||||
assign core_rst_n_o = ext_rst_r & jtag_rst_r[`JTAG_RESET_FF_LEVELS-1];
|
||||
assign jtag_rst_n_o = ext_rst_r;
|
||||
|
||||
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,318 @@
|
|||
/*
|
||||
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_core(
|
||||
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
|
||||
output wire[31:0] dbus_addr_o,
|
||||
input wire[31:0] dbus_data_i,
|
||||
output wire[31:0] dbus_data_o,
|
||||
output wire[3:0] dbus_sel_o,
|
||||
output wire dbus_we_o,
|
||||
output wire dbus_req_valid_o,
|
||||
input wire dbus_req_ready_i,
|
||||
input wire dbus_rsp_valid_i,
|
||||
output wire dbus_rsp_ready_o,
|
||||
|
||||
output wire[31:0] ibus_addr_o, // 取指地址
|
||||
input wire[31:0] ibus_data_i, // 取到的指令内容
|
||||
output wire[31:0] ibus_data_o,
|
||||
output wire[3:0] ibus_sel_o,
|
||||
output wire ibus_we_o,
|
||||
output wire ibus_req_valid_o,
|
||||
input wire ibus_req_ready_i,
|
||||
input wire ibus_rsp_valid_i,
|
||||
output wire ibus_rsp_ready_o,
|
||||
|
||||
input wire jtag_halt_i,
|
||||
input wire[`INT_WIDTH-1:0] int_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[`INT_WIDTH-1:0] if_int_flag_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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// pipe_ctrl模块输出信号
|
||||
wire[31:0] ctrl_flush_addr_o;
|
||||
wire ctrl_flush_o;
|
||||
wire[`STALL_WIDTH-1:0] ctrl_stall_o;
|
||||
|
||||
// clint模块输出信号
|
||||
wire clint_csr_we_o;
|
||||
wire[31:0] clint_csr_waddr_o;
|
||||
wire[31:0] clint_csr_wdata_o;
|
||||
wire clint_stall_flag_o;
|
||||
wire[31:0] clint_int_addr_o;
|
||||
wire clint_int_assert_o;
|
||||
|
||||
assign dbus_addr_o = ex_mem_addr_o;
|
||||
assign dbus_data_o = ex_mem_wdata_o;
|
||||
assign dbus_we_o = ex_mem_we_o;
|
||||
assign dbus_sel_o = ex_mem_sel_o;
|
||||
assign dbus_req_valid_o = ex_mem_req_valid_o;
|
||||
assign dbus_rsp_ready_o = ex_mem_rsp_ready_o;
|
||||
|
||||
|
||||
ifu 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),
|
||||
.jtag_halt_i(jtag_halt_i),
|
||||
.inst_o(ifetch_inst_o),
|
||||
.pc_o(ifetch_pc_o),
|
||||
.inst_valid_o(ifetch_inst_valid_o),
|
||||
.ibus_addr_o(ibus_addr_o),
|
||||
.ibus_data_i(ibus_data_i),
|
||||
.ibus_data_o(ibus_data_o),
|
||||
.ibus_sel_o(ibus_sel_o),
|
||||
.ibus_we_o(ibus_we_o),
|
||||
.req_valid_o(ibus_req_valid_o),
|
||||
.req_ready_i(ibus_req_ready_i),
|
||||
.rsp_valid_i(ibus_rsp_valid_i),
|
||||
.rsp_ready_o(ibus_rsp_ready_o)
|
||||
);
|
||||
|
||||
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(clint_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),
|
||||
.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),
|
||||
.clint_we_i(clint_csr_we_o),
|
||||
.clint_waddr_i(clint_csr_waddr_o),
|
||||
.clint_wdata_i(clint_csr_wdata_o),
|
||||
.mtvec_o(csr_mtvec_o),
|
||||
.mepc_o(csr_mepc_o),
|
||||
.mstatus_o(csr_mstatus_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),
|
||||
.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),
|
||||
.rs1_rdata_i(regs_rdata1_o),
|
||||
.rs2_rdata_i(regs_rdata2_o),
|
||||
.inst_o(id_inst_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),
|
||||
.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_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 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(dbus_data_i),
|
||||
.mem_req_ready_i(dbus_req_ready_i),
|
||||
.mem_rsp_valid_i(dbus_rsp_valid_i),
|
||||
.mem_wdata_o(ex_mem_wdata_o),
|
||||
.mem_addr_o(ex_mem_addr_o),
|
||||
.mem_we_o(ex_mem_we_o),
|
||||
.mem_sel_o(ex_mem_sel_o),
|
||||
.mem_req_valid_o(ex_mem_req_valid_o),
|
||||
.mem_rsp_ready_o(ex_mem_rsp_ready_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(clint_int_assert_o),
|
||||
.int_addr_i(clint_int_addr_o),
|
||||
.inst_ecall_o(ex_inst_ecall_o),
|
||||
.inst_ebreak_o(ex_inst_ebreak_o),
|
||||
.inst_mret_o(ex_inst_mret_o),
|
||||
.int_stall_i(clint_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),
|
||||
.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)
|
||||
);
|
||||
|
||||
clint u_clint(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.int_flag_i(int_i),
|
||||
.inst_ecall_i(ex_inst_ecall_o),
|
||||
.inst_ebreak_i(ex_inst_ebreak_o),
|
||||
.inst_mret_i(ex_inst_mret_o),
|
||||
.inst_addr_i(ie_dec_pc_o),
|
||||
.jump_flag_i(ex_jump_flag_o),
|
||||
.mem_access_misaligned_i(ex_mem_access_misaligned_o),
|
||||
.csr_mtvec_i(csr_mtvec_o),
|
||||
.csr_mepc_i(csr_mepc_o),
|
||||
.csr_mstatus_i(csr_mstatus_o),
|
||||
.csr_we_o(clint_csr_we_o),
|
||||
.csr_waddr_o(clint_csr_waddr_o),
|
||||
.csr_wdata_o(clint_csr_wdata_o),
|
||||
.stall_flag_o(clint_stall_flag_o),
|
||||
.int_addr_o(clint_int_addr_o),
|
||||
.int_assert_o(clint_int_assert_o)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -14,11 +14,6 @@
|
|||
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
|
||||
|
@ -50,8 +45,13 @@ module jtag_dm #(
|
|||
dm_mem_addr_o,
|
||||
dm_mem_wdata_o,
|
||||
dm_mem_rdata_i,
|
||||
dm_mem_sel_o,
|
||||
|
||||
req_valid_o,
|
||||
req_ready_i,
|
||||
rsp_valid_i,
|
||||
rsp_ready_o,
|
||||
|
||||
dm_op_req_o,
|
||||
dm_halt_req_o,
|
||||
dm_reset_req_o
|
||||
|
||||
|
@ -78,7 +78,11 @@ module jtag_dm #(
|
|||
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[3:0] dm_mem_sel_o;
|
||||
output wire req_valid_o;
|
||||
input wire req_ready_i;
|
||||
input wire rsp_valid_i;
|
||||
output wire rsp_ready_o;
|
||||
output wire dm_halt_req_o;
|
||||
output wire dm_reset_req_o;
|
||||
|
||||
|
@ -107,8 +111,13 @@ module jtag_dm #(
|
|||
localparam COMMAND = 6'h17;
|
||||
localparam DPC = 16'h7b1;
|
||||
|
||||
localparam OP_SUCC = 2'b00;
|
||||
localparam OP_SUCC = 2'b00;
|
||||
|
||||
localparam STATE_IDLE = 3'b001;
|
||||
localparam STATE_EXE = 3'b010;
|
||||
localparam STATE_END = 3'b100;
|
||||
|
||||
reg[2:0] state;
|
||||
reg[31:0] read_data;
|
||||
reg dm_reg_we;
|
||||
reg[4:0] dm_reg_addr;
|
||||
|
@ -116,21 +125,29 @@ module jtag_dm #(
|
|||
reg dm_mem_we;
|
||||
reg[31:0] dm_mem_addr;
|
||||
reg[31:0] dm_mem_wdata;
|
||||
reg[31:0] dm_mem_rdata;
|
||||
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[DTM_REQ_BITS-1:0] rx_data; // driver请求数据
|
||||
reg[DTM_REQ_BITS-1:0] rx_data_r;
|
||||
|
||||
wire[31:0] sbaddress0_next = sbaddress0 + 4;
|
||||
wire[3:0] dm_mem_sel = (sbcs[19:17] == 3'd0)? 4'b0001:
|
||||
(sbcs[19:17] == 3'd1)? 4'b0011:
|
||||
4'b1111;
|
||||
wire[2:0] address_inc_step = (sbcs[19:17] == 3'd0)? 3'd1:
|
||||
(sbcs[19:17] == 3'd1)? 3'd2:
|
||||
3'd4;
|
||||
wire[31:0] sbaddress0_next = sbaddress0 + {29'h0, address_inc_step};
|
||||
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[DMI_OP_BITS-1:0] op = rx_data_r[DMI_OP_BITS-1:0];
|
||||
wire[DMI_DATA_BITS-1:0] data = rx_data_r[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
|
||||
wire[DMI_ADDR_BITS-1:0] address = rx_data_r[DTM_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
|
||||
|
||||
wire read_dmstatus = (op == `DTM_OP_READ) & (address == DMSTATUS);
|
||||
wire req_sys_bus = ~(address == DMSTATUS);
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
|
@ -151,155 +168,177 @@ module jtag_dm #(
|
|||
command <= 32'h0;
|
||||
dm_reg_wdata <= 32'h0;
|
||||
dm_mem_wdata <= 32'h0;
|
||||
dm_mem_rdata <= 32'h0;
|
||||
dmstatus <= 32'h430c82;
|
||||
is_read_reg <= 1'b0;
|
||||
read_data <= 32'h0;
|
||||
need_resp <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
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
|
||||
case (state)
|
||||
STATE_IDLE: begin
|
||||
// 接收到driver的请求
|
||||
if (rx_valid) begin
|
||||
rx_data_r <= rx_data;
|
||||
state <= STATE_EXE;
|
||||
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
|
||||
STATE_EXE: begin
|
||||
state <= STATE_END;
|
||||
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;
|
||||
if (sbcs[16] == 1'b1) begin
|
||||
sbaddress0 <= sbaddress0_next;
|
||||
end
|
||||
if (sbcs[15] == 1'b1) begin
|
||||
dm_mem_addr <= sbaddress0_next;
|
||||
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);
|
||||
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
|
||||
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;
|
||||
// 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]};
|
||||
// reset
|
||||
end else if (data[1] == 1'b1) begin
|
||||
dm_reset_req <= 1'b1;
|
||||
dm_halt_req <= 1'b0;
|
||||
dmstatus <= {dmstatus[31:12], 4'hc, 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
|
||||
if (data[15:0] < 16'h1020) begin
|
||||
dm_reg_we <= 1'b1;
|
||||
dm_reg_wdata <= data0;
|
||||
end
|
||||
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;
|
||||
DATA0: begin
|
||||
data0 <= 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;
|
||||
SBCS: begin
|
||||
sbcs <= data;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
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
|
||||
`DTM_OP_NOP: begin
|
||||
read_data <= {(DMI_DATA_BITS){1'b0}};
|
||||
end
|
||||
endcase
|
||||
end
|
||||
STATE_END: begin
|
||||
state <= STATE_IDLE;
|
||||
dm_mem_rdata <= dm_mem_rdata_i;
|
||||
need_resp <= 1'b0;
|
||||
dm_mem_we <= 1'b0;
|
||||
dm_reg_we <= 1'b0;
|
||||
dm_reset_req <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
wire jtag_req_hsked = (req_valid_o & req_ready_i);
|
||||
wire jtag_rsp_hsked = (rsp_valid_i & rsp_ready_o);
|
||||
|
||||
assign rsp_ready_o = (~rst_n)? 1'b0: 1'b1;
|
||||
assign dm_mem_sel_o = dm_mem_sel;
|
||||
|
||||
|
||||
assign dm_reg_we_o = dm_reg_we;
|
||||
assign dm_reg_addr_o = dm_reg_addr;
|
||||
assign dm_reg_wdata_o = dm_reg_wdata;
|
||||
|
@ -307,7 +346,7 @@ module jtag_dm #(
|
|||
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 req_valid_o = (state != STATE_IDLE) & req_sys_bus;
|
||||
assign dm_halt_req_o = dm_halt_req;
|
||||
assign dm_reset_req_o = dm_reset_req;
|
||||
|
||||
|
@ -322,7 +361,7 @@ module jtag_dm #(
|
|||
.ack_i(dtm_ack_i),
|
||||
.req_i(need_resp),
|
||||
.req_data_i(dm_resp_data),
|
||||
.idle_o(tx_idle),
|
||||
.idle_o(),
|
||||
.req_o(dm_resp_valid_o),
|
||||
.req_data_o(dm_resp_data_o)
|
||||
);
|
||||
|
|
|
@ -14,11 +14,6 @@
|
|||
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,
|
||||
|
@ -186,19 +181,19 @@ module jtag_driver #(
|
|||
// 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_valid <= 1'b0;
|
||||
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_valid <= 1'b1;
|
||||
dtm_req_data <= shift_reg;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
dtm_req_valid <= `DTM_REQ_INVALID;
|
||||
dtm_req_valid <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,11 +34,17 @@ module jtag_top #(
|
|||
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[3:0] mem_sel_o,
|
||||
|
||||
output wire req_valid_o,
|
||||
input wire req_ready_i,
|
||||
input wire rsp_valid_i,
|
||||
output wire rsp_ready_o,
|
||||
|
||||
output wire halt_req_o,
|
||||
output wire reset_req_o
|
||||
|
@ -48,16 +54,15 @@ module jtag_top #(
|
|||
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
|
||||
// jtag_driver输出信号
|
||||
wire dtm_ack_o;
|
||||
wire dtm_req_valid_o;
|
||||
wire[DTM_REQ_BITS - 1:0] dtm_req_data_o;
|
||||
|
||||
// jtag_dm
|
||||
// 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;
|
||||
|
||||
|
@ -100,7 +105,11 @@ module jtag_top #(
|
|||
.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_mem_sel_o(mem_sel_o),
|
||||
.req_valid_o(req_valid_o),
|
||||
.req_ready_i(req_ready_i),
|
||||
.rsp_valid_i(rsp_valid_i),
|
||||
.rsp_ready_o(rsp_ready_o),
|
||||
.dm_halt_req_o(halt_req_o),
|
||||
.dm_reset_req_o(reset_req_o)
|
||||
);
|
||||
|
|
|
@ -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
|
|
@ -14,18 +14,21 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
// GPIO模块
|
||||
module gpio(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
input wire we_i,
|
||||
input wire rst_n,
|
||||
input wire[31:0] addr_i,
|
||||
input wire[31:0] data_i,
|
||||
input wire[3:0] sel_i,
|
||||
input wire we_i,
|
||||
output wire[31:0] data_o,
|
||||
|
||||
output reg[31:0] data_o,
|
||||
input wire req_valid_i,
|
||||
output wire req_ready_o,
|
||||
output wire rsp_valid_o,
|
||||
input wire rsp_ready_i,
|
||||
|
||||
input wire[1:0] io_pin_i,
|
||||
output wire[31:0] reg_ctrl,
|
||||
|
@ -33,38 +36,60 @@ module gpio(
|
|||
|
||||
);
|
||||
|
||||
|
||||
// GPIO控制寄存器
|
||||
// GPIO寄存器(偏移)地址
|
||||
localparam GPIO_CTRL = 4'h0;
|
||||
// GPIO数据寄存器
|
||||
localparam GPIO_DATA = 4'h4;
|
||||
|
||||
// 每2位控制1个IO的模式,最多支持16个IO
|
||||
// GPIO控制寄存器
|
||||
// 每2位控制1个IO的输入、输出模式,最多支持16个IO
|
||||
// 0: 高阻,1:输出,2:输入
|
||||
reg[31:0] gpio_ctrl;
|
||||
// 输入输出数据
|
||||
reg[31:0] gpio_data;
|
||||
|
||||
// GPIO输入输出数据寄存器
|
||||
reg[31:0] gpio_data;
|
||||
|
||||
assign reg_ctrl = gpio_ctrl;
|
||||
assign reg_data = gpio_data;
|
||||
|
||||
wire wen = we_i & req_valid_i;
|
||||
wire ren = (~we_i) & req_valid_i;
|
||||
wire write_reg_ctrl_en = wen & (addr_i[3:0] == GPIO_CTRL);
|
||||
wire write_reg_data_en = wen & (addr_i[3:0] == GPIO_DATA);
|
||||
|
||||
// 写寄存器
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
gpio_data <= 32'h0;
|
||||
// 写gpio_ctrl
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
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
|
||||
if (write_reg_ctrl_en) begin
|
||||
if (sel_i[0]) begin
|
||||
gpio_ctrl[7:0] <= data_i[7:0];
|
||||
end
|
||||
if (sel_i[1]) begin
|
||||
gpio_ctrl[15:8] <= data_i[15:8];
|
||||
end
|
||||
if (sel_i[2]) begin
|
||||
gpio_ctrl[23:16] <= data_i[23:16];
|
||||
end
|
||||
if (sel_i[3]) begin
|
||||
gpio_ctrl[31:24] <= data_i[31:24];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写gpio_data
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
gpio_data <= 32'h0;
|
||||
end else begin
|
||||
if (write_reg_data_en) begin
|
||||
if (sel_i[0]) begin
|
||||
gpio_data[7:0] <= data_i[7:0];
|
||||
end
|
||||
if (sel_i[1]) begin
|
||||
gpio_data[15:8] <= data_i[15:8];
|
||||
end
|
||||
end else begin
|
||||
if (gpio_ctrl[1:0] == 2'b10) begin
|
||||
gpio_data[0] <= io_pin_i[0];
|
||||
|
@ -76,23 +101,36 @@ module gpio(
|
|||
end
|
||||
end
|
||||
|
||||
reg[31:0] data_r;
|
||||
|
||||
// 读寄存器
|
||||
always @ (*) begin
|
||||
if (rst == 1'b0) begin
|
||||
data_o = 32'h0;
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
data_r <= 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
|
||||
if (ren) begin
|
||||
case (addr_i[3:0])
|
||||
GPIO_CTRL: data_r <= gpio_ctrl;
|
||||
GPIO_DATA: data_r <= gpio_data;
|
||||
default: data_r <= 32'h0;
|
||||
endcase
|
||||
end else begin
|
||||
data_r <= 32'h0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign data_o = data_r;
|
||||
|
||||
vld_rdy #(
|
||||
.CUT_READY(0)
|
||||
) u_vld_rdy(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.vld_i(req_valid_i),
|
||||
.rdy_o(req_ready_o),
|
||||
.rdy_i(rsp_ready_i),
|
||||
.vld_o(rsp_valid_o)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2019 Blue Liang, liangkangnan@163.com
|
||||
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.
|
||||
|
@ -16,35 +16,50 @@
|
|||
|
||||
`include "../core/defines.v"
|
||||
|
||||
// ram module
|
||||
module ram(
|
||||
|
||||
module ram #(
|
||||
parameter DP = 4096)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
input wire[31:0] addr_i,
|
||||
input wire[31:0] data_i,
|
||||
input wire[3:0] sel_i,
|
||||
input wire we_i,
|
||||
output wire[31:0] data_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
|
||||
input wire req_valid_i,
|
||||
output wire req_ready_o,
|
||||
output wire rsp_valid_o,
|
||||
input wire rsp_ready_i
|
||||
|
||||
);
|
||||
|
||||
reg[`MemBus] _ram[0:`MemNum - 1];
|
||||
wire[31:0] addr = addr_i[31:2];
|
||||
|
||||
gen_ram #(
|
||||
.DP(DP),
|
||||
.DW(32),
|
||||
.MW(4),
|
||||
.AW(32)
|
||||
) u_gen_ram(
|
||||
.clk(clk),
|
||||
.addr_i(addr),
|
||||
.data_i(data_i),
|
||||
.sel_i(sel_i),
|
||||
.we_i(we_i),
|
||||
.data_o(data_o)
|
||||
);
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (we_i == `WriteEnable) begin
|
||||
_ram[addr_i[31:2]] <= data_i;
|
||||
end
|
||||
end
|
||||
|
||||
always @ (*) begin
|
||||
if (rst == `RstEnable) begin
|
||||
data_o = `ZeroWord;
|
||||
end else begin
|
||||
data_o = _ram[addr_i[31:2]];
|
||||
end
|
||||
end
|
||||
vld_rdy #(
|
||||
.CUT_READY(0)
|
||||
) u_vld_rdy(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.vld_i(req_valid_i),
|
||||
.rdy_o(req_ready_o),
|
||||
.rdy_i(rsp_ready_i),
|
||||
.vld_o(rsp_valid_o)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -17,34 +17,49 @@
|
|||
`include "../core/defines.v"
|
||||
|
||||
|
||||
module rom(
|
||||
module rom #(
|
||||
parameter DP = 4096)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
input wire[31:0] addr_i,
|
||||
input wire[31:0] data_i,
|
||||
input wire[3:0] sel_i,
|
||||
input wire we_i,
|
||||
output wire[31:0] data_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
|
||||
input wire req_valid_i,
|
||||
output wire req_ready_o,
|
||||
output wire rsp_valid_o,
|
||||
input wire rsp_ready_i
|
||||
|
||||
);
|
||||
|
||||
reg[`MemBus] _rom[0:`RomNum - 1];
|
||||
wire[31:0] addr = addr_i[31:2];
|
||||
|
||||
gen_ram #(
|
||||
.DP(DP),
|
||||
.DW(32),
|
||||
.MW(4),
|
||||
.AW(32)
|
||||
) u_gen_ram(
|
||||
.clk(clk),
|
||||
.addr_i(addr),
|
||||
.data_i(data_i),
|
||||
.sel_i(sel_i),
|
||||
.we_i(we_i),
|
||||
.data_o(data_o)
|
||||
);
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (we_i == `WriteEnable) begin
|
||||
_rom[addr_i[31:2]] <= data_i;
|
||||
end
|
||||
end
|
||||
|
||||
always @ (*) begin
|
||||
if (rst == `RstEnable) begin
|
||||
data_o = `ZeroWord;
|
||||
end else begin
|
||||
data_o = _rom[addr_i[31:2]];
|
||||
end
|
||||
end
|
||||
vld_rdy #(
|
||||
.CUT_READY(0)
|
||||
) u_vld_rdy(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.vld_i(req_valid_i),
|
||||
.rdy_o(req_ready_o),
|
||||
.rdy_i(rsp_ready_i),
|
||||
.vld_o(rsp_valid_o)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
244
rtl/perips/spi.v
244
rtl/perips/spi.v
|
@ -1,244 +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.
|
||||
*/
|
||||
|
||||
|
||||
// spi master模块
|
||||
module spi(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
input wire[31:0] data_i,
|
||||
input wire[31:0] addr_i,
|
||||
input wire we_i,
|
||||
|
||||
output reg[31:0] data_o,
|
||||
|
||||
output reg spi_mosi, // spi控制器输出、spi设备输入信号
|
||||
input wire spi_miso, // spi控制器输入、spi设备输出信号
|
||||
output wire spi_ss, // spi设备片选
|
||||
output reg spi_clk // spi设备时钟,最大频率为输入clk的一半
|
||||
|
||||
);
|
||||
|
||||
|
||||
localparam SPI_CTRL = 4'h0; // spi_ctrl寄存器地址偏移
|
||||
localparam SPI_DATA = 4'h4; // spi_data寄存器地址偏移
|
||||
localparam SPI_STATUS = 4'h8; // spi_status寄存器地址偏移
|
||||
|
||||
// spi控制寄存器
|
||||
// addr: 0x00
|
||||
// [0]: 1: enable, 0: disable
|
||||
// [1]: CPOL
|
||||
// [2]: CPHA
|
||||
// [3]: select slave, 1: select, 0: deselect
|
||||
// [15:8]: clk div
|
||||
reg[31:0] spi_ctrl;
|
||||
// spi数据寄存器
|
||||
// addr: 0x04
|
||||
// [7:0] cmd or inout data
|
||||
reg[31:0] spi_data;
|
||||
// spi状态寄存器
|
||||
// addr: 0x08
|
||||
// [0]: 1: busy, 0: idle
|
||||
reg[31:0] spi_status;
|
||||
|
||||
reg[8:0] clk_cnt; // 分频计数
|
||||
reg en; // 使能,开始传输信号,传输期间一直有效
|
||||
reg[4:0] spi_clk_edge_cnt; // spi clk时钟沿的个数
|
||||
reg spi_clk_edge_level; // spi clk沿电平
|
||||
reg[7:0] rdata; // 从spi设备读回来的数据
|
||||
reg done; // 传输完成信号
|
||||
reg[3:0] bit_index; // 数据bit索引
|
||||
wire[8:0] div_cnt;
|
||||
|
||||
|
||||
assign spi_ss = ~spi_ctrl[3]; // SPI设备片选信号
|
||||
|
||||
assign div_cnt = spi_ctrl[15:8];// 0: 2分频,1:4分频,2:8分频,3:16分频,4:32分频,以此类推
|
||||
|
||||
|
||||
// 产生使能信号
|
||||
// 传输期间一直有效
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
en <= 1'b0;
|
||||
end else begin
|
||||
if (spi_ctrl[0] == 1'b1) begin
|
||||
en <= 1'b1;
|
||||
end else if (done == 1'b1) begin
|
||||
en <= 1'b0;
|
||||
end else begin
|
||||
en <= en;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 对输入时钟进行计数
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
clk_cnt <= 9'h0;
|
||||
end else if (en == 1'b1) begin
|
||||
if (clk_cnt == div_cnt) begin
|
||||
clk_cnt <= 9'h0;
|
||||
end else begin
|
||||
clk_cnt <= clk_cnt + 1'b1;
|
||||
end
|
||||
end else begin
|
||||
clk_cnt <= 9'h0;
|
||||
end
|
||||
end
|
||||
|
||||
// 对spi clk沿进行计数
|
||||
// 每当计数到分频值时产生一个上升沿脉冲
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
spi_clk_edge_cnt <= 5'h0;
|
||||
spi_clk_edge_level <= 1'b0;
|
||||
end else if (en == 1'b1) begin
|
||||
// 计数达到分频值
|
||||
if (clk_cnt == div_cnt) begin
|
||||
if (spi_clk_edge_cnt == 5'd17) begin
|
||||
spi_clk_edge_cnt <= 5'h0;
|
||||
spi_clk_edge_level <= 1'b0;
|
||||
end else begin
|
||||
spi_clk_edge_cnt <= spi_clk_edge_cnt + 1'b1;
|
||||
spi_clk_edge_level <= 1'b1;
|
||||
end
|
||||
end else begin
|
||||
spi_clk_edge_level <= 1'b0;
|
||||
end
|
||||
end else begin
|
||||
spi_clk_edge_cnt <= 5'h0;
|
||||
spi_clk_edge_level <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// bit序列
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
spi_clk <= 1'b0;
|
||||
rdata <= 8'h0;
|
||||
spi_mosi <= 1'b0;
|
||||
bit_index <= 4'h0;
|
||||
end else begin
|
||||
if (en) begin
|
||||
if (spi_clk_edge_level == 1'b1) begin
|
||||
case (spi_clk_edge_cnt)
|
||||
// 第奇数个时钟沿
|
||||
1, 3, 5, 7, 9, 11, 13, 15: begin
|
||||
spi_clk <= ~spi_clk;
|
||||
if (spi_ctrl[2] == 1'b1) begin
|
||||
spi_mosi <= spi_data[bit_index]; // 送出1bit数据
|
||||
bit_index <= bit_index - 1'b1;
|
||||
end else begin
|
||||
rdata <= {rdata[6:0], spi_miso}; // 读1bit数据
|
||||
end
|
||||
end
|
||||
// 第偶数个时钟沿
|
||||
2, 4, 6, 8, 10, 12, 14, 16: begin
|
||||
spi_clk <= ~spi_clk;
|
||||
if (spi_ctrl[2] == 1'b1) begin
|
||||
rdata <= {rdata[6:0], spi_miso}; // 读1bit数据
|
||||
end else begin
|
||||
spi_mosi <= spi_data[bit_index]; // 送出1bit数据
|
||||
bit_index <= bit_index - 1'b1;
|
||||
end
|
||||
end
|
||||
17: begin
|
||||
spi_clk <= spi_ctrl[1];
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end else begin
|
||||
// 初始状态
|
||||
spi_clk <= spi_ctrl[1];
|
||||
if (spi_ctrl[2] == 1'b0) begin
|
||||
spi_mosi <= spi_data[7]; // 送出最高位数据
|
||||
bit_index <= 4'h6;
|
||||
end else begin
|
||||
bit_index <= 4'h7;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 产生结束(完成)信号
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
done <= 1'b0;
|
||||
end else begin
|
||||
if (en && spi_clk_edge_cnt == 5'd17) begin
|
||||
done <= 1'b1;
|
||||
end else begin
|
||||
done <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// write reg
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
spi_ctrl <= 32'h0;
|
||||
spi_data <= 32'h0;
|
||||
spi_status <= 32'h0;
|
||||
end else begin
|
||||
spi_status[0] <= en;
|
||||
if (we_i == 1'b1) begin
|
||||
case (addr_i[3:0])
|
||||
SPI_CTRL: begin
|
||||
spi_ctrl <= data_i;
|
||||
end
|
||||
SPI_DATA: begin
|
||||
spi_data <= data_i;
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end else begin
|
||||
spi_ctrl[0] <= 1'b0;
|
||||
// 发送完成后更新数据寄存器
|
||||
if (done == 1'b1) begin
|
||||
spi_data <= {24'h0, rdata};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// read reg
|
||||
always @ (*) begin
|
||||
if (rst == 1'b0) begin
|
||||
data_o = 32'h0;
|
||||
end else begin
|
||||
case (addr_i[3:0])
|
||||
SPI_CTRL: begin
|
||||
data_o = spi_ctrl;
|
||||
end
|
||||
SPI_DATA: begin
|
||||
data_o = spi_data;
|
||||
end
|
||||
SPI_STATUS: begin
|
||||
data_o = spi_status;
|
||||
end
|
||||
default: begin
|
||||
data_o = 32'h0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -16,103 +16,153 @@
|
|||
|
||||
`include "../core/defines.v"
|
||||
|
||||
|
||||
// 32 bits count up timer module
|
||||
// 32位向上计数定时器模块
|
||||
module timer(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
input wire[31:0] data_i,
|
||||
input wire rst_n,
|
||||
input wire[31:0] addr_i,
|
||||
input wire[31:0] data_i,
|
||||
input wire[3:0] sel_i,
|
||||
input wire we_i,
|
||||
output wire[31:0] data_o,
|
||||
|
||||
input wire req_valid_i,
|
||||
output wire req_ready_o,
|
||||
output wire rsp_valid_o,
|
||||
input wire rsp_ready_i,
|
||||
|
||||
output reg[31:0] data_o,
|
||||
output wire int_sig_o
|
||||
|
||||
);
|
||||
|
||||
localparam REG_CTRL = 4'h0;
|
||||
// 寄存器(偏移)地址
|
||||
localparam REG_CTRL = 4'h0;
|
||||
localparam REG_COUNT = 4'h4;
|
||||
localparam REG_VALUE = 4'h8;
|
||||
|
||||
// [0]: timer enable
|
||||
// [1]: timer int enable
|
||||
// [2]: timer int pending, write 1 to clear it
|
||||
// addr offset: 0x00
|
||||
// 定时器控制寄存器,可读可写
|
||||
// bit[0]: 定时器使能
|
||||
// bit[1]: 定时器中断使能
|
||||
// bit[2]: 定时器中断pending标志,写1清零
|
||||
reg[31:0] timer_ctrl;
|
||||
|
||||
// timer current count, read only
|
||||
// addr offset: 0x04
|
||||
// 定时器当前计数值寄存器, 只读
|
||||
reg[31:0] timer_count;
|
||||
|
||||
// timer expired value
|
||||
// addr offset: 0x08
|
||||
// 定时器溢出值寄存器,当定时器计数值达到该值时产生pending,可读可写
|
||||
reg[31:0] timer_value;
|
||||
|
||||
wire wen = we_i & req_valid_i;
|
||||
wire ren = (~we_i) & req_valid_i;
|
||||
wire timer_en = (timer_ctrl[0] == 1'b1);
|
||||
wire timer_int_en = (timer_ctrl[1] == 1'b1);
|
||||
wire timer_expired = (timer_count >= timer_value);
|
||||
wire write_reg_ctrl_en = wen & (addr_i[3:0] == REG_CTRL);
|
||||
wire write_reg_value_en = wen & (addr_i[3:0] == REG_VALUE);
|
||||
|
||||
assign int_sig_o = ((timer_ctrl[2] == 1'b1) && (timer_ctrl[1] == 1'b1))? `INT_ASSERT: `INT_DEASSERT;
|
||||
|
||||
// counter
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
timer_count <= `ZeroWord;
|
||||
// 计数
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
timer_count <= 32'h0;
|
||||
end else begin
|
||||
if (timer_ctrl[0] == 1'b1) begin
|
||||
timer_count <= timer_count + 1'b1;
|
||||
if (timer_count >= timer_value) begin
|
||||
timer_count <= `ZeroWord;
|
||||
if (timer_en) begin
|
||||
if (timer_expired) begin
|
||||
timer_count <= 32'h0;
|
||||
end else begin
|
||||
timer_count <= timer_count + 1'b1;
|
||||
end
|
||||
end else begin
|
||||
timer_count <= `ZeroWord;
|
||||
timer_count <= 32'h0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// write regs
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
timer_ctrl <= `ZeroWord;
|
||||
timer_value <= `ZeroWord;
|
||||
reg int_sig_r;
|
||||
// 产生中断信号
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
int_sig_r <= 1'b0;
|
||||
end else begin
|
||||
if (we_i == `WriteEnable) begin
|
||||
if (write_reg_ctrl_en & (data_i[2] == 1'b1)) begin
|
||||
int_sig_r <= 1'b0;
|
||||
end else if (timer_int_en & timer_en & timer_expired) begin
|
||||
int_sig_r <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign int_sig_o = int_sig_r;
|
||||
|
||||
// 写timer_ctrl
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
timer_ctrl <= 32'h0;
|
||||
end else begin
|
||||
if (write_reg_ctrl_en) begin
|
||||
if (sel_i[0]) begin
|
||||
timer_ctrl[7:0] <= {data_i[7:3], timer_ctrl[2] & (~data_i[2]), data_i[1:0]};
|
||||
end
|
||||
end else begin
|
||||
if (timer_expired) begin
|
||||
timer_ctrl[0] <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写timer_value
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
timer_value <= 32'h0;
|
||||
end else begin
|
||||
if (write_reg_value_en) begin
|
||||
if (sel_i[0]) begin
|
||||
timer_value[7:0] <= data_i[7:0];
|
||||
end
|
||||
if (sel_i[1]) begin
|
||||
timer_value[15:8] <= data_i[15:8];
|
||||
end
|
||||
if (sel_i[2]) begin
|
||||
timer_value[23:16] <= data_i[23:16];
|
||||
end
|
||||
if (sel_i[3]) begin
|
||||
timer_value[31:24] <= data_i[31:24];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg[31:0] data_r;
|
||||
// 读寄存器
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
data_r <= 32'h0;
|
||||
end else begin
|
||||
if (ren) begin
|
||||
case (addr_i[3:0])
|
||||
REG_CTRL: begin
|
||||
timer_ctrl <= {data_i[31:3], (timer_ctrl[2] & (~data_i[2])), data_i[1:0]};
|
||||
end
|
||||
REG_VALUE: begin
|
||||
timer_value <= data_i;
|
||||
end
|
||||
REG_VALUE: data_r <= timer_value;
|
||||
REG_CTRL: data_r <= timer_ctrl;
|
||||
REG_COUNT: data_r <= timer_count;
|
||||
default: data_r <= 32'h0;
|
||||
endcase
|
||||
end else begin
|
||||
if ((timer_ctrl[0] == 1'b1) && (timer_count >= timer_value)) begin
|
||||
timer_ctrl[0] <= 1'b0;
|
||||
timer_ctrl[2] <= 1'b1;
|
||||
end
|
||||
data_r <= 32'h0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// read regs
|
||||
always @ (*) begin
|
||||
if (rst == `RstEnable) begin
|
||||
data_o = `ZeroWord;
|
||||
end else begin
|
||||
case (addr_i[3:0])
|
||||
REG_VALUE: begin
|
||||
data_o = timer_value;
|
||||
end
|
||||
REG_CTRL: begin
|
||||
data_o = timer_ctrl;
|
||||
end
|
||||
REG_COUNT: begin
|
||||
data_o = timer_count;
|
||||
end
|
||||
default: begin
|
||||
data_o = `ZeroWord;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
assign data_o = data_r;
|
||||
|
||||
vld_rdy #(
|
||||
.CUT_READY(0)
|
||||
) u_vld_rdy(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.vld_i(req_valid_i),
|
||||
.rdy_o(req_ready_o),
|
||||
.rdy_i(rsp_ready_i),
|
||||
.vld_o(rsp_valid_o)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -14,46 +14,49 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
`include "../core/defines.v"
|
||||
|
||||
// 串口模块(默认: 115200, 8 N 1)
|
||||
// 串口收发模块(默认: 115200, 8,N,1)
|
||||
module uart(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
input wire we_i,
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
input wire[31:0] addr_i,
|
||||
input wire[31:0] data_i,
|
||||
input wire[3:0] sel_i,
|
||||
input wire we_i,
|
||||
output wire[31:0] data_o,
|
||||
|
||||
input wire req_valid_i,
|
||||
output wire req_ready_o,
|
||||
output wire rsp_valid_o,
|
||||
input wire rsp_ready_i,
|
||||
|
||||
output reg[31:0] data_o,
|
||||
output wire tx_pin,
|
||||
input wire rx_pin
|
||||
|
||||
);
|
||||
|
||||
|
||||
// 50MHz时钟,波特率115200bps对应的分频系数
|
||||
localparam BAUD_115200 = 32'h1B8;
|
||||
// 波特率115200bps
|
||||
localparam BAUD_115200 = `CPU_CLOCK_HZ / 115200;
|
||||
|
||||
localparam S_IDLE = 4'b0001;
|
||||
localparam S_START = 4'b0010;
|
||||
localparam S_SEND_BYTE = 4'b0100;
|
||||
localparam S_STOP = 4'b1000;
|
||||
|
||||
reg tx_data_valid;
|
||||
reg tx_data_ready;
|
||||
|
||||
reg[3:0] state;
|
||||
reg[3:0] next_state;
|
||||
reg[15:0] cycle_cnt;
|
||||
reg tx_bit;
|
||||
reg[3:0] bit_cnt;
|
||||
reg[7:0] tx_data;
|
||||
reg tx_reg;
|
||||
|
||||
reg rx_q0;
|
||||
reg rx_q1;
|
||||
wire rx_negedge;
|
||||
reg rx_start; // RX使能
|
||||
reg[3:0] rx_clk_edge_cnt; // clk时钟沿的个数
|
||||
reg[3:0] rx_clk_edge_cnt; // clk沿的个数
|
||||
reg rx_clk_edge_level; // clk沿电平
|
||||
reg rx_done;
|
||||
reg[15:0] rx_clk_cnt;
|
||||
|
@ -61,159 +64,246 @@ module uart(
|
|||
reg[7:0] rx_data;
|
||||
reg rx_over;
|
||||
|
||||
localparam UART_CTRL = 8'h0;
|
||||
localparam UART_STATUS = 8'h4;
|
||||
localparam UART_BAUD = 8'h8;
|
||||
localparam UART_TXDATA = 8'hc;
|
||||
localparam UART_RXDATA = 8'h10;
|
||||
// 寄存器(偏移)地址
|
||||
localparam UART_CTRL = 8'h0;
|
||||
localparam UART_STATUS = 8'h4;
|
||||
localparam UART_BAUD = 8'h8;
|
||||
localparam UART_TXDATA = 8'hc;
|
||||
localparam UART_RXDATA = 8'h10;
|
||||
|
||||
// addr: 0x00
|
||||
// rw. bit[0]: tx enable, 1 = enable, 0 = disable
|
||||
// rw. bit[1]: rx enable, 1 = enable, 0 = disable
|
||||
// UART控制寄存器,可读可写
|
||||
// bit[0]: UART TX使能, 1: enable, 0: disable
|
||||
// bit[1]: UART RX使能, 1: enable, 0: disable
|
||||
reg[31:0] uart_ctrl;
|
||||
|
||||
// addr: 0x04
|
||||
// ro. bit[0]: tx busy, 1 = busy, 0 = idle
|
||||
// rw. bit[1]: rx over, 1 = over, 0 = receiving
|
||||
// must check this bit before tx data
|
||||
// UART状态寄存器
|
||||
// 只读,bit[0]: TX空闲状态标志, 1: busy, 0: idle
|
||||
// 可读可写,bit[1]: RX接收完成标志, 1: over, 0: receiving
|
||||
reg[31:0] uart_status;
|
||||
|
||||
// addr: 0x08
|
||||
// rw. clk div
|
||||
// UART波特率寄存器(分频系数),可读可写
|
||||
reg[31:0] uart_baud;
|
||||
|
||||
// addr: 0x10
|
||||
// ro. rx data
|
||||
// UART发送数据寄存器,可读可写
|
||||
reg[31:0] uart_tx;
|
||||
|
||||
// UART接收数据寄存器,只读
|
||||
reg[31:0] uart_rx;
|
||||
|
||||
assign tx_pin = tx_reg;
|
||||
wire wen = we_i & req_valid_i;
|
||||
wire ren = (~we_i) & req_valid_i;
|
||||
wire write_reg_ctrl_en = wen & (addr_i[7:0] == UART_CTRL);
|
||||
wire write_reg_status_en = wen & (addr_i[7:0] == UART_STATUS);
|
||||
wire write_reg_baud_en = wen & (addr_i[7:0] == UART_BAUD);
|
||||
wire write_reg_txdata_en = wen & (addr_i[7:0] == UART_TXDATA);
|
||||
wire tx_start = write_reg_txdata_en & sel_i[0] & uart_ctrl[0] & (~uart_status[0]);
|
||||
wire rx_recv_over = uart_ctrl[1] & rx_over;
|
||||
|
||||
assign tx_pin = tx_bit;
|
||||
|
||||
|
||||
// 写寄存器
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
uart_ctrl <= 32'h0;
|
||||
uart_status <= 32'h0;
|
||||
// 写uart_rxdata
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_rx <= 32'h0;
|
||||
uart_baud <= BAUD_115200;
|
||||
tx_data_valid <= 1'b0;
|
||||
end else begin
|
||||
if (we_i == 1'b1) begin
|
||||
case (addr_i[7:0])
|
||||
UART_CTRL: begin
|
||||
uart_ctrl <= data_i;
|
||||
end
|
||||
UART_BAUD: begin
|
||||
uart_baud <= data_i;
|
||||
end
|
||||
UART_STATUS: begin
|
||||
uart_status[1] <= data_i[1];
|
||||
end
|
||||
UART_TXDATA: begin
|
||||
if (uart_ctrl[0] == 1'b1 && uart_status[0] == 1'b0) begin
|
||||
tx_data <= data_i[7:0];
|
||||
uart_status[0] <= 1'b1;
|
||||
tx_data_valid <= 1'b1;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
// 接收完成时,保存接收到的数据
|
||||
if (rx_recv_over) begin
|
||||
uart_rx[7:0] <= rx_data;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写uart_txdata
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_tx <= 32'h0;
|
||||
end else begin
|
||||
// 开始发送时,保存要发送的数据
|
||||
if (tx_start) begin
|
||||
uart_tx[7:0] <= data_i[7:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写uart_status
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_status <= 32'h0;
|
||||
end else begin
|
||||
if (write_reg_status_en & sel_i[0]) begin
|
||||
// 写RX完成标志
|
||||
uart_status[1] <= data_i[1];
|
||||
end else begin
|
||||
tx_data_valid <= 1'b0;
|
||||
if (tx_data_ready == 1'b1) begin
|
||||
// 开始发送数据时,置位TX忙标志
|
||||
if (tx_start) begin
|
||||
uart_status[0] <= 1'b1;
|
||||
// 发送完成时,清TX忙标志
|
||||
end else if ((state == S_STOP) & (cycle_cnt == uart_baud[15:0])) begin
|
||||
uart_status[0] <= 1'b0;
|
||||
// 接收完成,置位接收完成标志
|
||||
end
|
||||
if (uart_ctrl[1] == 1'b1) begin
|
||||
if (rx_over == 1'b1) begin
|
||||
uart_status[1] <= 1'b1;
|
||||
uart_rx <= {24'h0, rx_data};
|
||||
end
|
||||
if (rx_recv_over) begin
|
||||
uart_status[1] <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 读寄存器
|
||||
always @ (*) begin
|
||||
if (rst == 1'b0) begin
|
||||
data_o = 32'h0;
|
||||
// 写uart_ctrl
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_ctrl <= 32'h0;
|
||||
end else begin
|
||||
case (addr_i[7:0])
|
||||
UART_CTRL: begin
|
||||
data_o = uart_ctrl;
|
||||
if (write_reg_ctrl_en & sel_i[0]) begin
|
||||
uart_ctrl[7:0] <= data_i[7:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写uart_baud
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_baud <= BAUD_115200;
|
||||
end else begin
|
||||
if (write_reg_baud_en) begin
|
||||
if (sel_i[0]) begin
|
||||
uart_baud[7:0] <= data_i[7:0];
|
||||
end
|
||||
UART_STATUS: begin
|
||||
data_o = uart_status;
|
||||
if (sel_i[1]) begin
|
||||
uart_baud[15:8] <= data_i[15:8];
|
||||
end
|
||||
UART_BAUD: begin
|
||||
data_o = uart_baud;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg[31:0] data_r;
|
||||
|
||||
// 读寄存器
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
data_r <= 32'h0;
|
||||
end else begin
|
||||
if (ren) begin
|
||||
case (addr_i[7:0])
|
||||
UART_CTRL: data_r <= uart_ctrl;
|
||||
UART_STATUS: data_r <= uart_status;
|
||||
UART_BAUD: data_r <= uart_baud;
|
||||
UART_RXDATA: data_r <= uart_rx;
|
||||
default: data_r <= 32'h0;
|
||||
endcase
|
||||
end else begin
|
||||
data_r <= 32'h0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign data_o = data_r;
|
||||
|
||||
// *************************** TX发送 ****************************
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
state <= S_IDLE;
|
||||
end else begin
|
||||
state <= next_state;
|
||||
end
|
||||
end
|
||||
|
||||
always @ (*) begin
|
||||
case (state)
|
||||
S_IDLE: begin
|
||||
if (tx_start) begin
|
||||
next_state = S_START;
|
||||
end else begin
|
||||
next_state = S_IDLE;
|
||||
end
|
||||
UART_RXDATA: begin
|
||||
data_o = uart_rx;
|
||||
end
|
||||
S_START: begin
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
next_state = S_SEND_BYTE;
|
||||
end else begin
|
||||
next_state = S_START;
|
||||
end
|
||||
default: begin
|
||||
data_o = 32'h0;
|
||||
end
|
||||
S_SEND_BYTE: begin
|
||||
if ((cycle_cnt == uart_baud[15:0]) & (bit_cnt == 4'd7)) begin
|
||||
next_state = S_STOP;
|
||||
end else begin
|
||||
next_state = S_SEND_BYTE;
|
||||
end
|
||||
end
|
||||
S_STOP: begin
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
next_state = S_IDLE;
|
||||
end else begin
|
||||
next_state = S_STOP;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
next_state = S_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// cycle_cnt
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
cycle_cnt <= 16'h0;
|
||||
end else begin
|
||||
if (state == S_IDLE) begin
|
||||
cycle_cnt <= 16'h0;
|
||||
end else begin
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
cycle_cnt <= 16'h0;
|
||||
end else begin
|
||||
cycle_cnt <= cycle_cnt + 16'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// bit_cnt
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
bit_cnt <= 4'h0;
|
||||
end else begin
|
||||
case (state)
|
||||
S_IDLE: begin
|
||||
bit_cnt <= 4'h0;
|
||||
end
|
||||
S_SEND_BYTE: begin
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
bit_cnt <= bit_cnt + 4'h1;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// *************************** TX发送 ****************************
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
state <= S_IDLE;
|
||||
cycle_cnt <= 16'd0;
|
||||
tx_reg <= 1'b0;
|
||||
bit_cnt <= 4'd0;
|
||||
tx_data_ready <= 1'b0;
|
||||
// tx_bit
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
tx_bit <= 1'b0;
|
||||
end else begin
|
||||
if (state == S_IDLE) begin
|
||||
tx_reg <= 1'b1;
|
||||
tx_data_ready <= 1'b0;
|
||||
if (tx_data_valid == 1'b1) begin
|
||||
state <= S_START;
|
||||
cycle_cnt <= 16'd0;
|
||||
bit_cnt <= 4'd0;
|
||||
tx_reg <= 1'b0;
|
||||
case (state)
|
||||
S_IDLE, S_STOP: begin
|
||||
tx_bit <= 1'b1;
|
||||
end
|
||||
end else begin
|
||||
cycle_cnt <= cycle_cnt + 16'd1;
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
cycle_cnt <= 16'd0;
|
||||
case (state)
|
||||
S_START: begin
|
||||
tx_reg <= tx_data[bit_cnt];
|
||||
state <= S_SEND_BYTE;
|
||||
bit_cnt <= bit_cnt + 4'd1;
|
||||
end
|
||||
S_SEND_BYTE: begin
|
||||
bit_cnt <= bit_cnt + 4'd1;
|
||||
if (bit_cnt == 4'd8) begin
|
||||
state <= S_STOP;
|
||||
tx_reg <= 1'b1;
|
||||
end else begin
|
||||
tx_reg <= tx_data[bit_cnt];
|
||||
end
|
||||
end
|
||||
S_STOP: begin
|
||||
tx_reg <= 1'b1;
|
||||
state <= S_IDLE;
|
||||
tx_data_ready <= 1'b1;
|
||||
end
|
||||
endcase
|
||||
S_START: begin
|
||||
tx_bit <= 1'b0;
|
||||
end
|
||||
end
|
||||
S_SEND_BYTE: begin
|
||||
tx_bit <= uart_tx[bit_cnt];
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// *************************** RX接收 ****************************
|
||||
|
||||
// 下降沿检测(检测起始信号)
|
||||
assign rx_negedge = rx_q1 && ~rx_q0;
|
||||
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_q0 <= 1'b0;
|
||||
rx_q1 <= 1'b0;
|
||||
end else begin
|
||||
|
@ -222,9 +312,12 @@ module uart(
|
|||
end
|
||||
end
|
||||
|
||||
// 开始接收数据信号,接收期间一直有效
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
// 下降沿检测(检测起始信号)
|
||||
assign rx_negedge = rx_q1 & (~rx_q0);
|
||||
|
||||
// 产生开始接收数据信号,接收期间一直有效
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_start <= 1'b0;
|
||||
end else begin
|
||||
if (uart_ctrl[1]) begin
|
||||
|
@ -239,8 +332,8 @@ module uart(
|
|||
end
|
||||
end
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_div_cnt <= 16'h0;
|
||||
end else begin
|
||||
// 第一个时钟沿只需波特率分频系数的一半
|
||||
|
@ -253,15 +346,15 @@ module uart(
|
|||
end
|
||||
|
||||
// 对时钟进行计数
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_clk_cnt <= 16'h0;
|
||||
end else if (rx_start == 1'b1) begin
|
||||
// 计数达到分频值
|
||||
if (rx_clk_cnt == rx_div_cnt) begin
|
||||
rx_clk_cnt <= 16'h0;
|
||||
end else begin
|
||||
rx_clk_cnt <= rx_clk_cnt + 1'b1;
|
||||
rx_clk_cnt <= rx_clk_cnt + 16'h1;
|
||||
end
|
||||
end else begin
|
||||
rx_clk_cnt <= 16'h0;
|
||||
|
@ -269,8 +362,8 @@ module uart(
|
|||
end
|
||||
|
||||
// 每当时钟计数达到分频值时产生一个上升沿脉冲
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_clk_edge_cnt <= 4'h0;
|
||||
rx_clk_edge_level <= 1'b0;
|
||||
end else if (rx_start == 1'b1) begin
|
||||
|
@ -282,7 +375,7 @@ module uart(
|
|||
rx_clk_edge_level <= 1'b0;
|
||||
end else begin
|
||||
// 时钟沿个数加1
|
||||
rx_clk_edge_cnt <= rx_clk_edge_cnt + 1'b1;
|
||||
rx_clk_edge_cnt <= rx_clk_edge_cnt + 4'h1;
|
||||
// 产生上升沿脉冲
|
||||
rx_clk_edge_level <= 1'b1;
|
||||
end
|
||||
|
@ -296,8 +389,8 @@ module uart(
|
|||
end
|
||||
|
||||
// bit序列
|
||||
always @ (posedge clk) begin
|
||||
if (rst == 1'b0) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_data <= 8'h0;
|
||||
rx_over <= 1'b0;
|
||||
end else begin
|
||||
|
@ -309,9 +402,17 @@ module uart(
|
|||
1: begin
|
||||
|
||||
end
|
||||
// 数据位
|
||||
2, 3, 4, 5, 6, 7, 8, 9: begin
|
||||
rx_data <= rx_data | (rx_pin << (rx_clk_edge_cnt - 2));
|
||||
// 第1位数据位
|
||||
2: begin
|
||||
if (rx_pin) begin
|
||||
rx_data <= 8'h80;
|
||||
end else begin
|
||||
rx_data <= 8'h0;
|
||||
end
|
||||
end
|
||||
// 剩余数据位
|
||||
3, 4, 5, 6, 7, 8, 9: begin
|
||||
rx_data <= {rx_pin, rx_data[7:1]};
|
||||
// 最后一位接收完成,置位接收完成标志
|
||||
if (rx_clk_edge_cnt == 4'h9) begin
|
||||
rx_over <= 1'b1;
|
||||
|
@ -326,4 +427,15 @@ module uart(
|
|||
end
|
||||
end
|
||||
|
||||
vld_rdy #(
|
||||
.CUT_READY(0)
|
||||
) u_vld_rdy(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.vld_i(req_valid_i),
|
||||
.rdy_o(req_ready_o),
|
||||
.rdy_i(rsp_ready_i),
|
||||
.vld_o(rsp_valid_o)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -1,363 +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"
|
||||
|
||||
// tinyriscv soc顶层模块
|
||||
module tinyriscv_soc_top(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
output reg over, // 测试是否完成信号
|
||||
output reg succ, // 测试是否成功信号
|
||||
|
||||
output wire halted_ind, // jtag是否已经halt住CPU信号
|
||||
|
||||
input wire uart_debug_pin, // 串口下载使能引脚
|
||||
|
||||
output wire uart_tx_pin, // UART发送引脚
|
||||
input wire uart_rx_pin, // UART接收引脚
|
||||
inout wire[1:0] gpio, // GPIO引脚
|
||||
|
||||
input wire jtag_TCK, // JTAG TCK引脚
|
||||
input wire jtag_TMS, // JTAG TMS引脚
|
||||
input wire jtag_TDI, // JTAG TDI引脚
|
||||
output wire jtag_TDO, // JTAG TDO引脚
|
||||
|
||||
input wire spi_miso, // SPI MISO引脚
|
||||
output wire spi_mosi, // SPI MOSI引脚
|
||||
output wire spi_ss, // SPI SS引脚
|
||||
output wire spi_clk // SPI CLK引脚
|
||||
|
||||
);
|
||||
|
||||
|
||||
// master 0 interface
|
||||
wire[`MemAddrBus] m0_addr_i;
|
||||
wire[`MemBus] m0_data_i;
|
||||
wire[`MemBus] m0_data_o;
|
||||
wire m0_req_i;
|
||||
wire m0_we_i;
|
||||
|
||||
// master 1 interface
|
||||
wire[`MemAddrBus] m1_addr_i;
|
||||
wire[`MemBus] m1_data_i;
|
||||
wire[`MemBus] m1_data_o;
|
||||
wire m1_req_i;
|
||||
wire m1_we_i;
|
||||
|
||||
// master 2 interface
|
||||
wire[`MemAddrBus] m2_addr_i;
|
||||
wire[`MemBus] m2_data_i;
|
||||
wire[`MemBus] m2_data_o;
|
||||
wire m2_req_i;
|
||||
wire m2_we_i;
|
||||
|
||||
// master 3 interface
|
||||
wire[`MemAddrBus] m3_addr_i;
|
||||
wire[`MemBus] m3_data_i;
|
||||
wire[`MemBus] m3_data_o;
|
||||
wire m3_req_i;
|
||||
wire m3_we_i;
|
||||
|
||||
// slave 0 interface
|
||||
wire[`MemAddrBus] s0_addr_o;
|
||||
wire[`MemBus] s0_data_o;
|
||||
wire[`MemBus] s0_data_i;
|
||||
wire s0_we_o;
|
||||
|
||||
// slave 1 interface
|
||||
wire[`MemAddrBus] s1_addr_o;
|
||||
wire[`MemBus] s1_data_o;
|
||||
wire[`MemBus] s1_data_i;
|
||||
wire s1_we_o;
|
||||
|
||||
// slave 2 interface
|
||||
wire[`MemAddrBus] s2_addr_o;
|
||||
wire[`MemBus] s2_data_o;
|
||||
wire[`MemBus] s2_data_i;
|
||||
wire s2_we_o;
|
||||
|
||||
// slave 3 interface
|
||||
wire[`MemAddrBus] s3_addr_o;
|
||||
wire[`MemBus] s3_data_o;
|
||||
wire[`MemBus] s3_data_i;
|
||||
wire s3_we_o;
|
||||
|
||||
// slave 4 interface
|
||||
wire[`MemAddrBus] s4_addr_o;
|
||||
wire[`MemBus] s4_data_o;
|
||||
wire[`MemBus] s4_data_i;
|
||||
wire s4_we_o;
|
||||
|
||||
// slave 5 interface
|
||||
wire[`MemAddrBus] s5_addr_o;
|
||||
wire[`MemBus] s5_data_o;
|
||||
wire[`MemBus] s5_data_i;
|
||||
wire s5_we_o;
|
||||
|
||||
// rib
|
||||
wire rib_hold_flag_o;
|
||||
|
||||
// jtag
|
||||
wire jtag_halt_req_o;
|
||||
wire jtag_reset_req_o;
|
||||
wire[`RegAddrBus] jtag_reg_addr_o;
|
||||
wire[`RegBus] jtag_reg_data_o;
|
||||
wire jtag_reg_we_o;
|
||||
wire[`RegBus] jtag_reg_data_i;
|
||||
|
||||
// tinyriscv
|
||||
wire[`INT_BUS] int_flag;
|
||||
|
||||
// timer0
|
||||
wire timer0_int;
|
||||
|
||||
// gpio
|
||||
wire[1:0] io_in;
|
||||
wire[31:0] gpio_ctrl;
|
||||
wire[31:0] gpio_data;
|
||||
|
||||
assign int_flag = {7'h0, timer0_int};
|
||||
|
||||
// 低电平点亮LED
|
||||
// 低电平表示已经halt住CPU
|
||||
assign halted_ind = ~jtag_halt_req_o;
|
||||
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
over <= 1'b1;
|
||||
succ <= 1'b1;
|
||||
end else begin
|
||||
over <= ~u_tinyriscv.u_regs.regs[26]; // when = 1, run over
|
||||
succ <= ~u_tinyriscv.u_regs.regs[27]; // when = 1, run succ, otherwise fail
|
||||
end
|
||||
end
|
||||
|
||||
// tinyriscv处理器核模块例化
|
||||
tinyriscv u_tinyriscv(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.rib_ex_addr_o(m0_addr_i),
|
||||
.rib_ex_data_i(m0_data_o),
|
||||
.rib_ex_data_o(m0_data_i),
|
||||
.rib_ex_req_o(m0_req_i),
|
||||
.rib_ex_we_o(m0_we_i),
|
||||
|
||||
.rib_pc_addr_o(m1_addr_i),
|
||||
.rib_pc_data_i(m1_data_o),
|
||||
|
||||
.jtag_reg_addr_i(jtag_reg_addr_o),
|
||||
.jtag_reg_data_i(jtag_reg_data_o),
|
||||
.jtag_reg_we_i(jtag_reg_we_o),
|
||||
.jtag_reg_data_o(jtag_reg_data_i),
|
||||
|
||||
.rib_hold_flag_i(rib_hold_flag_o),
|
||||
.jtag_halt_flag_i(jtag_halt_req_o),
|
||||
.jtag_reset_flag_i(jtag_reset_req_o),
|
||||
|
||||
.int_i(int_flag)
|
||||
);
|
||||
|
||||
// rom模块例化
|
||||
rom u_rom(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.we_i(s0_we_o),
|
||||
.addr_i(s0_addr_o),
|
||||
.data_i(s0_data_o),
|
||||
.data_o(s0_data_i)
|
||||
);
|
||||
|
||||
// ram模块例化
|
||||
ram u_ram(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.we_i(s1_we_o),
|
||||
.addr_i(s1_addr_o),
|
||||
.data_i(s1_data_o),
|
||||
.data_o(s1_data_i)
|
||||
);
|
||||
|
||||
// timer模块例化
|
||||
timer timer_0(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.data_i(s2_data_o),
|
||||
.addr_i(s2_addr_o),
|
||||
.we_i(s2_we_o),
|
||||
.data_o(s2_data_i),
|
||||
.int_sig_o(timer0_int)
|
||||
);
|
||||
|
||||
// uart模块例化
|
||||
uart uart_0(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.we_i(s3_we_o),
|
||||
.addr_i(s3_addr_o),
|
||||
.data_i(s3_data_o),
|
||||
.data_o(s3_data_i),
|
||||
.tx_pin(uart_tx_pin),
|
||||
.rx_pin(uart_rx_pin)
|
||||
);
|
||||
|
||||
// io0
|
||||
assign gpio[0] = (gpio_ctrl[1:0] == 2'b01)? gpio_data[0]: 1'bz;
|
||||
assign io_in[0] = gpio[0];
|
||||
// io1
|
||||
assign gpio[1] = (gpio_ctrl[3:2] == 2'b01)? gpio_data[1]: 1'bz;
|
||||
assign io_in[1] = gpio[1];
|
||||
|
||||
// gpio模块例化
|
||||
gpio gpio_0(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.we_i(s4_we_o),
|
||||
.addr_i(s4_addr_o),
|
||||
.data_i(s4_data_o),
|
||||
.data_o(s4_data_i),
|
||||
.io_pin_i(io_in),
|
||||
.reg_ctrl(gpio_ctrl),
|
||||
.reg_data(gpio_data)
|
||||
);
|
||||
|
||||
// spi模块例化
|
||||
spi spi_0(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.data_i(s5_data_o),
|
||||
.addr_i(s5_addr_o),
|
||||
.we_i(s5_we_o),
|
||||
.data_o(s5_data_i),
|
||||
.spi_mosi(spi_mosi),
|
||||
.spi_miso(spi_miso),
|
||||
.spi_ss(spi_ss),
|
||||
.spi_clk(spi_clk)
|
||||
);
|
||||
|
||||
// rib模块例化
|
||||
rib u_rib(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
// master 0 interface
|
||||
.m0_addr_i(m0_addr_i),
|
||||
.m0_data_i(m0_data_i),
|
||||
.m0_data_o(m0_data_o),
|
||||
.m0_req_i(m0_req_i),
|
||||
.m0_we_i(m0_we_i),
|
||||
|
||||
// master 1 interface
|
||||
.m1_addr_i(m1_addr_i),
|
||||
.m1_data_i(`ZeroWord),
|
||||
.m1_data_o(m1_data_o),
|
||||
.m1_req_i(`RIB_REQ),
|
||||
.m1_we_i(`WriteDisable),
|
||||
|
||||
// master 2 interface
|
||||
.m2_addr_i(m2_addr_i),
|
||||
.m2_data_i(m2_data_i),
|
||||
.m2_data_o(m2_data_o),
|
||||
.m2_req_i(m2_req_i),
|
||||
.m2_we_i(m2_we_i),
|
||||
|
||||
// master 3 interface
|
||||
.m3_addr_i(m3_addr_i),
|
||||
.m3_data_i(m3_data_i),
|
||||
.m3_data_o(m3_data_o),
|
||||
.m3_req_i(m3_req_i),
|
||||
.m3_we_i(m3_we_i),
|
||||
|
||||
// slave 0 interface
|
||||
.s0_addr_o(s0_addr_o),
|
||||
.s0_data_o(s0_data_o),
|
||||
.s0_data_i(s0_data_i),
|
||||
.s0_we_o(s0_we_o),
|
||||
|
||||
// slave 1 interface
|
||||
.s1_addr_o(s1_addr_o),
|
||||
.s1_data_o(s1_data_o),
|
||||
.s1_data_i(s1_data_i),
|
||||
.s1_we_o(s1_we_o),
|
||||
|
||||
// slave 2 interface
|
||||
.s2_addr_o(s2_addr_o),
|
||||
.s2_data_o(s2_data_o),
|
||||
.s2_data_i(s2_data_i),
|
||||
.s2_we_o(s2_we_o),
|
||||
|
||||
// slave 3 interface
|
||||
.s3_addr_o(s3_addr_o),
|
||||
.s3_data_o(s3_data_o),
|
||||
.s3_data_i(s3_data_i),
|
||||
.s3_we_o(s3_we_o),
|
||||
|
||||
// slave 4 interface
|
||||
.s4_addr_o(s4_addr_o),
|
||||
.s4_data_o(s4_data_o),
|
||||
.s4_data_i(s4_data_i),
|
||||
.s4_we_o(s4_we_o),
|
||||
|
||||
// slave 5 interface
|
||||
.s5_addr_o(s5_addr_o),
|
||||
.s5_data_o(s5_data_o),
|
||||
.s5_data_i(s5_data_i),
|
||||
.s5_we_o(s5_we_o),
|
||||
|
||||
.hold_flag_o(rib_hold_flag_o)
|
||||
);
|
||||
|
||||
// 串口下载模块例化
|
||||
uart_debug u_uart_debug(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.debug_en_i(uart_debug_pin),
|
||||
.req_o(m3_req_i),
|
||||
.mem_we_o(m3_we_i),
|
||||
.mem_addr_o(m3_addr_i),
|
||||
.mem_wdata_o(m3_data_i),
|
||||
.mem_rdata_i(m3_data_o)
|
||||
);
|
||||
|
||||
// jtag模块例化
|
||||
jtag_top #(
|
||||
.DMI_ADDR_BITS(6),
|
||||
.DMI_DATA_BITS(32),
|
||||
.DMI_OP_BITS(2)
|
||||
) u_jtag_top(
|
||||
.clk(clk),
|
||||
.jtag_rst_n(rst),
|
||||
.jtag_pin_TCK(jtag_TCK),
|
||||
.jtag_pin_TMS(jtag_TMS),
|
||||
.jtag_pin_TDI(jtag_TDI),
|
||||
.jtag_pin_TDO(jtag_TDO),
|
||||
.reg_we_o(jtag_reg_we_o),
|
||||
.reg_addr_o(jtag_reg_addr_o),
|
||||
.reg_wdata_o(jtag_reg_data_o),
|
||||
.reg_rdata_i(jtag_reg_data_i),
|
||||
.mem_we_o(m2_we_i),
|
||||
.mem_addr_o(m2_addr_i),
|
||||
.mem_wdata_o(m2_data_i),
|
||||
.mem_rdata_i(m2_data_o),
|
||||
.op_req_o(m2_req_i),
|
||||
.halt_req_o(jtag_halt_req_o),
|
||||
.reset_req_o(jtag_reset_req_o)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
// RIB总线模块
|
||||
module rib #(
|
||||
parameter MASTER_NUM = 3,
|
||||
parameter SLAVE_NUM = 2)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
|
||||
// master 0 interface
|
||||
input wire[31:0] m0_addr_i,
|
||||
input wire[31:0] m0_data_i,
|
||||
input wire[3:0] m0_sel_i,
|
||||
input wire m0_req_vld_i,
|
||||
input wire m0_rsp_rdy_i,
|
||||
input wire m0_we_i,
|
||||
output wire m0_req_rdy_o,
|
||||
output wire m0_rsp_vld_o,
|
||||
output wire[31:0] m0_data_o,
|
||||
|
||||
// master 1 interface
|
||||
input wire[31:0] m1_addr_i,
|
||||
input wire[31:0] m1_data_i,
|
||||
input wire[3:0] m1_sel_i,
|
||||
input wire m1_req_vld_i,
|
||||
input wire m1_rsp_rdy_i,
|
||||
input wire m1_we_i,
|
||||
output wire m1_req_rdy_o,
|
||||
output wire m1_rsp_vld_o,
|
||||
output wire[31:0] m1_data_o,
|
||||
|
||||
// master 2 interface
|
||||
input wire[31:0] m2_addr_i,
|
||||
input wire[31:0] m2_data_i,
|
||||
input wire[3:0] m2_sel_i,
|
||||
input wire m2_req_vld_i,
|
||||
input wire m2_rsp_rdy_i,
|
||||
input wire m2_we_i,
|
||||
output wire m2_req_rdy_o,
|
||||
output wire m2_rsp_vld_o,
|
||||
output wire[31:0] m2_data_o,
|
||||
|
||||
// master 3 interface
|
||||
input wire[31:0] m3_addr_i,
|
||||
input wire[31:0] m3_data_i,
|
||||
input wire[3:0] m3_sel_i,
|
||||
input wire m3_req_vld_i,
|
||||
input wire m3_rsp_rdy_i,
|
||||
input wire m3_we_i,
|
||||
output wire m3_req_rdy_o,
|
||||
output wire m3_rsp_vld_o,
|
||||
output wire[31:0] m3_data_o,
|
||||
|
||||
// slave 0 interface
|
||||
input wire[31:0] s0_data_i,
|
||||
input wire s0_req_rdy_i,
|
||||
input wire s0_rsp_vld_i,
|
||||
output wire[31:0] s0_addr_o,
|
||||
output wire[31:0] s0_data_o,
|
||||
output wire[3:0] s0_sel_o,
|
||||
output wire s0_req_vld_o,
|
||||
output wire s0_rsp_rdy_o,
|
||||
output wire s0_we_o,
|
||||
|
||||
// slave 1 interface
|
||||
input wire[31:0] s1_data_i,
|
||||
input wire s1_req_rdy_i,
|
||||
input wire s1_rsp_vld_i,
|
||||
output wire[31:0] s1_addr_o,
|
||||
output wire[31:0] s1_data_o,
|
||||
output wire[3:0] s1_sel_o,
|
||||
output wire s1_req_vld_o,
|
||||
output wire s1_rsp_rdy_o,
|
||||
output wire s1_we_o,
|
||||
|
||||
// slave 2 interface
|
||||
input wire[31:0] s2_data_i,
|
||||
input wire s2_req_rdy_i,
|
||||
input wire s2_rsp_vld_i,
|
||||
output wire[31:0] s2_addr_o,
|
||||
output wire[31:0] s2_data_o,
|
||||
output wire[3:0] s2_sel_o,
|
||||
output wire s2_req_vld_o,
|
||||
output wire s2_rsp_rdy_o,
|
||||
output wire s2_we_o,
|
||||
|
||||
// slave 3 interface
|
||||
input wire[31:0] s3_data_i,
|
||||
input wire s3_req_rdy_i,
|
||||
input wire s3_rsp_vld_i,
|
||||
output wire[31:0] s3_addr_o,
|
||||
output wire[31:0] s3_data_o,
|
||||
output wire[3:0] s3_sel_o,
|
||||
output wire s3_req_vld_o,
|
||||
output wire s3_rsp_rdy_o,
|
||||
output wire s3_we_o,
|
||||
|
||||
// slave 4 interface
|
||||
input wire[31:0] s4_data_i,
|
||||
input wire s4_req_rdy_i,
|
||||
input wire s4_rsp_vld_i,
|
||||
output wire[31:0] s4_addr_o,
|
||||
output wire[31:0] s4_data_o,
|
||||
output wire[3:0] s4_sel_o,
|
||||
output wire s4_req_vld_o,
|
||||
output wire s4_rsp_rdy_o,
|
||||
output wire s4_we_o
|
||||
|
||||
);
|
||||
|
||||
/////////////////////////////// mux master //////////////////////////////
|
||||
|
||||
wire[MASTER_NUM-1:0] master_req;
|
||||
wire[31:0] master_addr[MASTER_NUM-1:0];
|
||||
wire[31:0] master_data[MASTER_NUM-1:0];
|
||||
wire[3:0] master_sel[MASTER_NUM-1:0];
|
||||
wire[MASTER_NUM-1:0] master_rsp_rdy;
|
||||
wire[MASTER_NUM-1:0] master_we;
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
|
||||
if (MASTER_NUM == 2) begin: if_m_num_2
|
||||
assign master_req = {m0_req_vld_i, m1_req_vld_i};
|
||||
assign master_rsp_rdy = {m0_rsp_rdy_i, m1_rsp_rdy_i};
|
||||
assign master_we = {m0_we_i, m1_we_i};
|
||||
wire[32*MASTER_NUM-1:0] m_addr = {m0_addr_i, m1_addr_i};
|
||||
wire[32*MASTER_NUM-1:0] m_data = {m0_data_i, m1_data_i};
|
||||
wire[4*MASTER_NUM-1:0] m_sel = {m0_sel_i, m1_sel_i};
|
||||
for (i = 0; i < MASTER_NUM; i = i + 1) begin: for_m_num_2
|
||||
assign master_addr[i] = m_addr[(i+1)*32-1:32*i];
|
||||
assign master_data[i] = m_data[(i+1)*32-1:32*i];
|
||||
assign master_sel[i] = m_sel[(i+1)*4-1:4*i];
|
||||
end
|
||||
end
|
||||
|
||||
if (MASTER_NUM == 3) begin: if_m_num_3
|
||||
assign master_req = {m0_req_vld_i, m1_req_vld_i, m2_req_vld_i};
|
||||
assign master_rsp_rdy = {m0_rsp_rdy_i, m1_rsp_rdy_i, m2_rsp_rdy_i};
|
||||
assign master_we = {m0_we_i, m1_we_i, m2_we_i};
|
||||
wire[32*MASTER_NUM-1:0] m_addr = {m0_addr_i, m1_addr_i, m2_addr_i};
|
||||
wire[32*MASTER_NUM-1:0] m_data = {m0_data_i, m1_data_i, m2_data_i};
|
||||
wire[4*MASTER_NUM-1:0] m_sel = {m0_sel_i, m1_sel_i, m2_sel_i};
|
||||
for (i = 0; i < MASTER_NUM; i = i + 1) begin: for_m_num_3
|
||||
assign master_addr[i] = m_addr[(i+1)*32-1:32*i];
|
||||
assign master_data[i] = m_data[(i+1)*32-1:32*i];
|
||||
assign master_sel[i] = m_sel[(i+1)*4-1:4*i];
|
||||
end
|
||||
end
|
||||
|
||||
if (MASTER_NUM == 4) begin: if_m_num_4
|
||||
assign master_req = {m0_req_vld_i, m1_req_vld_i, m2_req_vld_i, m3_req_vld_i};
|
||||
assign master_rsp_rdy = {m0_rsp_rdy_i, m1_rsp_rdy_i, m2_rsp_rdy_i, m3_rsp_rdy_i};
|
||||
assign master_we = {m0_we_i, m1_we_i, m2_we_i, m3_we_i};
|
||||
wire[32*MASTER_NUM-1:0] m_addr = {m0_addr_i, m1_addr_i, m2_addr_i, m3_addr_i};
|
||||
wire[32*MASTER_NUM-1:0] m_data = {m0_data_i, m1_data_i, m2_data_i, m3_data_i};
|
||||
wire[4*MASTER_NUM-1:0] m_sel = {m0_sel_i, m1_sel_i, m2_sel_i, m3_sel_i};
|
||||
for (i = 0; i < MASTER_NUM; i = i + 1) begin: for_m_num_4
|
||||
assign master_addr[i] = m_addr[(i+1)*32-1:32*i];
|
||||
assign master_data[i] = m_data[(i+1)*32-1:32*i];
|
||||
assign master_sel[i] = m_sel[(i+1)*4-1:4*i];
|
||||
end
|
||||
end
|
||||
|
||||
wire[MASTER_NUM-1:0] master_req_vec;
|
||||
wire[MASTER_NUM-1:0] master_sel_vec;
|
||||
|
||||
// 优先级仲裁机制,LSB优先级最高,MSB优先级最低
|
||||
for (i = 0; i < MASTER_NUM; i = i + 1) begin: m_arb
|
||||
if (i == 0) begin: m_is_0
|
||||
assign master_req_vec[i] = 1'b1;
|
||||
end else begin: m_is_not_0
|
||||
assign master_req_vec[i] = ~(|master_req[i-1:0]);
|
||||
end
|
||||
assign master_sel_vec[i] = master_req_vec[i] & master_req[i];
|
||||
end
|
||||
|
||||
reg[31:0] mux_m_addr;
|
||||
reg[31:0] mux_m_data;
|
||||
reg[3:0] mux_m_sel;
|
||||
reg mux_m_req_vld;
|
||||
reg mux_m_rsp_rdy;
|
||||
reg mux_m_we;
|
||||
|
||||
integer j;
|
||||
|
||||
always @ (*) begin: m_out
|
||||
mux_m_addr = 32'h0;
|
||||
mux_m_data = 32'h0;
|
||||
mux_m_sel = 4'h0;
|
||||
mux_m_req_vld = 1'b0;
|
||||
mux_m_rsp_rdy = 1'b0;
|
||||
mux_m_we = 1'b0;
|
||||
for (j = 0; j < MASTER_NUM; j = j + 1) begin: m_sig_out
|
||||
mux_m_addr = mux_m_addr | ({32{master_sel_vec[j]}} & master_addr[j]);
|
||||
mux_m_data = mux_m_data | ({32{master_sel_vec[j]}} & master_data[j]);
|
||||
mux_m_sel = mux_m_sel | ({4 {master_sel_vec[j]}} & master_sel[j]);
|
||||
mux_m_req_vld = mux_m_req_vld | ({1 {master_sel_vec[j]}} & master_req[j]);
|
||||
mux_m_rsp_rdy = mux_m_rsp_rdy | ({1 {master_sel_vec[j]}} & master_rsp_rdy[j]);
|
||||
mux_m_we = mux_m_we | ({1 {master_sel_vec[j]}} & master_we[j]);
|
||||
end
|
||||
end
|
||||
|
||||
/////////////////////////////// mux slave /////////////////////////////////
|
||||
|
||||
wire[SLAVE_NUM-1:0] slave_sel;
|
||||
|
||||
// 访问地址的最高4位决定要访问的是哪一个从设备
|
||||
// 因此最多支持16个从设备
|
||||
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: s_sel
|
||||
assign slave_sel[i] = (mux_m_addr[31:28] == i);
|
||||
end
|
||||
|
||||
wire[SLAVE_NUM-1:0] slave_req_rdy;
|
||||
wire[SLAVE_NUM-1:0] slave_rsp_vld;
|
||||
wire[31:0] slave_data[SLAVE_NUM-1:0];
|
||||
|
||||
if (SLAVE_NUM == 2) begin: if_s_num_2
|
||||
assign slave_req_rdy = {s1_req_rdy_i, s0_req_rdy_i};
|
||||
assign slave_rsp_vld = {s1_rsp_vld_i, s0_rsp_vld_i};
|
||||
wire[32*SLAVE_NUM-1:0] s_data = {s1_data_i, s0_data_i};
|
||||
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: for_s_num_2
|
||||
assign slave_data[i] = s_data[(i+1)*32-1:32*i];
|
||||
end
|
||||
end
|
||||
|
||||
if (SLAVE_NUM == 3) begin: if_s_num_3
|
||||
assign slave_req_rdy = {s2_req_rdy_i, s1_req_rdy_i, s0_req_rdy_i};
|
||||
assign slave_rsp_vld = {s2_rsp_vld_i, s1_rsp_vld_i, s0_rsp_vld_i};
|
||||
wire[32*SLAVE_NUM-1:0] s_data = {s2_data_i, s1_data_i, s0_data_i};
|
||||
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: for_s_num_3
|
||||
assign slave_data[i] = s_data[(i+1)*32-1:32*i];
|
||||
end
|
||||
end
|
||||
|
||||
if (SLAVE_NUM == 4) begin: if_s_num_4
|
||||
assign slave_req_rdy = {s3_req_rdy_i, s2_req_rdy_i, s1_req_rdy_i, s0_req_rdy_i};
|
||||
assign slave_rsp_vld = {s3_rsp_vld_i, s2_rsp_vld_i, s1_rsp_vld_i, s0_rsp_vld_i};
|
||||
wire[32*SLAVE_NUM-1:0] s_data = {s3_data_i, s2_data_i, s1_data_i, s0_data_i};
|
||||
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: for_s_num_4
|
||||
assign slave_data[i] = s_data[(i+1)*32-1:32*i];
|
||||
end
|
||||
end
|
||||
|
||||
if (SLAVE_NUM == 5) begin: if_s_num_5
|
||||
assign slave_req_rdy = {s4_req_rdy_i, s3_req_rdy_i, s2_req_rdy_i, s1_req_rdy_i, s0_req_rdy_i};
|
||||
assign slave_rsp_vld = {s4_rsp_vld_i, s3_rsp_vld_i, s2_rsp_vld_i, s1_rsp_vld_i, s0_rsp_vld_i};
|
||||
wire[32*SLAVE_NUM-1:0] s_data = {s4_data_i, s3_data_i, s2_data_i, s1_data_i, s0_data_i};
|
||||
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: for_s_num_5
|
||||
assign slave_data[i] = s_data[(i+1)*32-1:32*i];
|
||||
end
|
||||
end
|
||||
|
||||
reg[31:0] mux_s_data;
|
||||
reg mux_s_req_rdy;
|
||||
reg mux_s_rsp_vld;
|
||||
|
||||
always @ (*) begin: s_out
|
||||
mux_s_data = 32'h0;
|
||||
mux_s_req_rdy = 1'b0;
|
||||
mux_s_rsp_vld = 1'b0;
|
||||
for (j = 0; j < SLAVE_NUM; j = j + 1) begin: s_sig_out
|
||||
mux_s_data = mux_s_data | ({32{slave_sel[j]}} & slave_data[j]);
|
||||
mux_s_req_rdy = mux_s_req_rdy | ({1 {slave_sel[j]}} & slave_req_rdy[j]);
|
||||
mux_s_rsp_vld = mux_s_rsp_vld | ({1 {slave_sel[j]}} & slave_rsp_vld[j]);
|
||||
end
|
||||
end
|
||||
|
||||
/////////////////////////////// demux master //////////////////////////////
|
||||
|
||||
wire[MASTER_NUM-1:0] demux_m_req_rdy;
|
||||
wire[MASTER_NUM-1:0] demux_m_rsp_vld;
|
||||
wire[32*MASTER_NUM-1:0] demux_m_data;
|
||||
|
||||
for (i = 0; i < MASTER_NUM; i = i + 1) begin: demux_m_sig
|
||||
assign demux_m_req_rdy[i] = {1 {master_sel_vec[i]}} & mux_s_req_rdy;
|
||||
assign demux_m_rsp_vld[i] = {1 {master_sel_vec[i]}} & mux_s_rsp_vld;
|
||||
assign demux_m_data[(i+1)*32-1:32*i] = {32{master_sel_vec[i]}} & mux_s_data;
|
||||
end
|
||||
|
||||
if (MASTER_NUM == 2) begin: demux_m_sig_2
|
||||
assign {m0_req_rdy_o, m1_req_rdy_o} = demux_m_req_rdy;
|
||||
assign {m0_rsp_vld_o, m1_rsp_vld_o} = demux_m_rsp_vld;
|
||||
assign {m0_data_o, m1_data_o} = demux_m_data;
|
||||
end
|
||||
|
||||
if (MASTER_NUM == 3) begin: demux_m_sig_3
|
||||
assign {m0_req_rdy_o, m1_req_rdy_o, m2_req_rdy_o} = demux_m_req_rdy;
|
||||
assign {m0_rsp_vld_o, m1_rsp_vld_o, m2_rsp_vld_o} = demux_m_rsp_vld;
|
||||
assign {m0_data_o, m1_data_o, m2_data_o} = demux_m_data;
|
||||
end
|
||||
|
||||
if (MASTER_NUM == 4) begin: demux_m_sig_4
|
||||
assign {m0_req_rdy_o, m1_req_rdy_o, m2_req_rdy_o, m3_req_rdy_o} = demux_m_req_rdy;
|
||||
assign {m0_rsp_vld_o, m1_rsp_vld_o, m2_rsp_vld_o, m3_rsp_vld_o} = demux_m_rsp_vld;
|
||||
assign {m0_data_o, m1_data_o, m2_data_o, m3_data_o} = demux_m_data;
|
||||
end
|
||||
|
||||
/////////////////////////////// demux slave //////////////////////////////
|
||||
|
||||
wire[32*SLAVE_NUM-1:0] demux_s_addr;
|
||||
wire[32*SLAVE_NUM-1:0] demux_s_data;
|
||||
wire[4*SLAVE_NUM-1:0] demux_s_sel;
|
||||
wire[SLAVE_NUM-1:0] demux_s_req_vld;
|
||||
wire[SLAVE_NUM-1:0] demux_s_rsp_rdy;
|
||||
wire[SLAVE_NUM-1:0] demux_s_we;
|
||||
|
||||
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: demux_s_sig
|
||||
// 去掉外设基地址,只保留offset
|
||||
assign demux_s_addr[(i+1)*32-1:32*i] = {32{slave_sel[i]}} & {4'h0, mux_m_addr[27:0]};
|
||||
assign demux_s_data[(i+1)*32-1:32*i] = {32{slave_sel[i]}} & mux_m_data;
|
||||
assign demux_s_sel[(i+1)*4-1:4*i] = {4 {slave_sel[i]}} & mux_m_sel;
|
||||
assign demux_s_req_vld[i] = {1 {slave_sel[i]}} & mux_m_req_vld;
|
||||
assign demux_s_rsp_rdy[i] = {1 {slave_sel[i]}} & mux_m_rsp_rdy;
|
||||
assign demux_s_we[i] = {1 {slave_sel[i]}} & mux_m_we;
|
||||
end
|
||||
|
||||
if (SLAVE_NUM == 2) begin: demux_s_sig_2
|
||||
assign {s1_addr_o, s0_addr_o} = demux_s_addr;
|
||||
assign {s1_data_o, s0_data_o} = demux_s_data;
|
||||
assign {s1_sel_o, s0_sel_o} = demux_s_sel;
|
||||
assign {s1_req_vld_o, s0_req_vld_o} = demux_s_req_vld;
|
||||
assign {s1_rsp_rdy_o, s0_rsp_rdy_o} = demux_s_rsp_rdy;
|
||||
assign {s1_we_o, s0_we_o} = demux_s_we;
|
||||
end
|
||||
|
||||
if (SLAVE_NUM == 3) begin: demux_s_sig_3
|
||||
assign {s2_addr_o, s1_addr_o, s0_addr_o} = demux_s_addr;
|
||||
assign {s2_data_o, s1_data_o, s0_data_o} = demux_s_data;
|
||||
assign {s2_sel_o, s1_sel_o, s0_sel_o} = demux_s_sel;
|
||||
assign {s2_req_vld_o, s1_req_vld_o, s0_req_vld_o} = demux_s_req_vld;
|
||||
assign {s2_rsp_rdy_o, s1_rsp_rdy_o, s0_rsp_rdy_o} = demux_s_rsp_rdy;
|
||||
assign {s2_we_o, s1_we_o, s0_we_o} = demux_s_we;
|
||||
end
|
||||
|
||||
if (SLAVE_NUM == 4) begin: demux_s_sig_4
|
||||
assign {s3_addr_o, s2_addr_o, s1_addr_o, s0_addr_o} = demux_s_addr;
|
||||
assign {s3_data_o, s2_data_o, s1_data_o, s0_data_o} = demux_s_data;
|
||||
assign {s3_sel_o, s2_sel_o, s1_sel_o, s0_sel_o} = demux_s_sel;
|
||||
assign {s3_req_vld_o, s2_req_vld_o, s1_req_vld_o, s0_req_vld_o} = demux_s_req_vld;
|
||||
assign {s3_rsp_rdy_o, s2_rsp_rdy_o, s1_rsp_rdy_o, s0_rsp_rdy_o} = demux_s_rsp_rdy;
|
||||
assign {s3_we_o, s2_we_o, s1_we_o, s0_we_o} = demux_s_we;
|
||||
end
|
||||
|
||||
if (SLAVE_NUM == 5) begin: demux_s_sig_5
|
||||
assign {s4_addr_o, s3_addr_o, s2_addr_o, s1_addr_o, s0_addr_o} = demux_s_addr;
|
||||
assign {s4_data_o, s3_data_o, s2_data_o, s1_data_o, s0_data_o} = demux_s_data;
|
||||
assign {s4_sel_o, s3_sel_o, s2_sel_o, s1_sel_o, s0_sel_o} = demux_s_sel;
|
||||
assign {s4_req_vld_o, s3_req_vld_o, s2_req_vld_o, s1_req_vld_o, s0_req_vld_o} = demux_s_req_vld;
|
||||
assign {s4_rsp_rdy_o, s3_rsp_rdy_o, s2_rsp_rdy_o, s1_rsp_rdy_o, s0_rsp_rdy_o} = demux_s_rsp_rdy;
|
||||
assign {s4_we_o, s3_we_o, s2_we_o, s1_we_o, s0_we_o} = demux_s_we;
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,434 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
// tinyriscv soc顶层模块
|
||||
module tinyriscv_soc_top(
|
||||
|
||||
input wire clk,
|
||||
input wire rst_ext_i,
|
||||
|
||||
output wire halted_ind, // jtag是否已经halt住CPU信号
|
||||
|
||||
output wire uart_tx_pin, // UART发送引脚
|
||||
input wire uart_rx_pin, // UART接收引脚
|
||||
|
||||
inout wire[1:0] gpio, // GPIO引脚
|
||||
|
||||
input wire jtag_TCK, // JTAG TCK引脚
|
||||
input wire jtag_TMS, // JTAG TMS引脚
|
||||
input wire jtag_TDI, // JTAG TDI引脚
|
||||
output wire jtag_TDO // JTAG TDO引脚
|
||||
|
||||
);
|
||||
|
||||
// master 0 interface
|
||||
wire[31:0] m0_addr_i;
|
||||
wire[31:0] m0_data_i;
|
||||
wire[3:0] m0_sel_i;
|
||||
wire m0_req_vld_i;
|
||||
wire m0_rsp_rdy_i;
|
||||
wire m0_we_i;
|
||||
wire m0_req_rdy_o;
|
||||
wire m0_rsp_vld_o;
|
||||
wire[31:0] m0_data_o;
|
||||
|
||||
// master 1 interface
|
||||
wire[31:0] m1_addr_i;
|
||||
wire[31:0] m1_data_i;
|
||||
wire[3:0] m1_sel_i;
|
||||
wire m1_req_vld_i;
|
||||
wire m1_rsp_rdy_i;
|
||||
wire m1_we_i;
|
||||
wire m1_req_rdy_o;
|
||||
wire m1_rsp_vld_o;
|
||||
wire[31:0] m1_data_o;
|
||||
|
||||
// master 2 interface
|
||||
wire[31:0] m2_addr_i;
|
||||
wire[31:0] m2_data_i;
|
||||
wire[3:0] m2_sel_i;
|
||||
wire m2_req_vld_i;
|
||||
wire m2_rsp_rdy_i;
|
||||
wire m2_we_i;
|
||||
wire m2_req_rdy_o;
|
||||
wire m2_rsp_vld_o;
|
||||
wire[31:0] m2_data_o;
|
||||
|
||||
// master 3 interface
|
||||
wire[31:0] m3_addr_i;
|
||||
wire[31:0] m3_data_i;
|
||||
wire[3:0] m3_sel_i;
|
||||
wire m3_req_vld_i;
|
||||
wire m3_rsp_rdy_i;
|
||||
wire m3_we_i;
|
||||
wire m3_req_rdy_o;
|
||||
wire m3_rsp_vld_o;
|
||||
wire[31:0] m3_data_o;
|
||||
|
||||
// slave 0 interface
|
||||
wire[31:0] s0_data_i;
|
||||
wire s0_req_rdy_i;
|
||||
wire s0_rsp_vld_i;
|
||||
wire[31:0] s0_addr_o;
|
||||
wire[31:0] s0_data_o;
|
||||
wire[3:0] s0_sel_o;
|
||||
wire s0_req_vld_o;
|
||||
wire s0_rsp_rdy_o;
|
||||
wire s0_we_o;
|
||||
|
||||
// slave 1 interface
|
||||
wire[31:0] s1_data_i;
|
||||
wire s1_req_rdy_i;
|
||||
wire s1_rsp_vld_i;
|
||||
wire[31:0] s1_addr_o;
|
||||
wire[31:0] s1_data_o;
|
||||
wire[3:0] s1_sel_o;
|
||||
wire s1_req_vld_o;
|
||||
wire s1_rsp_rdy_o;
|
||||
wire s1_we_o;
|
||||
|
||||
// slave 2 interface
|
||||
wire[31:0] s2_data_i;
|
||||
wire s2_req_rdy_i;
|
||||
wire s2_rsp_vld_i;
|
||||
wire[31:0] s2_addr_o;
|
||||
wire[31:0] s2_data_o;
|
||||
wire[3:0] s2_sel_o;
|
||||
wire s2_req_vld_o;
|
||||
wire s2_rsp_rdy_o;
|
||||
wire s2_we_o;
|
||||
|
||||
// slave 3 interface
|
||||
wire[31:0] s3_data_i;
|
||||
wire s3_req_rdy_i;
|
||||
wire s3_rsp_vld_i;
|
||||
wire[31:0] s3_addr_o;
|
||||
wire[31:0] s3_data_o;
|
||||
wire[3:0] s3_sel_o;
|
||||
wire s3_req_vld_o;
|
||||
wire s3_rsp_rdy_o;
|
||||
wire s3_we_o;
|
||||
|
||||
// slave 4 interface
|
||||
wire[31:0] s4_data_i;
|
||||
wire s4_req_rdy_i;
|
||||
wire s4_rsp_vld_i;
|
||||
wire[31:0] s4_addr_o;
|
||||
wire[31:0] s4_data_o;
|
||||
wire[3:0] s4_sel_o;
|
||||
wire s4_req_vld_o;
|
||||
wire s4_rsp_rdy_o;
|
||||
wire s4_we_o;
|
||||
|
||||
// jtag
|
||||
wire jtag_halt_req_o;
|
||||
wire jtag_reset_req_o;
|
||||
wire[4:0] jtag_reg_addr_o;
|
||||
wire[31:0] jtag_reg_data_o;
|
||||
wire jtag_reg_we_o;
|
||||
wire[31:0] jtag_reg_data_i;
|
||||
|
||||
// tinyriscv
|
||||
wire[`INT_WIDTH-1:0] int_flag;
|
||||
wire rst_n;
|
||||
wire jtag_rst_n;
|
||||
|
||||
// timer0
|
||||
wire timer0_int;
|
||||
|
||||
// gpio
|
||||
wire[1:0] io_in;
|
||||
wire[31:0] gpio_ctrl;
|
||||
wire[31:0] gpio_data;
|
||||
|
||||
assign int_flag = {{(`INT_WIDTH-1){1'b0}}, timer0_int};
|
||||
|
||||
// 复位控制模块例化
|
||||
rst_ctrl u_rst_ctrl(
|
||||
.clk(clk),
|
||||
.rst_ext_i(rst_ext_i),
|
||||
.rst_jtag_i(jtag_reset_req_o),
|
||||
.core_rst_n_o(rst_n),
|
||||
.jtag_rst_n_o(jtag_rst_n)
|
||||
);
|
||||
|
||||
// 低电平点亮LED
|
||||
// 低电平表示已经halt住CPU
|
||||
assign halted_ind = ~jtag_halt_req_o;
|
||||
|
||||
// tinyriscv处理器核模块例化
|
||||
tinyriscv_core u_tinyriscv_core(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
|
||||
// 指令总线
|
||||
.ibus_addr_o(m0_addr_i),
|
||||
.ibus_data_i(m0_data_o),
|
||||
.ibus_data_o(m0_data_i),
|
||||
.ibus_we_o(m0_we_i),
|
||||
.ibus_sel_o(m0_sel_i),
|
||||
.ibus_req_valid_o(m0_req_vld_i),
|
||||
.ibus_req_ready_i(m0_req_rdy_o),
|
||||
.ibus_rsp_valid_i(m0_rsp_vld_o),
|
||||
.ibus_rsp_ready_o(m0_rsp_rdy_i),
|
||||
|
||||
// 数据总线
|
||||
.dbus_addr_o(m1_addr_i),
|
||||
.dbus_data_i(m1_data_o),
|
||||
.dbus_data_o(m1_data_i),
|
||||
.dbus_we_o(m1_we_i),
|
||||
.dbus_sel_o(m1_sel_i),
|
||||
.dbus_req_valid_o(m1_req_vld_i),
|
||||
.dbus_req_ready_i(m1_req_rdy_o),
|
||||
.dbus_rsp_valid_i(m1_rsp_vld_o),
|
||||
.dbus_rsp_ready_o(m1_rsp_rdy_i),
|
||||
|
||||
.jtag_halt_i(jtag_halt_req_o),
|
||||
.int_i(int_flag)
|
||||
);
|
||||
|
||||
// 指令存储器
|
||||
rom #(
|
||||
.DP(`ROM_DEPTH)
|
||||
) u_rom(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.addr_i(s0_addr_o),
|
||||
.data_i(s0_data_o),
|
||||
.sel_i(s0_sel_o),
|
||||
.we_i(s0_we_o),
|
||||
.data_o(s0_data_i),
|
||||
.req_valid_i(s0_req_vld_o),
|
||||
.req_ready_o(s0_req_rdy_i),
|
||||
.rsp_valid_o(s0_rsp_vld_i),
|
||||
.rsp_ready_i(s0_rsp_rdy_o)
|
||||
);
|
||||
|
||||
// 数据存储器
|
||||
ram #(
|
||||
.DP(`RAM_DEPTH)
|
||||
) u_ram(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.addr_i(s1_addr_o),
|
||||
.data_i(s1_data_o),
|
||||
.sel_i(s1_sel_o),
|
||||
.we_i(s1_we_o),
|
||||
.data_o(s1_data_i),
|
||||
.req_valid_i(s1_req_vld_o),
|
||||
.req_ready_o(s1_req_rdy_i),
|
||||
.rsp_valid_o(s1_rsp_vld_i),
|
||||
.rsp_ready_i(s1_rsp_rdy_o)
|
||||
);
|
||||
|
||||
// timer模块例化
|
||||
timer timer_0(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.addr_i(s2_addr_o),
|
||||
.data_i(s2_data_o),
|
||||
.sel_i(s2_sel_o),
|
||||
.we_i(s2_we_o),
|
||||
.data_o(s2_data_i),
|
||||
.req_valid_i(s2_req_vld_o),
|
||||
.req_ready_o(s2_req_rdy_i),
|
||||
.rsp_valid_o(s2_rsp_vld_i),
|
||||
.rsp_ready_i(s2_rsp_rdy_o),
|
||||
.int_sig_o(timer0_int)
|
||||
);
|
||||
|
||||
// uart模块例化
|
||||
uart uart_0(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.addr_i(s3_addr_o),
|
||||
.data_i(s3_data_o),
|
||||
.sel_i(s3_sel_o),
|
||||
.we_i(s3_we_o),
|
||||
.data_o(s3_data_i),
|
||||
.req_valid_i(s3_req_vld_o),
|
||||
.req_ready_o(s3_req_rdy_i),
|
||||
.rsp_valid_o(s3_rsp_vld_i),
|
||||
.rsp_ready_i(s3_rsp_rdy_o),
|
||||
.tx_pin(uart_tx_pin),
|
||||
.rx_pin(uart_rx_pin)
|
||||
);
|
||||
|
||||
// io0
|
||||
assign gpio[0] = (gpio_ctrl[1:0] == 2'b01)? gpio_data[0]: 1'bz;
|
||||
assign io_in[0] = gpio[0];
|
||||
// io1
|
||||
assign gpio[1] = (gpio_ctrl[3:2] == 2'b01)? gpio_data[1]: 1'bz;
|
||||
assign io_in[1] = gpio[1];
|
||||
|
||||
// gpio模块例化
|
||||
gpio gpio_0(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.addr_i(s4_addr_o),
|
||||
.data_i(s4_data_o),
|
||||
.sel_i(s4_sel_o),
|
||||
.we_i(s4_we_o),
|
||||
.data_o(s4_data_i),
|
||||
.req_valid_i(s4_req_vld_o),
|
||||
.req_ready_o(s4_req_rdy_i),
|
||||
.rsp_valid_o(s4_rsp_vld_i),
|
||||
.rsp_ready_i(s4_rsp_rdy_o),
|
||||
.io_pin_i(io_in),
|
||||
.reg_ctrl(gpio_ctrl),
|
||||
.reg_data(gpio_data)
|
||||
);
|
||||
|
||||
// jtag模块例化
|
||||
jtag_top #(
|
||||
.DMI_ADDR_BITS(6),
|
||||
.DMI_DATA_BITS(32),
|
||||
.DMI_OP_BITS(2)
|
||||
) u_jtag_top(
|
||||
.clk(clk),
|
||||
.jtag_rst_n(jtag_rst_n),
|
||||
.jtag_pin_TCK(jtag_TCK),
|
||||
.jtag_pin_TMS(jtag_TMS),
|
||||
.jtag_pin_TDI(jtag_TDI),
|
||||
.jtag_pin_TDO(jtag_TDO),
|
||||
.reg_we_o(jtag_reg_we_o),
|
||||
.reg_addr_o(jtag_reg_addr_o),
|
||||
.reg_wdata_o(jtag_reg_data_o),
|
||||
.reg_rdata_i(jtag_reg_data_i),
|
||||
.mem_we_o(m2_we_i),
|
||||
.mem_addr_o(m2_addr_i),
|
||||
.mem_wdata_o(m2_data_i),
|
||||
.mem_rdata_i(m2_data_o),
|
||||
.mem_sel_o(m2_sel_i),
|
||||
.req_valid_o(m2_req_vld_i),
|
||||
.req_ready_i(m2_req_rdy_o),
|
||||
.rsp_valid_i(m2_rsp_vld_o),
|
||||
.rsp_ready_o(m2_rsp_rdy_i),
|
||||
.halt_req_o(jtag_halt_req_o),
|
||||
.reset_req_o(jtag_reset_req_o)
|
||||
);
|
||||
|
||||
// rib总线模块例化
|
||||
rib #(
|
||||
.MASTER_NUM(3),
|
||||
.SLAVE_NUM(5)
|
||||
) u_rib(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
|
||||
// master 0 interface
|
||||
.m0_addr_i(m0_addr_i),
|
||||
.m0_data_i(m0_data_i),
|
||||
.m0_sel_i(m0_sel_i),
|
||||
.m0_req_vld_i(m0_req_vld_i),
|
||||
.m0_rsp_rdy_i(m0_rsp_rdy_i),
|
||||
.m0_we_i(m0_we_i),
|
||||
.m0_req_rdy_o(m0_req_rdy_o),
|
||||
.m0_rsp_vld_o(m0_rsp_vld_o),
|
||||
.m0_data_o(m0_data_o),
|
||||
|
||||
// master 1 interface
|
||||
.m1_addr_i(m1_addr_i),
|
||||
.m1_data_i(m1_data_i),
|
||||
.m1_sel_i(m1_sel_i),
|
||||
.m1_req_vld_i(m1_req_vld_i),
|
||||
.m1_rsp_rdy_i(m1_rsp_rdy_i),
|
||||
.m1_we_i(m1_we_i),
|
||||
.m1_req_rdy_o(m1_req_rdy_o),
|
||||
.m1_rsp_vld_o(m1_rsp_vld_o),
|
||||
.m1_data_o(m1_data_o),
|
||||
|
||||
// master 2 interface
|
||||
.m2_addr_i(m2_addr_i),
|
||||
.m2_data_i(m2_data_i),
|
||||
.m2_sel_i(m2_sel_i),
|
||||
.m2_req_vld_i(m2_req_vld_i),
|
||||
.m2_rsp_rdy_i(m2_rsp_rdy_i),
|
||||
.m2_we_i(m2_we_i),
|
||||
.m2_req_rdy_o(m2_req_rdy_o),
|
||||
.m2_rsp_vld_o(m2_rsp_vld_o),
|
||||
.m2_data_o(m2_data_o),
|
||||
|
||||
// master 3 interface
|
||||
.m3_addr_i(m3_addr_i),
|
||||
.m3_data_i(m3_data_i),
|
||||
.m3_sel_i(m3_sel_i),
|
||||
.m3_req_vld_i(m3_req_vld_i),
|
||||
.m3_rsp_rdy_i(m3_rsp_rdy_i),
|
||||
.m3_we_i(m3_we_i),
|
||||
.m3_req_rdy_o(m3_req_rdy_o),
|
||||
.m3_rsp_vld_o(m3_rsp_vld_o),
|
||||
.m3_data_o(m3_data_o),
|
||||
|
||||
// slave 0 interface
|
||||
.s0_data_i(s0_data_i),
|
||||
.s0_req_rdy_i(s0_req_rdy_i),
|
||||
.s0_rsp_vld_i(s0_rsp_vld_i),
|
||||
.s0_addr_o(s0_addr_o),
|
||||
.s0_data_o(s0_data_o),
|
||||
.s0_sel_o(s0_sel_o),
|
||||
.s0_req_vld_o(s0_req_vld_o),
|
||||
.s0_rsp_rdy_o(s0_rsp_rdy_o),
|
||||
.s0_we_o(s0_we_o),
|
||||
|
||||
// slave 1 interface
|
||||
.s1_data_i(s1_data_i),
|
||||
.s1_req_rdy_i(s1_req_rdy_i),
|
||||
.s1_rsp_vld_i(s1_rsp_vld_i),
|
||||
.s1_addr_o(s1_addr_o),
|
||||
.s1_data_o(s1_data_o),
|
||||
.s1_sel_o(s1_sel_o),
|
||||
.s1_req_vld_o(s1_req_vld_o),
|
||||
.s1_rsp_rdy_o(s1_rsp_rdy_o),
|
||||
.s1_we_o(s1_we_o),
|
||||
|
||||
// slave 2 interface
|
||||
.s2_data_i(s2_data_i),
|
||||
.s2_req_rdy_i(s2_req_rdy_i),
|
||||
.s2_rsp_vld_i(s2_rsp_vld_i),
|
||||
.s2_addr_o(s2_addr_o),
|
||||
.s2_data_o(s2_data_o),
|
||||
.s2_sel_o(s2_sel_o),
|
||||
.s2_req_vld_o(s2_req_vld_o),
|
||||
.s2_rsp_rdy_o(s2_rsp_rdy_o),
|
||||
.s2_we_o(s2_we_o),
|
||||
|
||||
// slave 3 interface
|
||||
.s3_data_i(s3_data_i),
|
||||
.s3_req_rdy_i(s3_req_rdy_i),
|
||||
.s3_rsp_vld_i(s3_rsp_vld_i),
|
||||
.s3_addr_o(s3_addr_o),
|
||||
.s3_data_o(s3_data_o),
|
||||
.s3_sel_o(s3_sel_o),
|
||||
.s3_req_vld_o(s3_req_vld_o),
|
||||
.s3_rsp_rdy_o(s3_rsp_rdy_o),
|
||||
.s3_we_o(s3_we_o),
|
||||
|
||||
// slave 4 interface
|
||||
.s4_data_i(s4_data_i),
|
||||
.s4_req_rdy_i(s4_req_rdy_i),
|
||||
.s4_rsp_vld_i(s4_rsp_vld_i),
|
||||
.s4_addr_o(s4_addr_o),
|
||||
.s4_data_o(s4_data_o),
|
||||
.s4_sel_o(s4_sel_o),
|
||||
.s4_req_vld_o(s4_req_vld_o),
|
||||
.s4_rsp_rdy_o(s4_rsp_rdy_o),
|
||||
.s4_we_o(s4_we_o)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -19,7 +19,7 @@ module gen_ticks_sync #(
|
|||
parameter DP = 2,
|
||||
parameter DW = 32)(
|
||||
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
input wire clk,
|
||||
|
||||
input wire[DW-1:0] din,
|
||||
|
@ -32,11 +32,11 @@ module gen_ticks_sync #(
|
|||
genvar i;
|
||||
|
||||
generate
|
||||
for (i = 0; i < DP; i = i + 1) begin: dp_width
|
||||
for (i = 0; i < DP; i = i + 1) begin: ticks_sync
|
||||
if (i == 0) begin: dp_is_0
|
||||
gen_rst_0_dff #(DW) rst_0_dff(clk, rst, din, sync_dat[0]);
|
||||
gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, din, sync_dat[0]);
|
||||
end else begin: dp_is_not_0
|
||||
gen_rst_0_dff #(DW) rst_0_dff(clk, rst, sync_dat[i-1], sync_dat[i]);
|
||||
gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, sync_dat[i-1], sync_dat[i]);
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
|
|
@ -19,7 +19,7 @@ module gen_pipe_dff #(
|
|||
parameter DW = 32)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
input wire hold_en,
|
||||
|
||||
input wire[DW-1:0] def_val,
|
||||
|
@ -30,8 +30,8 @@ module gen_pipe_dff #(
|
|||
|
||||
reg[DW-1:0] qout_r;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (!rst | hold_en) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | hold_en) begin
|
||||
qout_r <= def_val;
|
||||
end else begin
|
||||
qout_r <= din;
|
||||
|
@ -47,7 +47,7 @@ module gen_rst_0_dff #(
|
|||
parameter DW = 32)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
|
||||
input wire[DW-1:0] din,
|
||||
output wire[DW-1:0] qout
|
||||
|
@ -56,8 +56,8 @@ module gen_rst_0_dff #(
|
|||
|
||||
reg[DW-1:0] qout_r;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (!rst) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
qout_r <= {DW{1'b0}};
|
||||
end else begin
|
||||
qout_r <= din;
|
||||
|
@ -73,7 +73,7 @@ module gen_rst_1_dff #(
|
|||
parameter DW = 32)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
|
||||
input wire[DW-1:0] din,
|
||||
output wire[DW-1:0] qout
|
||||
|
@ -82,8 +82,8 @@ module gen_rst_1_dff #(
|
|||
|
||||
reg[DW-1:0] qout_r;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (!rst) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
qout_r <= {DW{1'b1}};
|
||||
end else begin
|
||||
qout_r <= din;
|
||||
|
@ -99,7 +99,7 @@ module gen_rst_def_dff #(
|
|||
parameter DW = 32)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
input wire[DW-1:0] def_val,
|
||||
|
||||
input wire[DW-1:0] din,
|
||||
|
@ -109,8 +109,8 @@ module gen_rst_def_dff #(
|
|||
|
||||
reg[DW-1:0] qout_r;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (!rst) begin
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
qout_r <= def_val;
|
||||
end else begin
|
||||
qout_r <= din;
|
||||
|
@ -126,7 +126,33 @@ module gen_en_dff #(
|
|||
parameter DW = 32)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire rst_n,
|
||||
|
||||
input wire en,
|
||||
input wire[DW-1:0] din,
|
||||
output wire[DW-1:0] qout
|
||||
|
||||
);
|
||||
|
||||
reg[DW-1:0] qout_r;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
qout_r <= {DW{1'b0}};
|
||||
end else if (en == 1'b1) begin
|
||||
qout_r <= din;
|
||||
end
|
||||
end
|
||||
|
||||
assign qout = qout_r;
|
||||
|
||||
endmodule
|
||||
|
||||
// 带使能端、没有复位的触发器
|
||||
module gen_en_dffnr #(
|
||||
parameter DW = 32)(
|
||||
|
||||
input wire clk,
|
||||
|
||||
input wire en,
|
||||
input wire[DW-1:0] din,
|
||||
|
@ -137,9 +163,7 @@ module gen_en_dff #(
|
|||
reg[DW-1:0] qout_r;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (!rst) begin
|
||||
qout_r <= {DW{1'b0}};
|
||||
end else if (en == 1'b1) begin
|
||||
if (en == 1'b1) begin
|
||||
qout_r <= din;
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
|
||||
module gen_ram #(
|
||||
parameter DP = 512,
|
||||
parameter DW = 32,
|
||||
parameter MW = 4,
|
||||
parameter AW = 32)(
|
||||
|
||||
input wire clk,
|
||||
input wire[AW-1:0] addr_i,
|
||||
input wire[DW-1:0] data_i,
|
||||
input wire[MW-1:0] sel_i,
|
||||
input wire we_i,
|
||||
|
||||
output wire[DW-1:0] data_o
|
||||
|
||||
);
|
||||
|
||||
reg[DW-1:0] ram [0:DP-1];
|
||||
reg[AW-1:0] addr_r;
|
||||
wire[MW-1:0] wen;
|
||||
wire ren;
|
||||
|
||||
assign ren = (~we_i);
|
||||
assign wen = ({MW{we_i}} & sel_i);
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (ren) begin
|
||||
addr_r <= addr_i;
|
||||
end
|
||||
end
|
||||
|
||||
assign data_o = ram[addr_r];
|
||||
|
||||
genvar i;
|
||||
|
||||
generate
|
||||
for (i = 0; i < MW; i = i + 1) begin: sel_width
|
||||
if ((8 * i + 8) > DW) begin: i_gt_8
|
||||
always @ (posedge clk) begin: i_gt_8_ff
|
||||
if (wen[i]) begin: gt_8_wen
|
||||
ram[addr_i][DW-1:8*i] <= data_i[DW-1:8*i];
|
||||
end
|
||||
end
|
||||
end else begin: i_lt_8
|
||||
always @ (posedge clk) begin: i_lt_8_ff
|
||||
if (wen[i]) begin: lt_8_wen
|
||||
ram[addr_i][8*i+7:8*i] <= data_i[8*i+7:8*i];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
module vld_rdy #(
|
||||
parameter CUT_READY = 0)(
|
||||
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
|
||||
input wire vld_i,
|
||||
output wire rdy_o,
|
||||
input wire rdy_i,
|
||||
output wire vld_o
|
||||
|
||||
);
|
||||
|
||||
wire vld_set;
|
||||
wire vld_clr;
|
||||
wire vld_ena;
|
||||
wire vld_r;
|
||||
wire vld_nxt;
|
||||
|
||||
// The valid will be set when input handshaked
|
||||
assign vld_set = vld_i & rdy_o;
|
||||
// The valid will be clr when output handshaked
|
||||
assign vld_clr = vld_o & rdy_i;
|
||||
|
||||
assign vld_ena = vld_set | vld_clr;
|
||||
assign vld_nxt = vld_set | (~vld_clr);
|
||||
|
||||
gen_en_dff #(1) vld_dff(clk, rst_n, vld_ena, vld_nxt, vld_r);
|
||||
|
||||
assign vld_o = vld_r;
|
||||
|
||||
if (CUT_READY == 1) begin
|
||||
// If cut ready, then only accept when stage is not full
|
||||
assign rdy_o = (~vld_r);
|
||||
end else begin
|
||||
// If not cut ready, then can accept when stage is not full or it is popping
|
||||
assign rdy_o = (~vld_r) | vld_clr;
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -2,6 +2,5 @@
|
|||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
gpio.bin
|
||||
gpio.dump
|
||||
gpio
|
||||
*.bin
|
||||
*.dump
|
|
@ -0,0 +1,4 @@
|
|||
**bsp**:板级支持包,是所有C语言程序的基础(公共部分代码)。
|
||||
|
||||
**examples**:一些C语言程序例程。
|
||||
|
|
@ -2,3 +2,5 @@
|
|||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
|
@ -0,0 +1,3 @@
|
|||
**include**: 公共头文件目录。
|
||||
|
||||
**lib**: 公共函数目录。
|
|
@ -1,14 +1,15 @@
|
|||
|
||||
RISCV_PATH := $(TOOLCHAIN_DIR)/tools/gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64/
|
||||
RISCV_TOOLS_PATH := $(TOOLCHAIN_DIR)/tools/gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64/bin
|
||||
RISCV_TOOLS_PREFIX := riscv-none-embed-
|
||||
|
||||
RISCV_GCC := $(abspath $(RISCV_PATH)/bin/riscv-none-embed-gcc)
|
||||
RISCV_AS := $(abspath $(RISCV_PATH)/bin/riscv-none-embed-as)
|
||||
RISCV_GXX := $(abspath $(RISCV_PATH)/bin/riscv-none-embed-g++)
|
||||
RISCV_OBJDUMP := $(abspath $(RISCV_PATH)/bin/riscv-none-embed-objdump)
|
||||
RISCV_GDB := $(abspath $(RISCV_PATH)/bin/riscv-none-embed-gdb)
|
||||
RISCV_AR := $(abspath $(RISCV_PATH)/bin/riscv-none-embed-ar)
|
||||
RISCV_OBJCOPY := $(abspath $(RISCV_PATH)/bin/riscv-none-embed-objcopy)
|
||||
RISCV_READELF := $(abspath $(RISCV_PATH)/bin/riscv-none-embed-readelf)
|
||||
RISCV_GCC := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)gcc)
|
||||
RISCV_AS := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)as)
|
||||
RISCV_GXX := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)g++)
|
||||
RISCV_OBJDUMP := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)objdump)
|
||||
RISCV_GDB := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)gdb)
|
||||
RISCV_AR := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)ar)
|
||||
RISCV_OBJCOPY := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)objcopy)
|
||||
RISCV_READELF := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)readelf)
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGET)
|
||||
|
@ -20,8 +21,6 @@ C_SRCS += $(COMMON_DIR)/trap_handler.c
|
|||
C_SRCS += $(COMMON_DIR)/lib/utils.c
|
||||
C_SRCS += $(COMMON_DIR)/lib/xprintf.c
|
||||
C_SRCS += $(COMMON_DIR)/lib/uart.c
|
||||
C_SRCS += $(COMMON_DIR)/lib/flash_n25q.c
|
||||
C_SRCS += $(COMMON_DIR)/lib/spi.c
|
||||
|
||||
LINKER_SCRIPT := $(COMMON_DIR)/link.lds
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _TRAP_CODE_H_
|
||||
#define _TRAP_CODE_H_
|
||||
|
||||
#define TRAP_USER_SW (0x80000000)
|
||||
#define TRAP_MACH_SW (0x80000003)
|
||||
#define TRAP_USER_TIMER (0x80000004)
|
||||
#define TRAP_MACH_TIMER (0x80000007)
|
||||
#define TRAP_USER_EXT (0x80000008)
|
||||
#define TRAP_MACH_EXT (0x8000000B)
|
||||
#define TRAP_INST_ADDR_MISA (0x00000000)
|
||||
#define TRAP_ILLEGAL_INST (0x00000002)
|
||||
#define TRAP_BREAKPOINT (0x00000003)
|
||||
#define TRAP_LOAD_ADDR_MISA (0x00000004)
|
||||
#define TRAP_STORE_ADDR_MISA (0x00000006)
|
||||
#define TRAP_ECALL_U (0x00000008)
|
||||
#define TRAP_ECALL_S (0x00000009)
|
||||
#define TRAP_ECALL_M (0x0000000B)
|
||||
|
||||
#endif
|
|
@ -2,3 +2,5 @@
|
|||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
|
@ -4,7 +4,7 @@ ENTRY(_start)
|
|||
|
||||
MEMORY
|
||||
{
|
||||
flash (wxa!ri) : ORIGIN = 0x00000000, LENGTH = 16K
|
||||
flash (wxa!ri) : ORIGIN = 0x00000000, LENGTH = 32K
|
||||
ram (wxa!ri) : ORIGIN = 0x10000000, LENGTH = 16K
|
||||
}
|
||||
|
|
@ -50,10 +50,11 @@ test_if_asynchronous:
|
|||
srli a2, a0, 31 /* MSB of mcause is 1 if handing an asynchronous interrupt - shift to LSB to clear other bits. */
|
||||
beq a2, x0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */
|
||||
|
||||
call trap_handler
|
||||
call interrupt_handler
|
||||
j asynchronous_return
|
||||
|
||||
handle_synchronous:
|
||||
call exception_handler
|
||||
addi a1, a1, 4
|
||||
csrw mepc, a1
|
||||
|
||||
|
@ -97,7 +98,12 @@ asynchronous_return:
|
|||
mret
|
||||
|
||||
|
||||
.weak trap_handler
|
||||
trap_handler:
|
||||
.weak interrupt_handler
|
||||
interrupt_handler:
|
||||
1:
|
||||
j 1b
|
||||
|
||||
.weak exception_handler
|
||||
exception_handler:
|
||||
2:
|
||||
j 2b
|
|
@ -0,0 +1,18 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "./include/trap_code.h"
|
||||
|
||||
extern void timer0_irq_handler() __attribute__((weak));
|
||||
|
||||
|
||||
void interrupt_handler(uint32_t mcause, uint32_t mepc)
|
||||
{
|
||||
// we have only timer0 interrupt here
|
||||
timer0_irq_handler();
|
||||
}
|
||||
|
||||
void exception_handler(uint32_t mcause, uint32_t mepc)
|
||||
{
|
||||
if ((mcause != TRAP_BREAKPOINT) && (mcause != TRAP_ECALL_M))
|
||||
while (1);
|
||||
}
|
|
@ -2,6 +2,6 @@
|
|||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
simple.bin
|
||||
simple.dump
|
||||
simple
|
||||
*.bin
|
||||
*.dump
|
||||
freertos
|
|
@ -11,7 +11,7 @@ TARGET = freertos
|
|||
CFLAGS += -Os
|
||||
ASM_SRCS := ../../Source/portable/RISC-V/portASM.S
|
||||
#LDFLAGS +=
|
||||
INCLUDES += -I. -I../../Source/portable/RISC-V -I../../Source/include -I../../../
|
||||
INCLUDES += -I. -I../../Source/portable/RISC-V -I../../Source/include -I../../../../bsp
|
||||
|
||||
C_SRCS := \
|
||||
main.c \
|
||||
|
@ -23,6 +23,6 @@ C_SRCS := \
|
|||
../../Source/portable/RISC-V/port.c \
|
||||
|
||||
|
||||
COMMON_DIR = ../../..
|
||||
COMMON_DIR = ../../../../bsp
|
||||
TOOLCHAIN_DIR = ../../../../..
|
||||
include ../../../common.mk
|
||||
include ../../../../bsp/common.mk
|
|
@ -0,0 +1,6 @@
|
|||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
|
@ -0,0 +1,6 @@
|
|||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.bin
|
||||
*.dump
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue