Compare commits

...

189 Commits

Author SHA1 Message Date
liangkangnan 280a548e62 sdk:examples: update gpio
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-18 15:13:25 +08:00
liangkangnan 6942faa82d sdk:examples: update led_toggle
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-18 14:54:54 +08:00
liangkangnan 5745f0140d fpga:xilinx:cmod_a7:constrs: leds and spi use same pin
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-18 14:52:56 +08:00
liangkangnan 47b744a7ec tools:bootrom: enable qspi mode
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-04 11:11:39 +08:00
liangkangnan d65cdee729 rtl:perips:bootrom: enable qspi mode
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-04 11:10:28 +08:00
liangkangnan 574474acc8 rtl:perips:xip: add qspi mode support
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-04 11:09:10 +08:00
liangkangnan e379fdd445 fpga:doc: add cmod_a7 sch
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-04 11:07:03 +08:00
liangkangnan 5dd0fa4034 sdk: update flash_ctrl
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-03 10:36:04 +08:00
liangkangnan b61fd21057 tools: remove flash_loader
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:53:20 +08:00
liangkangnan 6d37b9fc9c rtl:perips: remove flash_ctrl module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:50:29 +08:00
liangkangnan ad3dbd1a51 rtl:core: add bootrom and xip module address
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:32:56 +08:00
liangkangnan 6c6f6cf7af tools:openocd: add flash band for tinyriscv
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:23:09 +08:00
liangkangnan da19d3ebe5 fpga:cmod_a7:top: add bootrom module and use xip instead of flash_ctrl module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:18:17 +08:00
liangkangnan 3eaa4cdc97 sim🔝 add bootrom module and use xip instead of flash_ctrl module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:16:07 +08:00
liangkangnan f704e47e4a rtl:perips: add bootrom and xip
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:11:40 +08:00
liangkangnan 6aa5f18429 tools: add bootrom
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:06:00 +08:00
liangkangnan 9aba174156 sdk🔗 change flash addr to 0x02000000
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 15:04:35 +08:00
liangkangnan b3cfa2dfa6 rtl: do not need request all the access period
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-04-01 14:12:59 +08:00
liangkangnan 1b296983eb tools: add debug_rom
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-03-30 20:36:56 +08:00
liangkangnan 09c0b531b0 sdk: use cmod_a7 for default board, its input clock = 12MHz
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-03-28 10:25:49 +08:00
liangkangnan d6a14415c9 rtl: optimized for instr fetch and mem access
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-03-28 10:19:07 +08:00
liangkangnan 7993b97612 rtl:utils: add async_fifo module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-03-23 20:47:51 +08:00
liangkangnan 8bfee71fd0 rtl:sys_bus: fix only select one master
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-03-21 17:54:36 +08:00
liangkangnan 36380133f4 regtool: update README
Signed-off-by: liangkangnan <liangkangnan@163.com>
2023-01-18 10:43:58 +08:00
liangkangnan 769f93c70a fpga: cmod_a7: add sch doc
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-10-10 09:03:42 +08:00
liangkangnan 384320c7b1 fpga: constrs: change for cmod_a7 extern board
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-10-10 09:02:45 +08:00
liangkangnan ccadad262f sdk: add support for gd25xx nor flash
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-10-10 09:00:03 +08:00
liangkangnan 26a221a132 sdk:examples:led_toggle: update
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-20 15:03:55 +08:00
liangkangnan 22407f4b1f sdk:examples: add led_toggle
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-20 15:00:17 +08:00
liangkangnan ed2644b66e fpga:README: update bin file download address
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-18 20:00:06 +08:00
liangkangnan 53ae450762 fpga: update README.md
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-18 09:17:40 +08:00
liangkangnan a27d949a5d tools:openocd: update to support cmsis_dap-v2 driver
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-17 10:22:17 +08:00
liangkangnan 490c52054b fpga: xilinx: cmod_a7: add bin.tcl and mcs.tcl
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-12 19:33:49 +08:00
liangkangnan 4c16dfb254 rtl: move top module into fpga dir
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-10 08:13:38 +08:00
liangkangnan 4958cb66c2 rtl: top: move out sim_jtag module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-06 14:32:56 +08:00
liangkangnan 504f836de5 sim: remote_bitbang: fix print when connected
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-08-05 09:53:16 +08:00
liangkangnan 3666009efc fpga: xilinx: add tcl scripts
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-05-07 17:55:56 +08:00
liangkangnan 5b7b657384 sim: add CFLAGS VL_DEBUG
Signed-off-by: liangkangnan <liangkangnan@163.com>
2022-01-05 17:30:29 +08:00
liangkangnan 92e89292b1 tests:isa: remove unused test case
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-12-20 15:04:55 +08:00
liangkangnan bed8ed965e sdk:bsp: add link script for flash
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-25 09:02:32 +08:00
liangkangnan 3120110be3 rtl:core: ifu support for boot from flash
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-25 09:00:09 +08:00
liangkangnan d67f1abab3 tools:openocd: update openocd_win.exe
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-18 19:27:38 +08:00
liangkangnan 4720d020e4 rtl:perips:flash_ctrl: fix read state
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-16 15:24:37 +08:00
liangkangnan cfc170f896 tools: add flash_loader
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-11 10:04:17 +08:00
liangkangnan 27dc2ed0c1 tools: update linux openocd
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-11 09:58:42 +08:00
liangkangnan 8f4c2cb7fe sdk:examples: add flash_ctrl
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-04 10:13:11 +08:00
liangkangnan e097662c62 sim🔝 print sim result optimized
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-03 11:51:19 +08:00
liangkangnan ecd4ecafc6 sdk:bsp:lib: clear sim result flags when start running
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-03 11:48:02 +08:00
liangkangnan 15928977e1 rtl:perips: add flash_ctrl module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-02 10:54:37 +08:00
liangkangnan 274b19363b rtl:perips:spi: fix ss delay ctrl by sw
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-01 09:55:10 +08:00
liangkangnan 1e510dab9d rtl: utils: add up_counter module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-01 09:52:46 +08:00
liangkangnan d8a7a67787 sdk:lib: add flash n25q
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-10-22 09:02:43 +08:00
liangkangnan 90d9349128 sdk:lib:spi: update fifo op
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-10-12 10:31:57 +08:00
liangkangnan 448f733f22 sdk:include:spi: add fifo reset
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-10-12 10:23:16 +08:00
liangkangnan b6d3b39f4d rtl:perips:spi: add fifo reset
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-10-12 10:22:02 +08:00
liangkangnan 04d4dd8dfa regtool: update README.md
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-10-12 10:16:32 +08:00
liangkangnan 0667139d7e sdk:examples: remove spi_master2
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-29 09:26:57 +08:00
liangkangnan 2d9aab4ecb sdk: add arg for multi perips
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-29 09:24:04 +08:00
liangkangnan 9a8637be12 sdk:examples: update spi_master
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-24 09:26:02 +08:00
liangkangnan 22e6866dea sdk:examples:spi_master: add quad fast read
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-23 09:45:48 +08:00
liangkangnan 75de08cfc8 sdk:examples: add spi_master
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-17 09:09:38 +08:00
liangkangnan 718e16a46d sdk:bsp: add spi
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-17 09:08:29 +08:00
liangkangnan 3903d9e7f4 rtl:pinmux: add more spi mux
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-17 09:06:47 +08:00
liangkangnan d40f39a091 sdk:examples: use pinmux to config IO
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-13 18:11:20 +08:00
liangkangnan 3b7fa13a73 fpga:constrs: reassign pins
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-10 09:59:34 +08:00
liangkangnan 22a038cc09 rtl🔝 add more perips
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-10 09:57:39 +08:00
liangkangnan 519ef32ae7 sdk: adapt to more perips
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-10 09:56:21 +08:00
liangkangnan 55f37e93fa rtl:perips:gpio: increase to 16 gpios
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-10 09:51:08 +08:00
liangkangnan 4086a2d863 rtl:perips: add pinmux
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-10 09:48:44 +08:00
liangkangnan 4d0f63ef86 sdk:examples: add int_preempt
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-07 09:46:09 +08:00
liangkangnan 57690b00bd rtl:perips: add spi master
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-06 10:01:56 +08:00
liangkangnan f74f2d8f5d rtl:utils:edge_detect: add DP parameter
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-01 14:14:36 +08:00
liangkangnan 574708bd89 rtl:utils:gen_buf: add handle for DP=0
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-01 14:12:21 +08:00
liangkangnan ae3ff5a211 rtl🚌 use gnt and rvalid signal
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-09-01 09:54:32 +08:00
liangkangnan f7231a2f15 sdk:examples: add i2c_slave
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-26 09:28:23 +08:00
liangkangnan 2c11873056 rtl:i2c: fix slave read error
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-26 09:25:18 +08:00
liangkangnan e708eb6d4d rtl:perips:i2c: add i2c slave
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-25 17:51:35 +08:00
liangkangnan 7e57d8db17 rtl:perips:rvic: bug fix
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-25 17:47:18 +08:00
liangkangnan 9905a7c3a2 sdk:bsp: add i2c0 slave api
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-20 14:17:01 +08:00
liangkangnan 08492931fc bsp:lib:sim_ctrl: add dump wave api
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-20 11:51:49 +08:00
liangkangnan 92e1e5a77a sim: add dump wave enable by softwave
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-20 11:50:21 +08:00
liangkangnan facd5d31f4 sdk:examples: add i2c_master
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-20 09:26:13 +08:00
liangkangnan 3f400f2fb8 tmp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-19 17:45:45 +08:00
liangkangnan 1218a1ef4b sdk: rename to timer0_irq_handler
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-19 10:22:18 +08:00
liangkangnan 4ac826a398 sdk:bsp: add i2c
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-19 09:45:40 +08:00
liangkangnan cd9e219d1b fpga:xilinx:constrs: add i2c pin
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-19 09:44:36 +08:00
liangkangnan 2afcba47ea rtl:perips: add i2c master
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-19 09:43:12 +08:00
liangkangnan 6143d9ee6a rtl:gpio: remove gpio.h
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-17 10:20:30 +08:00
liangkangnan 12467d1554 sdk:bsp: adapte to new rvic
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-14 14:05:08 +08:00
liangkangnan d4b670217a rtl:perips: rewrite rvic
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-14 14:03:47 +08:00
liangkangnan 477d9efc34 sdk:examples: adapte to new perips
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-13 10:07:13 +08:00
liangkangnan fdd953c0f0 sdk:bsp: update gpio
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-13 09:35:56 +08:00
liangkangnan 5fa659a084 rtl:perips: rewrite gpio
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-13 09:33:15 +08:00
liangkangnan 9387f56a33 sdk:examples: add uart_int
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-13 09:31:19 +08:00
liangkangnan aaa5684cc9 sdk:bsp: remove machine_timer
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-11 14:47:35 +08:00
liangkangnan 0437ff99da sdk: examples: remove machine_timer
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-10 11:30:08 +08:00
liangkangnan 79f83c1ad4 tmp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-10 11:26:46 +08:00
liangkangnan ad5adcb843 tmp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-10 11:09:53 +08:00
liangkangnan c4fe45ffaf sdk: examples: add timer
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-10 09:54:20 +08:00
liangkangnan 64041b4d2b rtl: perips: rewrite timer module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-10 09:47:37 +08:00
liangkangnan f6c8a046c7 tools:regtool: add README.md
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-07 15:26:12 +08:00
liangkangnan c178a8fbb2 tools: add regtool
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-07 15:07:44 +08:00
liangkangnan 72b982d133 sdk:lib: rewrite uart
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-07 14:30:29 +08:00
liangkangnan 58f180a92f rtl: perips: rewrite uart module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-08-07 14:28:46 +08:00
liangkangnan cba47c1f64 use none-vector interrupt mode
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-26 09:54:38 +08:00
liangkangnan 9e7653a96a sdk:bsp: adapt to rvic
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-22 09:40:26 +08:00
liangkangnan 3227fb1ffd rtl:perips: add rvic
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-22 09:36:04 +08:00
liangkangnan e9044a7efe tests:random_instruction: add .gitignore
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-12 19:46:00 +08:00
liangkangnan 5ebb41c477 tests/random_instruction: add README.md
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-12 19:29:40 +08:00
liangkangnan 8f3aa6bb2c tests: add random instruction
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-12 18:22:02 +08:00
liangkangnan ac245a5d6c tools: add riscv-torture
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-12 18:13:01 +08:00
liangkangnan 18de7f2e00 test: use csr_sstatus for test result
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-10 14:49:36 +08:00
liangkangnan fd2c981317 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-09 15:18:09 +08:00
liangkangnan 53e4263706 rtl: ifu optimization
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-03 15:09:13 +08:00
liangkangnan 34218536c1 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-07-01 09:46:56 +08:00
liangkangnan 3269041c0b rtl: add config for branch predictor
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-28 11:31:04 +08:00
liangkangnan 2db9e7dbb9 rtl: add sync_fifo module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-28 11:09:37 +08:00
liangkangnan 96d6976c44 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-19 16:33:50 +08:00
liangkangnan 5f56e8d0fb temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-18 20:04:46 +08:00
liangkangnan 4e99bd4f33 README: update
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-11 09:49:31 +08:00
liangkangnan 7196d33074 rtl: add static branch predict unit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-11 09:44:26 +08:00
liangkangnan e26dda807e README: update
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-08 19:35:29 +08:00
liangkangnan f9f78976fb rtl: core: optimize mem access
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-05 20:00:15 +08:00
liangkangnan 6121a21322 rtl: top: make jtag host highest priority
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-05 19:59:07 +08:00
liangkangnan 4436e0cc6a tools: update openocd for win
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-05 19:48:41 +08:00
liangkangnan b7b8572542 tb: add tests type macro
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-05 16:59:26 +08:00
liangkangnan d9a1f89fd2 tests: riscv-compliance: add support
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-05 16:02:02 +08:00
liangkangnan 6059c4c3a7 tests: isa: add support
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-05 15:11:33 +08:00
liangkangnan c847244c5b rtl: perips: fix machine timer
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-06-03 09:23:50 +08:00
liangkangnan 646bc96419 openocd: update
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-31 14:07:36 +08:00
liangkangnan 6d8015727e temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-31 10:27:01 +08:00
liangkangnan 247a5b6354 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-28 15:10:37 +08:00
liangkangnan cd9ac0adae debug: change dmi addr bits to 7
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-28 10:37:50 +08:00
liangkangnan fb461a6176 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-25 11:45:53 +08:00
liangkangnan c6163aaff1 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-25 09:41:00 +08:00
liangkangnan fd5413791d example: coremark: print tips after uart init
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-22 15:26:24 +08:00
liangkangnan 87849fbd35 README: update
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-21 17:08:46 +08:00
liangkangnan 5353371516 doc: add obi spec
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-21 17:06:39 +08:00
liangkangnan bffeebd0bf example:simple: add -g flag
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-21 17:05:56 +08:00
liangkangnan b98e1c5538 bsp: use self-build gcc
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-21 14:19:50 +08:00
liangkangnan af63e677d9 example: fix freertos
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-21 09:50:21 +08:00
liangkangnan 01c3159a83 use larger ram
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-21 09:43:34 +08:00
liangkangnan a67fba652d add mmcm module for xilinx fpga
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-20 11:05:39 +08:00
liangkangnan 5efa66ee64 debug: fix breakpoint
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-19 19:09:17 +08:00
liangkangnan c7a374acb8 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-19 16:09:39 +08:00
liangkangnan f08fd1b17e debug: fix step
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-19 15:35:11 +08:00
liangkangnan 6cd6532423 example: add uart loopback
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-17 16:56:52 +08:00
liangkangnan 136dc45a09 change core clock to 25MHZ
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-17 16:40:25 +08:00
liangkangnan 536d28ede3 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-17 10:22:04 +08:00
liangkangnan b0f4592322 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-15 14:52:30 +08:00
liangkangnan 6e466fbbf7 add perips
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-14 21:00:57 +08:00
liangkangnan 5811bdde13 debug: add hw breakpoint support
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-14 14:37:47 +08:00
liangkangnan b02b38bddc temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-11 16:21:58 +08:00
liangkangnan 36147d9391 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-11 10:35:36 +08:00
liangkangnan 4a4c08bc69 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-04 21:11:43 +08:00
liangkangnan 10d8d35a13 rtl: fix combilation loop
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-02 14:51:12 +08:00
liangkangnan 738fba1d6f temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-30 18:27:30 +08:00
liangkangnan 53865371ce temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-30 16:41:24 +08:00
liangkangnan dfa8bf490e bus: fix bug
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-30 08:59:10 +08:00
liangkangnan f9412fca3c temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-29 19:27:25 +08:00
liangkangnan 77812d60df temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-26 14:08:26 +08:00
liangkangnan 4da79b6046 debug: add sba module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-26 09:48:19 +08:00
liangkangnan 65a26842c4 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-25 19:34:21 +08:00
liangkangnan ec65381ba9 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-25 17:14:09 +08:00
liangkangnan 462cc4c786 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-13 19:49:09 +08:00
liangkangnan 05e2441d24 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-13 16:34:00 +08:00
liangkangnan 9ac1b31965 rtl: add reset module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-13 14:12:47 +08:00
liangkangnan 7803e89d68 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-13 11:10:06 +08:00
liangkangnan e53f681063 rtl: optimize csr regs
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-13 09:25:29 +08:00
liangkangnan bd2d372c66 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-12 19:18:35 +08:00
liangkangnan 16fa475ba7 rtl:perips: remove vld rdy signals
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-09 20:47:00 +08:00
liangkangnan ad775ef316 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-09 20:27:33 +08:00
liangkangnan f1f09584ee optimize ifu and lsu
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-09 20:22:34 +08:00
liangkangnan e3667e0ddd temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-04-01 11:29:00 +08:00
liangkangnan 9943d02600 temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-03-31 18:00:19 +08:00
liangkangnan c070f0b49d temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-03-31 15:25:22 +08:00
liangkangnan 9322b595bc tools: add openocd ex arrt
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-03-29 19:21:02 +08:00
Blue Liang e2c07ec19b temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-03-29 19:10:02 +08:00
Blue Liang b4b54d831b temp commit
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-03-29 18:22:52 +08:00
liangkangnan f23b545499 tools: BinToMem.py: use unix format
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-03-29 15:26:19 +08:00
Blue Liang 8214134b89 tmp commit, unstable
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-03-29 15:14:50 +08:00
liangkangnan 5c87fc09ef tb: add jtag testbench
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-12-06 20:07:06 +08:00
liangkangnan fdc776ab5e rtl: debug: support reset cmd
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-12-06 20:06:12 +08:00
liangkangnan f03f42fc9b rtl: add reset ctrl module
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-11-18 22:15:08 +08:00
liangkangnan ceddc1af24 test:example: move C examples to sdk directory
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-11-08 22:09:38 +08:00
liangkangnan 5c9f1a140e rtl: add mem access misaligned exception
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-11-08 22:08:03 +08:00
Blue Liang 60a4f7d6df rtl: add generate block name
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-10-26 17:01:04 +08:00
liangkangnan eb5647915a python scripts: remove verison
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-10-25 12:02:26 +08:00
liangkangnan 2b44f1e8f3 first release
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-10-23 21:26:18 +08:00
1016 changed files with 273606 additions and 256659 deletions

4
.gitignore vendored
View File

@ -2,5 +2,5 @@
*.o
*.ko
*.obj
tools/gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64
*.bin
*.dump

232
README.md
View File

@ -1,203 +1,143 @@
与本项目配套的设计文档[《从零开始写RISC-V处理器》](https://liangkangnan.gitee.io/2020/04/29/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E5%86%99RISC-V%E5%A4%84%E7%90%86%E5%99%A8/),目前已经更新完第三章硬件篇,开始更新软件篇。
# 1.概述
# 1.初衷
本分支是在bram分支的基础上进行改进的。
本开源项目的初衷是本人想入门RISC-V熟悉RISC-V的指令内容和汇编语法。
改进的地方主要有:
本人对RISC-V很感兴趣很看好RISC-V的发展前景觉得RISC-V就是CPU中的Linux。由于RISC-V是这两年才开始迅速发展的因此关于RISC-V的学习参考资料目前还很少特别是适合入门的资料因此学习起来进度很缓慢于是萌生了自己从零开始写RISC-V处理器核的想法。
1. 开发环境切换到Linux(Ubuntu18.04)系统下;
2. 仿真器使用verilator
3. 内部总线使用OBI总线(详细内容见doc/OBI-v1.0.pdf文档)
4. 增加指令trace功能
6. JTAG模块全面改进和优化支持3个硬件断点单步等功能支持gdb调试
7. 增加静态分支预测功能;
本人是一名FPGA小白为了快速入门、深入掌握RISC-V我开始了学习FPGA和verilog的&quot;艰难&quot;历程。我工作的内容是和嵌入式软件相关的平时根本不会接触到FPGA也不会用到RISC-V因此只能用业余时间来学习RISC-V。
# 2.使用方法
网上有不少关于RISC-V的开源项目但是大多都写得很&quot;高深&quot;对于我这种小白来说学习起来是非常吃力的不太适合入门。本项目目前的代码量非常少是很简单易懂的对于想入门RISC-V的同学来说是一个很好的参考希望能够吸引更多的同学参与到RISC-V的学习中来促进RISC-V的发展如果能起到抛砖引玉的作用的话那就更好了也许说是砖的话就有点夸大了但哪怕是起到一颗沙子的作用也就足矣。
## 2.1安装gcc工具链
# 2.介绍
下载gcc工具链([百度云链接](https://pan.baidu.com/s/1iRiZoPnt9M1upXsUkvLEfA)提取码yaib),使用下面的命令解压到/opt/riscv32目录下
本项目实现的是一个单核32位的小型RISC-V处理器核(tinyriscv)采用verilog语言编写。设计目标是对标ARM Cortex-M3系列处理器。tinyriscv有以下特点
```
sudo tar zxf tinyriscv-gcc-toolchain.tar.gz -C /
```
1. 支持RV32IM指令集通过RISC-V指令兼容性测试
3. 采用三级流水线,即取指,译码,执行;
4. 可以运行C语言程序
5. 支持JTAG可以通过openocd读写内存(在线更新程序)
6. 支持中断;
6. 支持总线;
7. 支持FreeRTOS
8. 支持通过串口更新程序;
9. 容易移植到任何FPGA平台(如果资源足够的话)
## 2.2下载代码
项目中的各目录说明
下载本项目verilator分支的代码
**rtl**该目录包含tinyriscv的所有verilog源码
```
git clone -b verilator https://gitee.com/liangkangnan/tinyriscv.git
```
**sim**该目录包含仿真批处理bat文件和脚本
## 2.3运行仿真
**tests**该目录包含测试程序源码其中example目录为C语言程序例程源码isa目录为RV32指令测试源码
打开终端进入到sim目录下执行以下的命令编译
**tools**该目录包含编译汇编和C语言程序所需GNU工具链和将二进制文件转成仿真所需的mem格式文件的工具BinToMem还有通过串口下载程序的脚本。BinToMem\_CLI.exe需要在cmd窗口下执行BinToMem\_GUI.exe提供图形界面双击即可运行
```
make recompile
```
**pic**:存放图片;
这个命令会重新编译整个rtl源码和sdk/examples/simple这个C语言例程。如果需要使用其他例程可以用PROG参数指定比如
**tb**该目录包含仿真的testbench文件
```
make PROG=/path/sdk/examples/hello_world/hello_world.mem recompile
```
**fpga**存放FPGA相关文件比如约束文件
执行以下命令运行仿真:
tinyriscv的整体框架如下
```
make run
```
![tinyriscv整体框架](./pic/arch.jpg)
![make_run](./pic/make_run.png)
tinyriscv目前外挂了6个外设每个外设的空间大小为256MB地址空间分配如下图所示
打开另一个终端进入到tools/openocd目录下运行openocd
<img src="./pic/addr_alloc.jpg" alt="地址空间分配" style="zoom:70%;" />
```
./openocd_linux -f ../../sim/remote_bitbang.cfg
```
# 3.CoreMark测试
![openocd](./pic/openocd.png)
目前tinyriscv在Xilinx Artix-7 35T FPGA平台(时钟50MHz)上运行CoreMark跑分程序的结果如下图所示
可以看到openocd已经连上了可以使用telnet或者gdb进行调试了。
![tinyriscv跑分](./pic/tinyriscv_coremark.png)
### 2.3.1使用telnet进行调试
可知tinyriscv的跑分成绩为2.4。此成绩是基于指令在rom存储和数据在ram存储的情况下得出的如果指令和数据都在ram的话跑分上3.0问题应该不大。
再打开另一个终端输入以下命令连接telnet
选了几款其他MCU的跑分结果如下图所示
```
telnet localhost 4444
```
![其他MCU跑分结果](./pic/other_coremark.png)
![telnet](./pic/telnet.png)
更多MCU的跑分结果可以到[coremark](https://www.eembc.org/coremark/scores.php)官网查询。
然后就可以使用各种命令进行调试了。下面介绍一些常用的命令:
# 4.如何使用
**halt**停住MCU进入调试模式
本项目运行在windows平台编译仿真工具使用的是iverilog和vpp波形查看工具使用的是gtkwave。
**resume**MCU从停住的地方继续执行退出调试模式
## 4.1安装环境
**reset**复位MCU复位之后就开始执行。通常在下载完程序后使用该命令来运行程序
在使用之前需要安装以下工具:
**reset halt**复位MCU然后停住MCU即MCU停在复位地址处
1. 安装iverilog工具
**bp 0x00000010 4 hw**打断点其中0x00000010是断点的地址4表示地址长度为4个字节hw表示硬件断点。tinyriscv只支持硬件断点。
可以在这里[http://bleyer.org/icarus/](http://bleyer.org/icarus/)下载安装过程中记得同意把iverilog添加到环境变量中当然也可以在安装完成后手动进行添加。安装完成后iverilog、vvp和gtkwave等工具也就安装好了。
**rbp 0x00000010**删除0x00000010地址处的断点
2. 安装GNU工具链
**bp**:查看所有断点信息;
可以通过百度网盘下载(链接: https://pan.baidu.com/s/1bYgslKxHMjtiZtIPsB2caQ 提取码: 9n3c),或者通过微云下载[https://share.weiyun.com/5bMOsu9](https://share.weiyun.com/5bMOsu9)下载完成后将压缩包解压到本项目的tools目录下。注意目录的层次结构解压后的工具路径应该如下所示
**step**:单步执行,每次执行一条指令;
`tinyriscv\tools\gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64\bin\riscv-none-embed-gcc`
**mww 0x00000010 0x1234**即memory write word往0x00000010地址处写入0x1234长度为4个字节
3. 安装make工具
**mdw 0x00000010 2**即memory display word从0x00000010地址处读取2个word
可以通过百度网盘下载(链接: https://pan.baidu.com/s/1nFaUIwv171PDXuF7TziDFg 提取码: 9ntc),或者通过微云下载[https://share.weiyun.com/59xtmWR](https://share.weiyun.com/59xtmWR)下载完成后直接解压然后将make所在的路径添加到环境变量里。
**reg sp**读取sp寄存器的值
4. 安装python3
**reg sp 0x10**往sp寄存器写入0x10
到[python官网](https://www.python.org/)下载win版本的python注意要下载python3版本的。网速慢的同学可以通过百度网盘下载(链接: https://pan.baidu.com/s/1gNC8L5dZTsN6E5TJD2rmnQ 提取码: 3b4t),或者通过微云下载[https://share.weiyun.com/XwzSQHND](https://share.weiyun.com/XwzSQHND)。安装完后将python添加到环境变量里
**load_image**加载image文件比如load_image filename address bin min_address max_length其中filename表示要加载的文件address表示要加载到哪个地址bin表示文件的类型min_address表示最小地址该值与address相同即可max_length表示文件的最大长度。目前使用这个命令来下载C语言程序
5. 下载代码
**verify_image**比如verify_image filename offset其中filename表示已经下载了的文件offset表示从哪个地址开始校验。使用这个命令来校验下载进去的程序是否正确。
使用git clone命令下载不要使用zip方式下载否则有些文件会有格式问题
**load_bin**如果觉得load_image命令的参数比较多可以使用load_bin命令比如load_bin bin_file 0x0 1表示将bin_file二进制文件下载到0x0地址处并且校验
`git clone https://gitee.com/liangkangnan/tinyriscv.git`
### 2.3.2使用gdb进行调试
## 4.2运行指令测试程序
除了使用telnet进行调试之外还可以使用gdb进行调试这也是大部分IDEeclipse等所使用的调试方式。
### 4.2.1 运行旧的指令测试程序
openocd连上之后打开另一个终端执行以下命令运行gdb
旧的指令测试程序属于比较早的指令兼容性测试方法虽然目前RISC-V官方已经不更新了但仍然是一个比较好的测试参考。
```
/opt/riscv32/bin/riscv32-unknown-elf-gdb ~/tinyriscv/sdk/examples/simple/simple
```
下面以add指令为例说明如何运行旧的指令测试程序。
接着,设置一下超时时间:
打开CMD窗口进入到sim目录执行以下命令
```
set remotetimeout 2000
```
```sim_new_nowave.bat ..\tests\isa\generated\rv32ui-p-add.bin inst.data```
连接openocd服务
如果运行成功的话就可以看到&quot;PASS&quot;的打印。其他指令使用方法类似。
```
target remote localhost:3333
```
![](./pic/test_output.png)
加载程序:
也可以一次性对所有指令进行测试,方法如下。
```
load
```
打开CMD窗口进入到sim目录下执行以下命令
之后就可以用gdb命令来调试了比如打印mul变量的值
`python .\test_all_isa.py`
```
print mul
```
### 4.2.2运行新的指令测试程序
![gdb](./pic/gdb.png)
新的指令兼容性([riscv-compliance](https://github.com/riscv/riscv-compliance))测试项相对于旧的指令兼容性测试项来说对指令的测试更加严谨可以精确到每一条指令的运行结果而且RISC-V官方一直在更新。
下面以add指令为例说明如何运行新的指令测试程序。
打开CMD窗口进入到sim/compliance_test目录执行以下命令
`python compliance_test.py ..\..\tests\riscv-compliance\build_generated\rv32i\I-ADD-01.elf.bin inst.data`
如果运行成功的话就可以看到&quot;PASS&quot;的打印。其他指令使用方法类似。
![new_test_output](./pic/new_test_output.png)
## 4.3运行C语言程序
C语言程序例程位于tests\example目录里。
下面以simple程序为例进行说明。
首先打开CMD窗口进入到tests\example\simple目录执行以下命令清除旧的目标文件
`make clean`
然后重新编译:
`make`
编译成功之后进入到sim目录执行以下命令开始测试
` .\sim_new_nowave.bat ..\tests\example\simple\simple.bin inst.data`
# 5.移植到FPGA
详细的移植方法请查看本项目下的fpga目录中的README.md文件。
# 6.未来计划
1. 写设计文档;
2. 优化资源和功耗(主要是译码和执行部分)
3. 支持硬件中断嵌套和快速实时中断;
4. ......
# 7.更新记录
2020-07-04支持通过UART烧写固件
2020-05-27增加新的指令兼容性(riscv-compliance)测试项。
2020-05-05支持spi master增加spi测试例程。
2020-04-25支持FreeRTOS(v10.3.1)。
2020-04-18适当添加代码注释优化中断管理模块。
2020-04-11增加CoreMark跑分例程和跑分成绩。
2020-04-05支持CSR指令。
2020-03-29重大更新主要更新如下
1. 支持RIB(RISC-V Internal Bus)总线;
2. 优化乘法代码节省了2/3的DSP资源
3. 优化除法代码解决了除法模块的BUG
4. 完善C语言例程、启动代码和链接脚本
5. 增加一次性对所有指令进行测试的脚本;
2020-03-08支持中断为此增加了timer模块来验证。
2020-03-01支持JTAG配合openocd可进行内存读写。JTAG文档参考[深入浅出RISC-V调试](https://liangkangnan.gitee.io/2020/03/21/深入浅出RISC-V调试/)。
2020-02-23支持在Xilinx Artix-7平台上运行。详见[tinyriscv_vivado](https://gitee.com/liangkangnan/tinyriscv_vivado)。
2020-01-13支持RV32M的除法指令。其C语言实现详见[div](https://gitee.com/liangkangnan/div)。
2020-01-02支持RV32M的乘法指令。
2019-12-06第一次发布。
# 8.其他
如有疑问或者建议,欢迎在下方评论、或者私信、或者发邮件(liangkangnan@163.com)给我24小时内必回复。
如果您热爱RISC-V或者对RISC-V感兴趣欢迎发邮件或者私信我我把您拉进群里面交流RISC-V相关的技术。
注意如果要用gdb进行调试则编译C程序时必须加上-g参数。

BIN
doc/OBI-v1.0.pdf Normal file

Binary file not shown.

Binary file not shown.

BIN
doc/riscv-debug-release.pdf Normal file

Binary file not shown.

BIN
doc/riscv-privileged.pdf Normal file

Binary file not shown.

BIN
doc/riscv-spec.pdf Normal file

Binary file not shown.

View File

@ -1,12 +1,12 @@
# 1.概述
介绍如何将tinyriscv移植到FPGA平台上和如何通过JTAG或者UART下载程序到FPGA。
介绍如何将tinyriscv移植到FPGA平台上和如何通过JTAG下载程序到FPGA。
1.软件xilinx vivado(以2018.1版本为例)开发环境。
2.FPGAxilinx Artix-7 35T。
3.调试器CMSIS-DAP或者DAPLink。
3.调试器CMSIS-DAP或者DAPLink要带JTAG功能
这里只是以Xilinx平台为例实际上可以移植到任何FPGA平台只要资源足够
@ -66,6 +66,8 @@
勾选上红色框里那两项然后点击Finish按钮。
最后还要添加顶层文件即fpga/xilinx/perf-v/tinyriscv_soc_top.sv文件。
至此RTL源文件添加完成。
## 2.3添加约束文件
@ -82,7 +84,7 @@
![](./images/add_src_6.png)
点击Add Files按钮选择tinyriscv项目里的FPGA/constrs/tinyriscv.xdc文件如下图所示
点击Add Files按钮选择tinyriscv项目里的fpga/xilinx/perf-v/constrs/tinyriscv.xdc文件如下图所示
![](./images/add_src_7.png)
@ -156,9 +158,9 @@
打开一个CMD窗口然后cd进入到tinyriscv项目的tools/openocd目录执行命令
`openocd.exe -f tinyriscv.cfg`
`openocd_win.exe -f tinyriscv_cmsisdap_jtag.cfg`
如果执行成功的话则会如下图所示:
如果执行成功的话则会如下图所示(由于项目一直在更新,图片上的信息可能会跟实际的不一致,以文字描述为准)
![openocd](./images/openocd.png)
@ -166,55 +168,29 @@
`telnet localhost 4444`
然后在这个CMD窗口下使用load_image命令将固件下载到FPGA这里以freertos.bin文件为例如下所示
然后在这个CMD窗口下使用load_bin命令将固件下载到FPGA的ROM里掉电会消失这里以freertos.bin文件为例如下所示
`load_image D:/gitee/open/tinyriscv/tests/example/FreeRTOS/Demo/tinyriscv_GCC/freertos.bin 0x0 bin 0x0 0x1000000`
`load_bin D:/gitee/open/tinyriscv/tests/example/FreeRTOS/Demo/tinyriscv_GCC/freertos.bin 0x0 1`
使用verify_image命令来校验是否下载成功如下所示
load_bin命令用法
`verify_image D:/gitee/open/tinyriscv/tests/example/FreeRTOS/Demo/tinyriscv_GCC/freertos.bin 0x0`
`load_bin file address verify[0|1]`
如果下载出错的话会有提示的,没有提示则说明下载成功。
file表示要下载的bin文件
address表示要下载的地址
verify表示是否检验1校验0不校验
最后执行以下命令让程序跑起来:
`resume 0`
或者
`reset`
或者短按一下开发板上的复位按键。
**注意每次下载程序前记得先执行halt命令停住CPU。**
## 3.2通过UART方式下载
通过UART方式下载前需要先使能UART debug模块。在约束文件里指定的uart_debug_en引脚当其输入为高电平时表示使能UART debug模块输入为低电平时表示关闭UART debug模块。
当使能了UART debug模块后就可以通过tools/tinyriscv_fw_downloader.py脚本来下载程序。
tinyriscv_fw_downloader.py脚本使用方法
`python tinyriscv_fw_downloader.py 串口号 bin文件`
打开CMD窗口进入到tools目录比如输入以下命令
![uart_debug](./images/uart_debug.png)
即可下载freertos.bin程序到软核里。下载完后先关闭UART debug模块然后按板子上的复位(rst)按键即可让程序跑起来。
# 4.Vivado仿真设置
如果要在vivado里进行RTL仿真的话还需要添加tb目录里的tinyriscv_soc_tb.v文件具体方法和添加RTL源文件类似只是在源文件类型里选择simulation sources如下图所示
![add_sim](./images/add_sim.png)
最后设置一下define.v文件的路径如下图所示
![defines](./images/defines.png)
最后还要指定inst.data文件的路径即修改tinyriscv_soc_tb.v文件里的下面这一行
```
// read mem data
initial begin
$readmemh ("F://yourpath/inst.data", tinyriscv_soc_top_0.u_rom._rom);
end
```
设置完成后即可进行RTL仿真。

View File

@ -1,81 +0,0 @@
# 时钟约束50MHz
set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports {clk}];
create_clock -add -name sys_clk_pin -period 20.00 -waveform {0 10} [get_ports {clk}];
# 时钟引脚
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN N14 [get_ports clk]
# 复位引脚
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property PACKAGE_PIN L13 [get_ports rst]
# 程序执行完毕指示引脚
set_property IOSTANDARD LVCMOS33 [get_ports over]
set_property PACKAGE_PIN M16 [get_ports over]
# 程序执行成功指示引脚
set_property IOSTANDARD LVCMOS33 [get_ports succ]
set_property PACKAGE_PIN N16 [get_ports succ]
# CPU停住指示引脚
set_property IOSTANDARD LVCMOS33 [get_ports halted_ind]
set_property PACKAGE_PIN P15 [get_ports halted_ind]
# 串口下载使能引脚
set_property IOSTANDARD LVCMOS33 [get_ports uart_debug_pin]
set_property PACKAGE_PIN K13 [get_ports uart_debug_pin]
# 串口发送引脚
set_property IOSTANDARD LVCMOS33 [get_ports uart_tx_pin]
set_property PACKAGE_PIN M6 [get_ports uart_tx_pin]
# 串口接收引脚
set_property IOSTANDARD LVCMOS33 [get_ports uart_rx_pin]
set_property PACKAGE_PIN N6 [get_ports uart_rx_pin]
# GPIO0引脚
set_property IOSTANDARD LVCMOS33 [get_ports {gpio[0]}]
set_property PACKAGE_PIN P16 [get_ports {gpio[0]}]
# GPIO1引脚
set_property IOSTANDARD LVCMOS33 [get_ports {gpio[1]}]
set_property PACKAGE_PIN T15 [get_ports {gpio[1]}]
# JTAG TCK引脚
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TCK]
set_property PACKAGE_PIN N11 [get_ports jtag_TCK]
#create_clock -name jtag_clk_pin -period 300 [get_ports {jtag_TCK}];
# JTAG TMS引脚
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TMS]
set_property PACKAGE_PIN N3 [get_ports jtag_TMS]
# JTAG TDI引脚
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TDI]
set_property PACKAGE_PIN N2 [get_ports jtag_TDI]
# JTAG TDO引脚
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TDO]
set_property PACKAGE_PIN M1 [get_ports jtag_TDO]
# SPI MISO引脚
set_property IOSTANDARD LVCMOS33 [get_ports spi_miso]
set_property PACKAGE_PIN P1 [get_ports spi_miso]
# SPI MOSI引脚
set_property IOSTANDARD LVCMOS33 [get_ports spi_mosi]
set_property PACKAGE_PIN N1 [get_ports spi_mosi]
# SPI SS引脚
set_property IOSTANDARD LVCMOS33 [get_ports spi_ss]
set_property PACKAGE_PIN M5 [get_ports spi_ss]
# SPI CLK引脚
set_property IOSTANDARD LVCMOS33 [get_ports spi_clk]
set_property PACKAGE_PIN N4 [get_ports spi_clk]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]

7
fpga/xilinx/cmod_a7/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
out/
.Xil/
*.log
*.html
*.xml

View File

@ -0,0 +1,30 @@
VIVADO_BASE := /home/ubuntu/Xilinx/Vivado/2018.1/bin
VIVADO := $(VIVADO_BASE)/vivado
VIVADOFLAGS := \
-nojournal -mode batch \
-source scripts/init.tcl
.PHONY: synth
synth:
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl
.PHONY: impl
impl:
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl
.PHONY: bit
bit:
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl -source scripts/bit.tcl -source scripts/report.tcl
.PHONY: bin
bin:
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl -source scripts/bit.tcl -source scripts/bin.tcl -source scripts/report.tcl
.PHONY: mcs
mcs:
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl -source scripts/bit.tcl -source scripts/mcs.tcl -source scripts/report.tcl
.PHONY: clean
clean::
rm -rf .Xil .ip_user_files *.log *.jou out usage_statistics_webtalk.xml usage_statistics_webtalk.html

View File

@ -0,0 +1,16 @@
本目录包含FPGA约束文件vivado tcl脚本和顶层文件。
```
constrs包含FPGA约束文件
scripts包含vivado tcl脚本
tinyriscv_soc_top.sv整个SOC的顶层文件
```
根据vivado的安装路径修改Makefile文件。
生成bit文件
`make bit`
即可在out目录下生成bit文件。

View File

@ -0,0 +1,85 @@
## 12 MHz Clock Signal
set_property -dict { PACKAGE_PIN L17 IOSTANDARD LVCMOS33 } [get_ports { clk_12m_i }]; #IO_L12P_T1_MRCC_14 Sch=gclk
create_clock -add -name sys_clk_pin -period 83.33 -waveform {0 41.66} [get_ports {clk_12m_i}]
## 复位引脚
set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports rst_ext_i]; #IO_L19P_T3_16 Sch=btn[1]
## CPU停住指示引脚
set_property -dict { PACKAGE_PIN A17 IOSTANDARD LVCMOS33 } [get_ports halted_ind_pin]; #IO_L12N_T1_MRCC_16 Sch=led[1]
## 串口引脚
# UART0 TX
set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports {io_pins[0]}]; #IO_L7N_T1_D10_14 Sch=uart_rxd_out
# UART0 RX
set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports {io_pins[3]}]; #IO_L7P_T1_D09_14 Sch=uart_txd_in
## I2C引脚(EEPROM)
# I2C0 SCL引脚
set_property -dict { PACKAGE_PIN L1 IOSTANDARD LVCMOS33 } [get_ports {io_pins[6]}]; #IO_L6N_T0_VREF_35 Sch=pio[13]
# I2C0 SDA引脚
set_property -dict { PACKAGE_PIN L2 IOSTANDARD LVCMOS33 } [get_ports {io_pins[8]}]; #IO_L5N_T0_AD13N_35 Sch=pio[14]
## DS18B20
set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports {io_pins[5]}]; #IO_L11P_T1_SRCC_16 Sch=pio[05]
## WS2812
set_property -dict { PACKAGE_PIN P1 IOSTANDARD LVCMOS33 } [get_ports {io_pins[4]}]; #IO_L19N_T3_VREF_35 Sch=pio[23]
## USER KEY
# KEY1
set_property -dict { PACKAGE_PIN U4 IOSTANDARD LVCMOS33 } [get_ports {io_pins[1]}]; #IO_L11P_T1_SRCC_34 Sch=pio[38]
# KEY2
set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports {io_pins[2]}]; #IO_L16N_T2_34 Sch=pio[39]
## ANI
# PWM_V
set_property -dict { PACKAGE_PIN M3 IOSTANDARD LVCMOS33 } [get_ports {io_pins[7]}]; #IO_L8N_T1_AD14N_35 Sch=pio[01]
# C_OUT
set_property -dict { PACKAGE_PIN L3 IOSTANDARD LVCMOS33 } [get_ports {io_pins[9]}]; #IO_L8P_T1_AD14P_35 Sch=pio[02]
## SPI/LED
# SS
set_property -dict { PACKAGE_PIN M1 IOSTANDARD LVCMOS33 } [get_ports {io_pins[11]}]; #IO_L9N_T1_DQS_AD7N_35 Sch=pio[17]
# DQ1
set_property -dict { PACKAGE_PIN N3 IOSTANDARD LVCMOS33 } [get_ports {io_pins[13]}]; #IO_L12P_T1_MRCC_35 Sch=pio[18]
# DQ2/LED7
set_property -dict { PACKAGE_PIN P3 IOSTANDARD LVCMOS33 } [get_ports {io_pins[14]}]; #IO_L12N_T1_MRCC_35 Sch=pio[19]
# DQ3/LED6
set_property -dict { PACKAGE_PIN M2 IOSTANDARD LVCMOS33 } [get_ports {io_pins[15]}]; #IO_L9P_T1_DQS_AD7P_35 Sch=pio[20]
# SCK/LED5
set_property -dict { PACKAGE_PIN N1 IOSTANDARD LVCMOS33 } [get_ports {io_pins[10]}]; #IO_L10N_T1_AD15N_35 Sch=pio[21]
# DQ0/LED4
set_property -dict { PACKAGE_PIN N2 IOSTANDARD LVCMOS33 } [get_ports {io_pins[12]}]; #IO_L10P_T1_AD15P_35 Sch=pio[22]
## QSPI Flash引脚(存放程序)
# CLK
set_property -dict { PACKAGE_PIN J1 IOSTANDARD LVCMOS33 } [get_ports flash_spi_clk_pin]; #IO_L3N_T0_DQS_AD5N_35 Sch=pio[11]
# SS
set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports flash_spi_ss_pin]; #IO_L6N_T0_VREF_16 Sch=pio[07]
# DQ0
set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports {flash_spi_dq_pin[0]}]; #IO_L5P_T0_AD13P_35 Sch=pio[12]
# DQ1
set_property -dict { PACKAGE_PIN B15 IOSTANDARD LVCMOS33 } [get_ports {flash_spi_dq_pin[1]}]; #IO_L11N_T1_SRCC_16 Sch=pio[08]
# DQ2
set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports {flash_spi_dq_pin[2]}]; #IO_L6P_T0_16 Sch=pio[09]
# DQ3
set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports {flash_spi_dq_pin[3]}]; #IO_L7P_T1_AD6P_35 Sch=pio[10]
## JTAG引脚
# JTAG TCK引脚
#set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets jtag_TCK_pin]
set_property -dict { PACKAGE_PIN W7 IOSTANDARD LVCMOS33 } [get_ports jtag_TCK_pin]; #IO_L13P_T2_MRCC_34 Sch=pio[46]
# JTAG TMS引脚
set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports jtag_TMS_pin]; #IO_L14P_T2_SRCC_34 Sch=pio[47]
# JTAG TDI引脚
set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports jtag_TDI_pin]; #IO_L14N_T2_SRCC_34 Sch=pio[48]
# JTAG TDO引脚
set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports jtag_TDO_pin]; #IO_L19P_T3_34 Sch=pio[45]
## Set unused pin pullnone
set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 6 [current_design]

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1 @@
write_cfgmem -format bin -size 4 -interface SPIx4 -loadbit {up 0x00000000 "out/tinyriscv_soc_top.bit" } -force -file "out/tinyriscv_soc_top.bin"

View File

@ -0,0 +1 @@
write_bitstream -force [file join $outdir "${top_module}.bit"]

View File

@ -0,0 +1,5 @@
opt_design
place_design
phys_opt_design
power_opt_design
route_design

View File

@ -0,0 +1,43 @@
set prj_name {tinyriscv}
set part_fpga {xc7a15tcpg236-1}
set top_module {tinyriscv_soc_top}
set scriptsdir ./scripts
set constrsdir ./constrs
set outdir ./out
set srcdir ../../../rtl
#
proc rec_glob { basedir pattern } {
set dirlist [glob -nocomplain -directory $basedir -type d *]
set findlist [glob -nocomplain -directory $basedir $pattern]
foreach dir $dirlist {
set reclist [rec_glob $dir $pattern]
set findlist [concat $findlist $reclist]
}
return $findlist
}
# ()
create_project -part $part_fpga -in_memory
# sources_1
if {[get_filesets -quiet sources_1] eq ""} {
create_fileset -srcset sources_1
}
set src_pkg_files [rec_glob $srcdir "*pkg.sv"]
set src_verilog_files [rec_glob $srcdir "*.sv"]
set src_all_files [concat $src_pkg_files $src_verilog_files]
# verilog
add_files -norecurse -fileset sources_1 $src_all_files
add_files -norecurse -fileset sources_1 ./tinyriscv_soc_top.sv
# constrs_1
if {[get_filesets -quiet constrs_1] eq ""} {
create_fileset -constrset constrs_1
}
#
add_files -norecurse -fileset constrs_1 [glob -directory $constrsdir {*.xdc}]
#
file mkdir $outdir

View File

@ -0,0 +1 @@
write_cfgmem -format mcs -size 4 -interface SPIx4 -loadbit {up 0x00000000 "out/tinyriscv_soc_top.bit" } -force -file "out/tinyriscv_soc_top.mcs"

View File

@ -0,0 +1,12 @@
set rptdir [file join $outdir report]
file mkdir $rptdir
set rptutil [file join $rptdir utilization.txt]
report_datasheet -file [file join $rptdir datasheet.txt]
report_utilization -hierarchical -file $rptutil
report_clock_utilization -file $rptutil -append
report_ram_utilization -file $rptutil -append -detail
report_timing_summary -file [file join $rptdir timing.txt] -max_paths 10
report_high_fanout_nets -file [file join $rptdir fanout.txt] -timing -load_types -max_nets 25
report_drc -file [file join $rptdir drc.txt]
report_io -file [file join $rptdir io.txt]
report_clocks -file [file join $rptdir clocks.txt]

View File

@ -0,0 +1 @@
synth_design -top $top_module

View File

@ -0,0 +1,668 @@
/*
Copyright 2022 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "../../../rtl/core/defines.sv"
`include "../../../rtl/debug/jtag_def.sv"
// tinyriscv soc顶层模块
module tinyriscv_soc_top #(
parameter bit TRACE_ENABLE = 1'b0,
parameter int GPIO_NUM = 16,
parameter int I2C_NUM = 2,
parameter int UART_NUM = 3,
parameter int SPI_NUM = 1
)(
input wire clk_12m_i, // 时钟引脚
input wire rst_ext_i, // 复位引脚,高电平有效
output wire halted_ind_pin, // jtag是否已经halt住CPU高电平有效
inout wire[GPIO_NUM-1:0] io_pins, // IO引脚1bit代表一个IO
output wire flash_spi_clk_pin, // flash spi clk引脚
output wire flash_spi_ss_pin, // flash spi ss引脚
inout wire [3:0] flash_spi_dq_pin, // flash spi dq引脚
input wire jtag_TCK_pin, // JTAG TCK引脚
input wire jtag_TMS_pin, // JTAG TMS引脚
input wire jtag_TDI_pin, // JTAG TDI引脚
output wire jtag_TDO_pin // JTAG TDO引脚
);
localparam int MASTERS = 3; // Number of master ports
localparam int SLAVES = 17; // Number of slave ports
// masters
localparam int JtagHost = 0;
localparam int CoreD = 1;
localparam int CoreI = 2;
// slaves
localparam int Rom = 0;
localparam int Ram = 1;
localparam int JtagDevice = 2;
localparam int Timer0 = 3;
localparam int Gpio = 4;
localparam int Uart0 = 5;
localparam int Rvic = 6;
localparam int I2c0 = 7;
localparam int Spi0 = 8;
localparam int Pinmux = 9;
localparam int Uart1 = 10;
localparam int Uart2 = 11;
localparam int I2c1 = 12;
localparam int Timer1 = 13;
localparam int Timer2 = 14;
localparam int Xip = 15;
localparam int Bootrom = 16;
wire master_req [MASTERS];
wire master_gnt [MASTERS];
wire master_rvalid [MASTERS];
wire [31:0] master_addr [MASTERS];
wire master_we [MASTERS];
wire [ 3:0] master_be [MASTERS];
wire [31:0] master_rdata [MASTERS];
wire [31:0] master_wdata [MASTERS];
wire slave_req [SLAVES];
wire slave_gnt [SLAVES];
wire slave_rvalid [SLAVES];
wire [31:0] slave_addr [SLAVES];
wire slave_we [SLAVES];
wire [ 3:0] slave_be [SLAVES];
wire [31:0] slave_rdata [SLAVES];
wire [31:0] slave_wdata [SLAVES];
wire [31:0] slave_addr_mask [SLAVES];
wire [31:0] slave_addr_base [SLAVES];
wire clk;
wire rst_ext_n;
wire ndmreset;
wire ndmreset_n;
wire debug_req;
wire core_halted;
reg[31:0] irq_src;
wire int_req;
wire[7:0] int_id;
wire timer0_irq;
wire timer1_irq;
wire timer2_irq;
wire uart0_irq;
wire uart1_irq;
wire uart2_irq;
wire gpio0_irq;
wire gpio1_irq;
wire i2c0_irq;
wire i2c1_irq;
wire spi0_irq;
wire gpio2_4_irq;
wire gpio5_7_irq;
wire gpio8_irq;
wire gpio9_irq;
wire gpio10_12_irq;
wire gpio13_15_irq;
wire[GPIO_NUM-1:0] gpio_data_in;
wire[GPIO_NUM-1:0] gpio_oe;
wire[GPIO_NUM-1:0] gpio_data_out;
wire[GPIO_NUM-1:0] io_data_in;
wire[GPIO_NUM-1:0] io_oe;
wire[GPIO_NUM-1:0] io_data_out;
wire[I2C_NUM-1:0] i2c_scl_in;
wire[I2C_NUM-1:0] i2c_scl_oe;
wire[I2C_NUM-1:0] i2c_scl_out;
wire[I2C_NUM-1:0] i2c_sda_in;
wire[I2C_NUM-1:0] i2c_sda_oe;
wire[I2C_NUM-1:0] i2c_sda_out;
wire[UART_NUM-1:0] uart_tx;
wire[UART_NUM-1:0] uart_rx;
wire[SPI_NUM-1:0] spi_clk_in;
wire[SPI_NUM-1:0] spi_clk_oe;
wire[SPI_NUM-1:0] spi_clk_out;
wire[SPI_NUM-1:0] spi_ss_in;
wire[SPI_NUM-1:0] spi_ss_oe;
wire[SPI_NUM-1:0] spi_ss_out;
wire[3:0] spi_dq_in[SPI_NUM-1:0];
wire[3:0] spi_dq_oe[SPI_NUM-1:0];
wire[3:0] spi_dq_out[SPI_NUM-1:0];
wire[31:0] core_instr_addr;
wire[31:0] core_data_addr;
wire[3:0] flash_spi_dq_in;
wire[3:0] flash_spi_dq_oe;
wire[3:0] flash_spi_dq_out;
// 中断源
always @ (*) begin
irq_src = 32'h0;
irq_src[ 0] = timer0_irq;
irq_src[ 1] = uart0_irq;
irq_src[ 2] = gpio0_irq;
irq_src[ 3] = gpio1_irq;
irq_src[ 4] = i2c0_irq;
irq_src[ 5] = spi0_irq;
irq_src[ 6] = gpio2_4_irq;
irq_src[ 7] = gpio5_7_irq;
irq_src[ 8] = gpio8_irq;
irq_src[ 9] = gpio9_irq;
irq_src[10] = gpio10_12_irq;
irq_src[11] = gpio13_15_irq;
irq_src[12] = uart1_irq;
irq_src[13] = uart2_irq;
irq_src[14] = i2c1_irq;
irq_src[15] = timer1_irq;
irq_src[16] = timer2_irq;
end
assign rst_ext_n = ~rst_ext_i;
assign halted_ind_pin = core_halted;
assign master_we[CoreI] = '0;
assign master_be[CoreI] = '0;
tinyriscv_core #(
.DEBUG_HALT_ADDR(`DEBUG_ADDR_BASE + `HaltAddress),
.DEBUG_EXCEPTION_ADDR(`DEBUG_ADDR_BASE + `ExceptionAddress),
.BranchPredictor(1'b1),
.TRACE_ENABLE(TRACE_ENABLE)
) u_tinyriscv_core (
.clk (clk),
.rst_n (ndmreset_n),
.instr_req_o (master_req[CoreI]),
.instr_gnt_i (master_gnt[CoreI]),
.instr_rvalid_i (master_rvalid[CoreI]),
.instr_addr_o (master_addr[CoreI]),
.instr_rdata_i (master_rdata[CoreI]),
.instr_err_i (1'b0),
.data_req_o (master_req[CoreD]),
.data_gnt_i (master_gnt[CoreD]),
.data_rvalid_i (master_rvalid[CoreD]),
.data_we_o (master_we[CoreD]),
.data_be_o (master_be[CoreD]),
.data_addr_o (master_addr[CoreD]),
.data_wdata_o (master_wdata[CoreD]),
.data_rdata_i (master_rdata[CoreD]),
.data_err_i (1'b0),
.int_req_i (int_req),
.int_id_i (int_id),
.debug_req_i (debug_req)
);
assign slave_addr_mask[Rom] = `ROM_ADDR_MASK;
assign slave_addr_base[Rom] = `ROM_ADDR_BASE;
// 1.指令存储器
rom #(
.DP(`ROM_DEPTH)
) u_rom (
.clk_i (clk),
.rst_ni (ndmreset_n),
.req_i (slave_req[Rom]),
.addr_i (slave_addr[Rom]),
.data_i (slave_wdata[Rom]),
.be_i (slave_be[Rom]),
.we_i (slave_we[Rom]),
.gnt_o (slave_gnt[Rom]),
.rvalid_o (slave_rvalid[Rom]),
.data_o (slave_rdata[Rom])
);
assign slave_addr_mask[Ram] = `RAM_ADDR_MASK;
assign slave_addr_base[Ram] = `RAM_ADDR_BASE;
// 2.数据存储器
ram #(
.DP(`RAM_DEPTH)
) u_ram (
.clk_i (clk),
.rst_ni (ndmreset_n),
.req_i (slave_req[Ram]),
.addr_i (slave_addr[Ram]),
.data_i (slave_wdata[Ram]),
.be_i (slave_be[Ram]),
.we_i (slave_we[Ram]),
.gnt_o (slave_gnt[Ram]),
.rvalid_o (slave_rvalid[Ram]),
.data_o (slave_rdata[Ram])
);
assign slave_addr_mask[Timer0] = `TIMER0_ADDR_MASK;
assign slave_addr_base[Timer0] = `TIMER0_ADDR_BASE;
// 3.定时器0模块
timer_top timer0(
.clk_i (clk),
.rst_ni (ndmreset_n),
.irq_o (timer0_irq),
.req_i (slave_req[Timer0]),
.we_i (slave_we[Timer0]),
.be_i (slave_be[Timer0]),
.addr_i (slave_addr[Timer0]),
.data_i (slave_wdata[Timer0]),
.gnt_o (slave_gnt[Timer0]),
.rvalid_o(slave_rvalid[Timer0]),
.data_o (slave_rdata[Timer0])
);
assign slave_addr_mask[Timer1] = `TIMER1_ADDR_MASK;
assign slave_addr_base[Timer1] = `TIMER1_ADDR_BASE;
// 4.定时器1模块
timer_top timer1(
.clk_i (clk),
.rst_ni (ndmreset_n),
.irq_o (timer1_irq),
.req_i (slave_req[Timer1]),
.we_i (slave_we[Timer1]),
.be_i (slave_be[Timer1]),
.addr_i (slave_addr[Timer1]),
.data_i (slave_wdata[Timer1]),
.gnt_o (slave_gnt[Timer1]),
.rvalid_o(slave_rvalid[Timer1]),
.data_o (slave_rdata[Timer1])
);
assign slave_addr_mask[Timer2] = `TIMER2_ADDR_MASK;
assign slave_addr_base[Timer2] = `TIMER2_ADDR_BASE;
// 5.定时器2模块
timer_top timer2(
.clk_i (clk),
.rst_ni (ndmreset_n),
.irq_o (timer2_irq),
.req_i (slave_req[Timer2]),
.we_i (slave_we[Timer2]),
.be_i (slave_be[Timer2]),
.addr_i (slave_addr[Timer2]),
.data_i (slave_wdata[Timer2]),
.gnt_o (slave_gnt[Timer2]),
.rvalid_o(slave_rvalid[Timer2]),
.data_o (slave_rdata[Timer2])
);
assign slave_addr_mask[Gpio] = `GPIO_ADDR_MASK;
assign slave_addr_base[Gpio] = `GPIO_ADDR_BASE;
// 6.GPIO模块
gpio_top #(
.GPIO_NUM(GPIO_NUM)
) u_gpio (
.clk_i (clk),
.rst_ni (ndmreset_n),
.gpio_oe_o (gpio_oe),
.gpio_data_o (gpio_data_out),
.gpio_data_i (gpio_data_in),
.irq_gpio0_o (gpio0_irq),
.irq_gpio1_o (gpio1_irq),
.irq_gpio2_4_o (gpio2_4_irq),
.irq_gpio5_7_o (gpio5_7_irq),
.irq_gpio8_o (gpio8_irq),
.irq_gpio9_o (gpio9_irq),
.irq_gpio10_12_o(gpio10_12_irq),
.irq_gpio13_15_o(gpio13_15_irq),
.req_i (slave_req[Gpio]),
.we_i (slave_we[Gpio]),
.be_i (slave_be[Gpio]),
.addr_i (slave_addr[Gpio]),
.data_i (slave_wdata[Gpio]),
.gnt_o (slave_gnt[Gpio]),
.rvalid_o (slave_rvalid[Gpio]),
.data_o (slave_rdata[Gpio])
);
assign slave_addr_mask[Uart0] = `UART0_ADDR_MASK;
assign slave_addr_base[Uart0] = `UART0_ADDR_BASE;
// 7.串口0模块
uart_top uart0 (
.clk_i (clk),
.rst_ni (ndmreset_n),
.rx_i (uart_rx[0]),
.tx_o (uart_tx[0]),
.irq_o (uart0_irq),
.req_i (slave_req[Uart0]),
.we_i (slave_we[Uart0]),
.be_i (slave_be[Uart0]),
.addr_i (slave_addr[Uart0]),
.data_i (slave_wdata[Uart0]),
.gnt_o (slave_gnt[Uart0]),
.rvalid_o (slave_rvalid[Uart0]),
.data_o (slave_rdata[Uart0])
);
assign slave_addr_mask[Uart1] = `UART1_ADDR_MASK;
assign slave_addr_base[Uart1] = `UART1_ADDR_BASE;
// 8.串口1模块
uart_top uart1 (
.clk_i (clk),
.rst_ni (ndmreset_n),
.rx_i (uart_rx[1]),
.tx_o (uart_tx[1]),
.irq_o (uart1_irq),
.req_i (slave_req[Uart1]),
.we_i (slave_we[Uart1]),
.be_i (slave_be[Uart1]),
.addr_i (slave_addr[Uart1]),
.data_i (slave_wdata[Uart1]),
.gnt_o (slave_gnt[Uart1]),
.rvalid_o (slave_rvalid[Uart1]),
.data_o (slave_rdata[Uart1])
);
assign slave_addr_mask[Uart2] = `UART2_ADDR_MASK;
assign slave_addr_base[Uart2] = `UART2_ADDR_BASE;
// 9.串口2模块
uart_top uart2 (
.clk_i (clk),
.rst_ni (ndmreset_n),
.rx_i (uart_rx[2]),
.tx_o (uart_tx[2]),
.irq_o (uart2_irq),
.req_i (slave_req[Uart2]),
.we_i (slave_we[Uart2]),
.be_i (slave_be[Uart2]),
.addr_i (slave_addr[Uart2]),
.data_i (slave_wdata[Uart2]),
.gnt_o (slave_gnt[Uart2]),
.rvalid_o (slave_rvalid[Uart2]),
.data_o (slave_rdata[Uart2])
);
assign slave_addr_mask[Rvic] = `RVIC_ADDR_MASK;
assign slave_addr_base[Rvic] = `RVIC_ADDR_BASE;
// 10.中断控制器模块
rvic_top u_rvic(
.clk_i (clk),
.rst_ni (ndmreset_n),
.src_i (irq_src),
.irq_o (int_req),
.irq_id_o (int_id),
.req_i (slave_req[Rvic]),
.we_i (slave_we[Rvic]),
.be_i (slave_be[Rvic]),
.addr_i (slave_addr[Rvic]),
.data_i (slave_wdata[Rvic]),
.gnt_o (slave_gnt[Rvic]),
.rvalid_o (slave_rvalid[Rvic]),
.data_o (slave_rdata[Rvic])
);
assign slave_addr_mask[I2c0] = `I2C0_ADDR_MASK;
assign slave_addr_base[I2c0] = `I2C0_ADDR_BASE;
// 11.I2C0模块
i2c_top i2c0(
.clk_i (clk),
.rst_ni (ndmreset_n),
.scl_o (i2c_scl_out[0]),
.scl_oe_o (i2c_scl_oe[0]),
.scl_i (i2c_scl_in[0]),
.sda_o (i2c_sda_out[0]),
.sda_oe_o (i2c_sda_oe[0]),
.sda_i (i2c_sda_in[0]),
.irq_o (i2c0_irq),
.req_i (slave_req[I2c0]),
.we_i (slave_we[I2c0]),
.be_i (slave_be[I2c0]),
.addr_i (slave_addr[I2c0]),
.data_i (slave_wdata[I2c0]),
.gnt_o (slave_gnt[I2c0]),
.rvalid_o (slave_rvalid[I2c0]),
.data_o (slave_rdata[I2c0])
);
assign slave_addr_mask[I2c1] = `I2C1_ADDR_MASK;
assign slave_addr_base[I2c1] = `I2C1_ADDR_BASE;
// 12.I2C1模块
i2c_top i2c1(
.clk_i (clk),
.rst_ni (ndmreset_n),
.scl_o (i2c_scl_out[1]),
.scl_oe_o (i2c_scl_oe[1]),
.scl_i (i2c_scl_in[1]),
.sda_o (i2c_sda_out[1]),
.sda_oe_o (i2c_sda_oe[1]),
.sda_i (i2c_sda_in[1]),
.irq_o (i2c1_irq),
.req_i (slave_req[I2c1]),
.we_i (slave_we[I2c1]),
.be_i (slave_be[I2c1]),
.addr_i (slave_addr[I2c1]),
.data_i (slave_wdata[I2c1]),
.gnt_o (slave_gnt[I2c1]),
.rvalid_o (slave_rvalid[I2c1]),
.data_o (slave_rdata[I2c1])
);
assign slave_addr_mask[Spi0] = `SPI0_ADDR_MASK;
assign slave_addr_base[Spi0] = `SPI0_ADDR_BASE;
// 13.SPI0模块
spi_top spi0(
.clk_i (clk),
.rst_ni (ndmreset_n),
.spi_clk_i (spi_clk_in[0]),
.spi_clk_o (spi_clk_out[0]),
.spi_clk_oe_o(spi_clk_oe[0]),
.spi_ss_i (spi_ss_in[0]),
.spi_ss_o (spi_ss_out[0]),
.spi_ss_oe_o(spi_ss_oe[0]),
.spi_dq0_i (spi_dq_in[0][0]),
.spi_dq0_o (spi_dq_out[0][0]),
.spi_dq0_oe_o(spi_dq_oe[0][0]),
.spi_dq1_i (spi_dq_in[0][1]),
.spi_dq1_o (spi_dq_out[0][1]),
.spi_dq1_oe_o(spi_dq_oe[0][1]),
.spi_dq2_i (spi_dq_in[0][2]),
.spi_dq2_o (spi_dq_out[0][2]),
.spi_dq2_oe_o(spi_dq_oe[0][2]),
.spi_dq3_i (spi_dq_in[0][3]),
.spi_dq3_o (spi_dq_out[0][3]),
.spi_dq3_oe_o(spi_dq_oe[0][3]),
.irq_o (spi0_irq),
.req_i (slave_req[Spi0]),
.we_i (slave_we[Spi0]),
.be_i (slave_be[Spi0]),
.addr_i (slave_addr[Spi0]),
.data_i (slave_wdata[Spi0]),
.gnt_o (slave_gnt[Spi0]),
.rvalid_o (slave_rvalid[Spi0]),
.data_o (slave_rdata[Spi0])
);
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_io_data
assign io_pins[i] = io_oe[i] ? io_data_out[i] : 1'bz;
assign io_data_in[i] = io_pins[i];
end
assign slave_addr_mask[Pinmux] = `PINMUX_ADDR_MASK;
assign slave_addr_base[Pinmux] = `PINMUX_ADDR_BASE;
// 14.PINMUX模块
pinmux_top #(
.GPIO_NUM(GPIO_NUM),
.I2C_NUM(I2C_NUM),
.UART_NUM(UART_NUM),
.SPI_NUM(SPI_NUM)
) u_pinmux (
.clk_i (clk),
.rst_ni (ndmreset_n),
.gpio_oe_i (gpio_oe),
.gpio_val_i (gpio_data_out),
.gpio_val_o (gpio_data_in),
.i2c_sda_oe_i (i2c_sda_oe),
.i2c_sda_val_i (i2c_sda_out),
.i2c_sda_val_o (i2c_sda_in),
.i2c_scl_oe_i (i2c_scl_oe),
.i2c_scl_val_i (i2c_scl_out),
.i2c_scl_val_o (i2c_scl_in),
.uart_tx_oe_i ({UART_NUM{1'b1}}),
.uart_tx_val_i (uart_tx),
.uart_tx_val_o (),
.uart_rx_oe_i ({UART_NUM{1'b0}}),
.uart_rx_val_i (),
.uart_rx_val_o (uart_rx),
.spi_clk_oe_i (spi_clk_oe),
.spi_clk_val_i (spi_clk_out),
.spi_clk_val_o (spi_clk_in),
.spi_ss_oe_i (spi_ss_oe),
.spi_ss_val_i (spi_ss_out),
.spi_ss_val_o (spi_ss_in),
.spi_dq_oe_i (spi_dq_oe),
.spi_dq_val_i (spi_dq_out),
.spi_dq_val_o (spi_dq_in),
.io_val_i (io_data_in),
.io_val_o (io_data_out),
.io_oe_o (io_oe),
.req_i (slave_req[Pinmux]),
.we_i (slave_we[Pinmux]),
.be_i (slave_be[Pinmux]),
.addr_i (slave_addr[Pinmux]),
.data_i (slave_wdata[Pinmux]),
.gnt_o (slave_gnt[Pinmux]),
.rvalid_o (slave_rvalid[Pinmux]),
.data_o (slave_rdata[Pinmux])
);
for (genvar j = 0; j < 4; j = j + 1) begin : g_spi_pin_data
assign flash_spi_dq_pin[j] = flash_spi_dq_oe[j] ? flash_spi_dq_out[j] : 1'bz;
assign flash_spi_dq_in[j] = flash_spi_dq_pin[j];
end
assign slave_addr_mask[Xip] = `XIP_ADDR_MASK;
assign slave_addr_base[Xip] = `XIP_ADDR_BASE;
// 15.xip模块
xip_top xip (
.clk_i (clk),
.rst_ni (ndmreset_n),
.spi_clk_o (flash_spi_clk_pin),
.spi_clk_oe_o (),
.spi_ss_o (flash_spi_ss_pin),
.spi_ss_oe_o (),
.spi_dq0_i (flash_spi_dq_in[0]),
.spi_dq0_o (flash_spi_dq_out[0]),
.spi_dq0_oe_o (flash_spi_dq_oe[0]),
.spi_dq1_i (flash_spi_dq_in[1]),
.spi_dq1_o (flash_spi_dq_out[1]),
.spi_dq1_oe_o (flash_spi_dq_oe[1]),
.spi_dq2_i (flash_spi_dq_in[2]),
.spi_dq2_o (flash_spi_dq_out[2]),
.spi_dq2_oe_o (flash_spi_dq_oe[2]),
.spi_dq3_i (flash_spi_dq_in[3]),
.spi_dq3_o (flash_spi_dq_out[3]),
.spi_dq3_oe_o (flash_spi_dq_oe[3]),
.req_i (slave_req[Xip]),
.we_i (slave_we[Xip]),
.be_i (slave_be[Xip]),
.addr_i (slave_addr[Xip]),
.data_i (slave_wdata[Xip]),
.gnt_o (slave_gnt[Xip]),
.rvalid_o (slave_rvalid[Xip]),
.data_o (slave_rdata[Xip])
);
assign slave_addr_mask[Bootrom] = `BOOTROM_ADDR_MASK;
assign slave_addr_base[Bootrom] = `BOOTROM_ADDR_BASE;
// 16.bootrom模块
bootrom_top bootrom(
.clk_i (clk),
.rst_ni (ndmreset_n),
.req_i (slave_req[Bootrom]),
.we_i (slave_we[Bootrom]),
.be_i (slave_be[Bootrom]),
.addr_i (slave_addr[Bootrom]),
.data_i (slave_wdata[Bootrom]),
.gnt_o (slave_gnt[Bootrom]),
.rvalid_o(slave_rvalid[Bootrom]),
.data_o (slave_rdata[Bootrom])
);
// 内部总线
obi_interconnect #(
.MASTERS(MASTERS),
.SLAVES(SLAVES)
) bus (
.clk_i (clk),
.rst_ni (ndmreset_n),
.master_req_i (master_req),
.master_gnt_o (master_gnt),
.master_rvalid_o (master_rvalid),
.master_we_i (master_we),
.master_be_i (master_be),
.master_addr_i (master_addr),
.master_wdata_i (master_wdata),
.master_rdata_o (master_rdata),
.slave_addr_mask_i (slave_addr_mask),
.slave_addr_base_i (slave_addr_base),
.slave_req_o (slave_req),
.slave_gnt_i (slave_gnt),
.slave_rvalid_i (slave_rvalid),
.slave_we_o (slave_we),
.slave_be_o (slave_be),
.slave_addr_o (slave_addr),
.slave_wdata_o (slave_wdata),
.slave_rdata_i (slave_rdata)
);
assign clk = clk_12m_i;
// 复位信号产生
rst_gen #(
.RESET_FIFO_DEPTH(5)
) u_rst (
.clk (clk),
.rst_ni (rst_ext_n & (~ndmreset)),
.rst_no (ndmreset_n)
);
assign slave_addr_mask[JtagDevice] = `DEBUG_ADDR_MASK;
assign slave_addr_base[JtagDevice] = `DEBUG_ADDR_BASE;
// JTAG模块
jtag_top #(
) u_jtag (
.clk_i (clk),
.rst_ni (rst_ext_n),
.debug_req_o (debug_req),
.ndmreset_o (ndmreset),
.halted_o (core_halted),
.jtag_tck_i (jtag_TCK_pin),
.jtag_tdi_i (jtag_TDI_pin),
.jtag_tms_i (jtag_TMS_pin),
.jtag_trst_ni (rst_ext_n),
.jtag_tdo_o (jtag_TDO_pin),
.master_req_o (master_req[JtagHost]),
.master_gnt_i (master_gnt[JtagHost]),
.master_rvalid_i (master_rvalid[JtagHost]),
.master_we_o (master_we[JtagHost]),
.master_be_o (master_be[JtagHost]),
.master_addr_o (master_addr[JtagHost]),
.master_wdata_o (master_wdata[JtagHost]),
.master_rdata_i (master_rdata[JtagHost]),
.master_err_i (1'b0),
.slave_req_i (slave_req[JtagDevice]),
.slave_we_i (slave_we[JtagDevice]),
.slave_addr_i (slave_addr[JtagDevice]),
.slave_be_i (slave_be[JtagDevice]),
.slave_wdata_i (slave_wdata[JtagDevice]),
.slave_gnt_o (slave_gnt[JtagDevice]),
.slave_rvalid_o (slave_rvalid[JtagDevice]),
.slave_rdata_o (slave_rdata[JtagDevice])
);
endmodule

7
fpga/xilinx/perf-v/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
out/
.Xil/
*.log
*.html
*.xml

View File

@ -0,0 +1,22 @@
VIVADO_BASE := /home/ubuntu/Xilinx/Vivado/2018.1/bin
VIVADO := $(VIVADO_BASE)/vivado
VIVADOFLAGS := \
-nojournal -mode batch \
-source scripts/init.tcl
.PHONY: synth
synth:
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl
.PHONY: impl
impl:
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl
.PHONY: bit
bit:
$(VIVADO) $(VIVADOFLAGS) -source scripts/synth.tcl -source scripts/impl.tcl -source scripts/bit_stream.tcl -source scripts/report.tcl
.PHONY: clean
clean::
rm -rf .Xil .ip_user_files *.log *.jou out usage_statistics_webtalk.xml usage_statistics_webtalk.html

View File

@ -0,0 +1,16 @@
本目录包含FPGA约束文件vivado tcl脚本和顶层文件。
```
constrs包含FPGA约束文件
scripts包含vivado tcl脚本
tinyriscv_soc_top.sv整个SOC的顶层文件
```
根据vivado的安装路径修改Makefile文件。
生成bit文件
`make bit`
即可在out目录下生成bit文件。

View File

@ -0,0 +1,121 @@
# 时钟引脚
set_property IOSTANDARD LVCMOS33 [get_ports clk_50m_i]
set_property PACKAGE_PIN N14 [get_ports clk_50m_i]
# 时钟约束50MHz
create_clock -add -name SYS_CLK -period 20.00 [get_ports clk_50m_i]
# 复位引脚
set_property IOSTANDARD LVCMOS33 [get_ports rst_ext_ni]
set_property PACKAGE_PIN L13 [get_ports rst_ext_ni]
# CPU停住指示引脚
set_property IOSTANDARD LVCMOS33 [get_ports halted_ind_pin]
set_property PACKAGE_PIN P15 [get_ports halted_ind_pin]
# 串口发送引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[0]}]
set_property PACKAGE_PIN M6 [get_ports {io_pins[0]}]
# 串口接收引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[3]}]
set_property PACKAGE_PIN N6 [get_ports {io_pins[3]}]
# I2C0 SCL引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[6]}]
set_property PACKAGE_PIN R10 [get_ports {io_pins[6]}]
# I2C0 SDA引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[8]}]
set_property PACKAGE_PIN R11 [get_ports {io_pins[8]}]
# SPI DQ3引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[15]}]
set_property PACKAGE_PIN T14 [get_ports {io_pins[15]}]
# SPI DQ2引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[14]}]
set_property PACKAGE_PIN R16 [get_ports {io_pins[14]}]
# SPI DQ1引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[13]}]
set_property PACKAGE_PIN R15 [get_ports {io_pins[13]}]
# SPI DQ0引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[12]}]
set_property PACKAGE_PIN K13 [get_ports {io_pins[12]}]
# SPI SS引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[11]}]
set_property PACKAGE_PIN L14 [get_ports {io_pins[11]}]
# SPI CLK引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[10]}]
set_property PACKAGE_PIN M14 [get_ports {io_pins[10]}]
# GPIO0引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[7]}]
set_property PACKAGE_PIN P16 [get_ports {io_pins[7]}]
# GPIO1引脚
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[9]}]
set_property PACKAGE_PIN T15 [get_ports {io_pins[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[2]}]
set_property PACKAGE_PIN T13 [get_ports {io_pins[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[1]}]
set_property PACKAGE_PIN R13 [get_ports {io_pins[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[4]}]
set_property PACKAGE_PIN R7 [get_ports {io_pins[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {io_pins[5]}]
set_property PACKAGE_PIN R6 [get_ports {io_pins[5]}]
# SPI Flash引脚
# CLK
set_property IOSTANDARD LVCMOS33 [get_ports flash_spi_clk_pin]
set_property PACKAGE_PIN N4 [get_ports flash_spi_clk_pin]
# SS
set_property IOSTANDARD LVCMOS33 [get_ports flash_spi_ss_pin]
set_property PACKAGE_PIN M5 [get_ports flash_spi_ss_pin]
# DQ0
set_property IOSTANDARD LVCMOS33 [get_ports {flash_spi_dq_pin[0]}]
set_property PACKAGE_PIN N1 [get_ports {flash_spi_dq_pin[0]}]
# DQ1
set_property IOSTANDARD LVCMOS33 [get_ports {flash_spi_dq_pin[1]}]
set_property PACKAGE_PIN P1 [get_ports {flash_spi_dq_pin[1]}]
# DQ2
set_property IOSTANDARD LVCMOS33 [get_ports {flash_spi_dq_pin[2]}]
set_property PACKAGE_PIN P4 [get_ports {flash_spi_dq_pin[2]}]
# DQ3
set_property IOSTANDARD LVCMOS33 [get_ports {flash_spi_dq_pin[3]}]
set_property PACKAGE_PIN P3 [get_ports {flash_spi_dq_pin[3]}]
# JTAG TCK引脚
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TCK_pin]
set_property PACKAGE_PIN N11 [get_ports jtag_TCK_pin]
# 1MHZ
#create_clock -name JTAG_CLK -period 1000 [get_ports jtag_TCK_pin]
# JTAG TMS引脚
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TMS_pin]
set_property PACKAGE_PIN N3 [get_ports jtag_TMS_pin]
#set_input_delay -clock JTAG_CLK 500 [get_ports jtag_TMS_pin]
# JTAG TDI引脚
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TDI_pin]
set_property PACKAGE_PIN N2 [get_ports jtag_TDI_pin]
#set_input_delay -clock JTAG_CLK 500 [get_ports jtag_TDI_pin]
# JTAG TDO引脚
set_property IOSTANDARD LVCMOS33 [get_ports jtag_TDO_pin]
set_property PACKAGE_PIN M1 [get_ports jtag_TDO_pin]
#set_output_delay -clock JTAG_CLK 500 [get_ports jtag_TDO_pin]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]

View File

@ -0,0 +1,2 @@
write_bitstream -force [file join $outdir "${top_module}.bit"]

View File

@ -0,0 +1,8 @@
opt_design
place_design
phys_opt_design
power_opt_design
route_design

View File

@ -0,0 +1,62 @@
set prj_name {tinyriscv}
set part_fpga {xc7a35tftg256-1}
set top_module {tinyriscv_soc_top}
set scriptsdir ./scripts
set constrsdir ./constrs
set outdir ./out
set ipdir [file join $outdir ip]
set srcdir ../../../rtl
#
proc rec_glob { basedir pattern } {
set dirlist [glob -nocomplain -directory $basedir -type d *]
set findlist [glob -nocomplain -directory $basedir $pattern]
foreach dir $dirlist {
set reclist [rec_glob $dir $pattern]
set findlist [concat $findlist $reclist]
}
return $findlist
}
# ()
create_project -part $part_fpga -in_memory
# sources_1
if {[get_filesets -quiet sources_1] eq ""} {
create_fileset -srcset sources_1
}
set src_pkg_files [rec_glob $srcdir "*pkg.sv"]
set src_verilog_files [rec_glob $srcdir "*.sv"]
set src_all_files [concat $src_pkg_files $src_verilog_files]
# verilog
add_files -norecurse -fileset sources_1 $src_all_files
add_files -norecurse -fileset sources_1 ./tinyriscv_soc_top.sv
# constrs_1
if {[get_filesets -quiet constrs_1] eq ""} {
create_fileset -constrset constrs_1
}
#
add_files -norecurse -fileset constrs_1 [glob -directory $constrsdir {*.xdc}]
# IP
file mkdir $ipdir
update_ip_catalog -rebuild
source [file join $scriptsdir ip.tcl]
set_property GENERATE_SYNTH_CHECKPOINT {false} [get_files -all {*.xci}]
set obj [get_ips]
generate_target all $obj
export_ip_user_files -of_objects $obj -no_script -force
read_ip [glob -directory $ipdir [file join * {*.xci}]]
#
synth_design -top $top_module -include_dirs $ipdir
#set src_pkg_files [rec_glob $srcdir "*pkg.sv"]
#set src_verilog_files [rec_glob $srcdir "*.sv"]
#set src_all_files [concat $src_pkg_files $src_verilog_files]
#read_verilog -sv $src_all_files
#read_xdc ./constrs/tinyriscv.xdc

View File

@ -0,0 +1,9 @@
create_ip -name clk_wiz -vendor xilinx.com -library ip -module_name mmcm_main_clk -dir $ipdir -force
set_property -dict [list \
CONFIG.PRIM_IN_FREQ {50.000} \
CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {25.000} \
CONFIG.RESET_TYPE {ACTIVE_LOW} \
CONFIG.RESET_PORT {resetn}] \
[get_ips mmcm_main_clk]

View File

View File

@ -0,0 +1,13 @@
set rptdir [file join $outdir report]
file mkdir $rptdir
set rptutil [file join $rptdir utilization.txt]
report_datasheet -file [file join $rptdir datasheet.txt]
report_utilization -hierarchical -file $rptutil
report_clock_utilization -file $rptutil -append
report_ram_utilization -file $rptutil -append -detail
report_timing_summary -file [file join $rptdir timing.txt] -max_paths 10
report_high_fanout_nets -file [file join $rptdir fanout.txt] -timing -load_types -max_nets 25
report_drc -file [file join $rptdir drc.txt]
report_io -file [file join $rptdir io.txt]
report_clocks -file [file join $rptdir clocks.txt]

View File

@ -0,0 +1,52 @@
proc recglob { basedir pattern } {
set dirlist [glob -nocomplain -directory $basedir -type d *]
set findlist [glob -nocomplain -directory $basedir $pattern]
foreach dir $dirlist {
set reclist [recglob $dir $pattern]
set findlist [concat $findlist $reclist]
}
return $findlist
}
proc findincludedir { basedir pattern } {
#find all subdirectories containing ".vh" files
set vhfiles [recglob $basedir $pattern]
set vhdirs {}
foreach match $vhfiles {
lappend vhdirs [file dir $match]
}
set uniquevhdirs [lsort -unique $vhdirs]
return $uniquevhdirs
}
file mkdir $ipdir
source [file join $scriptsdir ip.tcl]
update_ip_catalog -rebuild
set obj [get_ips]
generate_target all $obj
read_ip [glob -directory $ipdir [file join * {*.xci}]]
# AR 58526 <http://www.xilinx.com/support/answers/58526.html>
set_property GENERATE_SYNTH_CHECKPOINT {false} [get_files -all {*.xci}]
set obj [get_ips]
generate_target all $obj
export_ip_user_files -of_objects $obj -no_script -force
set obj [current_fileset]
# Xilinx bug workaround
# scrape IP tree for directories containing .vh files
# [get_property include_dirs] misses all IP core subdirectory includes if user has specified -dir flag in create_ip
set property_include_dirs [get_property include_dirs $obj]
set ip_include_dirs [concat $property_include_dirs [findincludedir $ipdir "*.vh"]]
set ip_include_dirs [concat $ip_include_dirs [findincludedir $srcdir "*.h"]]
set ip_include_dirs [concat $ip_include_dirs [findincludedir $srcdir "*.vh"]]
synth_design -top $top_module -include_dirs $ipdir

View File

@ -0,0 +1,674 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "../../../rtl/core/defines.sv"
`include "../../../rtl/debug/jtag_def.sv"
// tinyriscv soc顶层模块
module tinyriscv_soc_top #(
parameter bit TRACE_ENABLE = 1'b0,
parameter int GPIO_NUM = 16,
parameter int I2C_NUM = 2,
parameter int UART_NUM = 3,
parameter int SPI_NUM = 1
)(
input wire clk_50m_i, // 时钟引脚
input wire rst_ext_ni, // 复位引脚,低电平有效
output wire halted_ind_pin, // jtag是否已经halt住CPU高电平有效
inout wire[GPIO_NUM-1:0] io_pins, // IO引脚1bit代表一个IO
output wire flash_spi_clk_pin, // flash spi clk引脚
output wire flash_spi_ss_pin, // flash spi ss引脚
inout wire [3:0] flash_spi_dq_pin, // flash spi dq引脚
input wire jtag_TCK_pin, // JTAG TCK引脚
input wire jtag_TMS_pin, // JTAG TMS引脚
input wire jtag_TDI_pin, // JTAG TDI引脚
output wire jtag_TDO_pin // JTAG TDO引脚
);
localparam int MASTERS = 3; // Number of master ports
localparam int SLAVES = 16; // Number of slave ports
// masters
localparam int JtagHost = 0;
localparam int CoreD = 1;
localparam int CoreI = 2;
// slaves
localparam int Rom = 0;
localparam int Ram = 1;
localparam int JtagDevice = 2;
localparam int Timer0 = 3;
localparam int Gpio = 4;
localparam int Uart0 = 5;
localparam int Rvic = 6;
localparam int I2c0 = 7;
localparam int Spi0 = 8;
localparam int Pinmux = 9;
localparam int Uart1 = 10;
localparam int Uart2 = 11;
localparam int I2c1 = 12;
localparam int Timer1 = 13;
localparam int Timer2 = 14;
localparam int FlashCtrl = 15;
wire master_req [MASTERS];
wire master_gnt [MASTERS];
wire master_rvalid [MASTERS];
wire [31:0] master_addr [MASTERS];
wire master_we [MASTERS];
wire [ 3:0] master_be [MASTERS];
wire [31:0] master_rdata [MASTERS];
wire [31:0] master_wdata [MASTERS];
wire slave_req [SLAVES];
wire slave_gnt [SLAVES];
wire slave_rvalid [SLAVES];
wire [31:0] slave_addr [SLAVES];
wire slave_we [SLAVES];
wire [ 3:0] slave_be [SLAVES];
wire [31:0] slave_rdata [SLAVES];
wire [31:0] slave_wdata [SLAVES];
wire [31:0] slave_addr_mask [SLAVES];
wire [31:0] slave_addr_base [SLAVES];
wire clk;
wire ndmreset;
wire ndmreset_n;
wire debug_req;
wire core_halted;
reg[31:0] irq_src;
wire int_req;
wire[7:0] int_id;
wire timer0_irq;
wire timer1_irq;
wire timer2_irq;
wire uart0_irq;
wire uart1_irq;
wire uart2_irq;
wire gpio0_irq;
wire gpio1_irq;
wire i2c0_irq;
wire i2c1_irq;
wire spi0_irq;
wire gpio2_4_irq;
wire gpio5_7_irq;
wire gpio8_irq;
wire gpio9_irq;
wire gpio10_12_irq;
wire gpio13_15_irq;
wire[GPIO_NUM-1:0] gpio_data_in;
wire[GPIO_NUM-1:0] gpio_oe;
wire[GPIO_NUM-1:0] gpio_data_out;
wire[GPIO_NUM-1:0] io_data_in;
wire[GPIO_NUM-1:0] io_oe;
wire[GPIO_NUM-1:0] io_data_out;
wire[I2C_NUM-1:0] i2c_scl_in;
wire[I2C_NUM-1:0] i2c_scl_oe;
wire[I2C_NUM-1:0] i2c_scl_out;
wire[I2C_NUM-1:0] i2c_sda_in;
wire[I2C_NUM-1:0] i2c_sda_oe;
wire[I2C_NUM-1:0] i2c_sda_out;
wire[UART_NUM-1:0] uart_tx;
wire[UART_NUM-1:0] uart_rx;
wire[SPI_NUM-1:0] spi_clk_in;
wire[SPI_NUM-1:0] spi_clk_oe;
wire[SPI_NUM-1:0] spi_clk_out;
wire[SPI_NUM-1:0] spi_ss_in;
wire[SPI_NUM-1:0] spi_ss_oe;
wire[SPI_NUM-1:0] spi_ss_out;
wire[3:0] spi_dq_in[SPI_NUM-1:0];
wire[3:0] spi_dq_oe[SPI_NUM-1:0];
wire[3:0] spi_dq_out[SPI_NUM-1:0];
wire[31:0] core_instr_addr;
wire[31:0] core_data_addr;
wire[3:0] flash_spi_dq_in;
wire[3:0] flash_spi_dq_oe;
wire[3:0] flash_spi_dq_out;
// 中断源
always @ (*) begin
irq_src = 32'h0;
irq_src[ 0] = timer0_irq;
irq_src[ 1] = uart0_irq;
irq_src[ 2] = gpio0_irq;
irq_src[ 3] = gpio1_irq;
irq_src[ 4] = i2c0_irq;
irq_src[ 5] = spi0_irq;
irq_src[ 6] = gpio2_4_irq;
irq_src[ 7] = gpio5_7_irq;
irq_src[ 8] = gpio8_irq;
irq_src[ 9] = gpio9_irq;
irq_src[10] = gpio10_12_irq;
irq_src[11] = gpio13_15_irq;
irq_src[12] = uart1_irq;
irq_src[13] = uart2_irq;
irq_src[14] = i2c1_irq;
irq_src[15] = timer1_irq;
irq_src[16] = timer2_irq;
end
// FPGA低电平点亮LED
assign halted_ind_pin = ~core_halted;
tinyriscv_core #(
.DEBUG_HALT_ADDR(`DEBUG_ADDR_BASE + `HaltAddress),
.DEBUG_EXCEPTION_ADDR(`DEBUG_ADDR_BASE + `ExceptionAddress),
.BranchPredictor(1'b1),
.TRACE_ENABLE(TRACE_ENABLE)
) u_tinyriscv_core (
.clk (clk),
.rst_n (ndmreset_n),
.instr_req_o (master_req[CoreI]),
.instr_gnt_i (master_gnt[CoreI]),
.instr_rvalid_i (master_rvalid[CoreI]),
.instr_addr_o (core_instr_addr),
.instr_rdata_i (master_rdata[CoreI]),
.instr_err_i (1'b0),
.data_req_o (master_req[CoreD]),
.data_gnt_i (master_gnt[CoreD]),
.data_rvalid_i (master_rvalid[CoreD]),
.data_we_o (master_we[CoreD]),
.data_be_o (master_be[CoreD]),
.data_addr_o (core_data_addr),
.data_wdata_o (master_wdata[CoreD]),
.data_rdata_i (master_rdata[CoreD]),
.data_err_i (1'b0),
.int_req_i (int_req),
.int_id_i (int_id),
.debug_req_i (debug_req)
);
// 是否访问flash
wire instr_access_flash;
wire data_access_flash;
assign instr_access_flash = ((core_instr_addr & (`FLASH_ADDR_MASK)) == `FLASH_ADDR_BASE);
assign data_access_flash = ((core_data_addr & (`FLASH_ADDR_MASK)) == `FLASH_ADDR_BASE);
// 转换后的地址
wire [31:0] instr_tran_addr;
wire [31:0] data_tran_addr;
assign instr_tran_addr = (core_instr_addr & (~(`FLASH_CTRL_ADDR_MASK))) | `FLASH_CTRL_ADDR_BASE;
assign data_tran_addr = (core_data_addr & (~(`FLASH_CTRL_ADDR_MASK))) | `FLASH_CTRL_ADDR_BASE;
// 当访问flash空间时转去访问flash ctrl模块
assign master_addr[CoreI] = instr_access_flash ? ({instr_tran_addr[31:24], 1'b1, instr_tran_addr[22:0]}) :
core_instr_addr;
assign master_addr[CoreD] = data_access_flash ? ({data_tran_addr[31:24], 1'b1, data_tran_addr[22:0]}) :
core_data_addr;
assign slave_addr_mask[Rom] = `ROM_ADDR_MASK;
assign slave_addr_base[Rom] = `ROM_ADDR_BASE;
// 1.指令存储器
rom #(
.DP(`ROM_DEPTH)
) u_rom (
.clk_i (clk),
.rst_ni (ndmreset_n),
.req_i (slave_req[Rom]),
.addr_i (slave_addr[Rom]),
.data_i (slave_wdata[Rom]),
.be_i (slave_be[Rom]),
.we_i (slave_we[Rom]),
.gnt_o (slave_gnt[Rom]),
.rvalid_o (slave_rvalid[Rom]),
.data_o (slave_rdata[Rom])
);
assign slave_addr_mask[Ram] = `RAM_ADDR_MASK;
assign slave_addr_base[Ram] = `RAM_ADDR_BASE;
// 2.数据存储器
ram #(
.DP(`RAM_DEPTH)
) u_ram (
.clk_i (clk),
.rst_ni (ndmreset_n),
.req_i (slave_req[Ram]),
.addr_i (slave_addr[Ram]),
.data_i (slave_wdata[Ram]),
.be_i (slave_be[Ram]),
.we_i (slave_we[Ram]),
.gnt_o (slave_gnt[Ram]),
.rvalid_o (slave_rvalid[Ram]),
.data_o (slave_rdata[Ram])
);
assign slave_addr_mask[Timer0] = `TIMER0_ADDR_MASK;
assign slave_addr_base[Timer0] = `TIMER0_ADDR_BASE;
// 3.定时器0模块
timer_top timer0(
.clk_i (clk),
.rst_ni (ndmreset_n),
.irq_o (timer0_irq),
.req_i (slave_req[Timer0]),
.we_i (slave_we[Timer0]),
.be_i (slave_be[Timer0]),
.addr_i (slave_addr[Timer0]),
.data_i (slave_wdata[Timer0]),
.gnt_o (slave_gnt[Timer0]),
.rvalid_o(slave_rvalid[Timer0]),
.data_o (slave_rdata[Timer0])
);
assign slave_addr_mask[Timer1] = `TIMER1_ADDR_MASK;
assign slave_addr_base[Timer1] = `TIMER1_ADDR_BASE;
// 4.定时器1模块
timer_top timer1(
.clk_i (clk),
.rst_ni (ndmreset_n),
.irq_o (timer1_irq),
.req_i (slave_req[Timer1]),
.we_i (slave_we[Timer1]),
.be_i (slave_be[Timer1]),
.addr_i (slave_addr[Timer1]),
.data_i (slave_wdata[Timer1]),
.gnt_o (slave_gnt[Timer1]),
.rvalid_o(slave_rvalid[Timer1]),
.data_o (slave_rdata[Timer1])
);
assign slave_addr_mask[Timer2] = `TIMER2_ADDR_MASK;
assign slave_addr_base[Timer2] = `TIMER2_ADDR_BASE;
// 5.定时器2模块
timer_top timer2(
.clk_i (clk),
.rst_ni (ndmreset_n),
.irq_o (timer2_irq),
.req_i (slave_req[Timer2]),
.we_i (slave_we[Timer2]),
.be_i (slave_be[Timer2]),
.addr_i (slave_addr[Timer2]),
.data_i (slave_wdata[Timer2]),
.gnt_o (slave_gnt[Timer2]),
.rvalid_o(slave_rvalid[Timer2]),
.data_o (slave_rdata[Timer2])
);
assign slave_addr_mask[Gpio] = `GPIO_ADDR_MASK;
assign slave_addr_base[Gpio] = `GPIO_ADDR_BASE;
// 6.GPIO模块
gpio_top #(
.GPIO_NUM(GPIO_NUM)
) u_gpio (
.clk_i (clk),
.rst_ni (ndmreset_n),
.gpio_oe_o (gpio_oe),
.gpio_data_o (gpio_data_out),
.gpio_data_i (gpio_data_in),
.irq_gpio0_o (gpio0_irq),
.irq_gpio1_o (gpio1_irq),
.irq_gpio2_4_o (gpio2_4_irq),
.irq_gpio5_7_o (gpio5_7_irq),
.irq_gpio8_o (gpio8_irq),
.irq_gpio9_o (gpio9_irq),
.irq_gpio10_12_o(gpio10_12_irq),
.irq_gpio13_15_o(gpio13_15_irq),
.req_i (slave_req[Gpio]),
.we_i (slave_we[Gpio]),
.be_i (slave_be[Gpio]),
.addr_i (slave_addr[Gpio]),
.data_i (slave_wdata[Gpio]),
.gnt_o (slave_gnt[Gpio]),
.rvalid_o (slave_rvalid[Gpio]),
.data_o (slave_rdata[Gpio])
);
assign slave_addr_mask[Uart0] = `UART0_ADDR_MASK;
assign slave_addr_base[Uart0] = `UART0_ADDR_BASE;
// 7.串口0模块
uart_top uart0 (
.clk_i (clk),
.rst_ni (ndmreset_n),
.rx_i (uart_rx[0]),
.tx_o (uart_tx[0]),
.irq_o (uart0_irq),
.req_i (slave_req[Uart0]),
.we_i (slave_we[Uart0]),
.be_i (slave_be[Uart0]),
.addr_i (slave_addr[Uart0]),
.data_i (slave_wdata[Uart0]),
.gnt_o (slave_gnt[Uart0]),
.rvalid_o (slave_rvalid[Uart0]),
.data_o (slave_rdata[Uart0])
);
assign slave_addr_mask[Uart1] = `UART1_ADDR_MASK;
assign slave_addr_base[Uart1] = `UART1_ADDR_BASE;
// 8.串口1模块
uart_top uart1 (
.clk_i (clk),
.rst_ni (ndmreset_n),
.rx_i (uart_rx[1]),
.tx_o (uart_tx[1]),
.irq_o (uart1_irq),
.req_i (slave_req[Uart1]),
.we_i (slave_we[Uart1]),
.be_i (slave_be[Uart1]),
.addr_i (slave_addr[Uart1]),
.data_i (slave_wdata[Uart1]),
.gnt_o (slave_gnt[Uart1]),
.rvalid_o (slave_rvalid[Uart1]),
.data_o (slave_rdata[Uart1])
);
assign slave_addr_mask[Uart2] = `UART2_ADDR_MASK;
assign slave_addr_base[Uart2] = `UART2_ADDR_BASE;
// 9.串口2模块
uart_top uart2 (
.clk_i (clk),
.rst_ni (ndmreset_n),
.rx_i (uart_rx[2]),
.tx_o (uart_tx[2]),
.irq_o (uart2_irq),
.req_i (slave_req[Uart2]),
.we_i (slave_we[Uart2]),
.be_i (slave_be[Uart2]),
.addr_i (slave_addr[Uart2]),
.data_i (slave_wdata[Uart2]),
.gnt_o (slave_gnt[Uart2]),
.rvalid_o (slave_rvalid[Uart2]),
.data_o (slave_rdata[Uart2])
);
assign slave_addr_mask[Rvic] = `RVIC_ADDR_MASK;
assign slave_addr_base[Rvic] = `RVIC_ADDR_BASE;
// 10.中断控制器模块
rvic_top u_rvic(
.clk_i (clk),
.rst_ni (ndmreset_n),
.src_i (irq_src),
.irq_o (int_req),
.irq_id_o (int_id),
.req_i (slave_req[Rvic]),
.we_i (slave_we[Rvic]),
.be_i (slave_be[Rvic]),
.addr_i (slave_addr[Rvic]),
.data_i (slave_wdata[Rvic]),
.gnt_o (slave_gnt[Rvic]),
.rvalid_o (slave_rvalid[Rvic]),
.data_o (slave_rdata[Rvic])
);
assign slave_addr_mask[I2c0] = `I2C0_ADDR_MASK;
assign slave_addr_base[I2c0] = `I2C0_ADDR_BASE;
// 11.I2C0模块
i2c_top i2c0(
.clk_i (clk),
.rst_ni (ndmreset_n),
.scl_o (i2c_scl_out[0]),
.scl_oe_o (i2c_scl_oe[0]),
.scl_i (i2c_scl_in[0]),
.sda_o (i2c_sda_out[0]),
.sda_oe_o (i2c_sda_oe[0]),
.sda_i (i2c_sda_in[0]),
.irq_o (i2c0_irq),
.req_i (slave_req[I2c0]),
.we_i (slave_we[I2c0]),
.be_i (slave_be[I2c0]),
.addr_i (slave_addr[I2c0]),
.data_i (slave_wdata[I2c0]),
.gnt_o (slave_gnt[I2c0]),
.rvalid_o (slave_rvalid[I2c0]),
.data_o (slave_rdata[I2c0])
);
assign slave_addr_mask[I2c1] = `I2C1_ADDR_MASK;
assign slave_addr_base[I2c1] = `I2C1_ADDR_BASE;
// 12.I2C1模块
i2c_top i2c1(
.clk_i (clk),
.rst_ni (ndmreset_n),
.scl_o (i2c_scl_out[1]),
.scl_oe_o (i2c_scl_oe[1]),
.scl_i (i2c_scl_in[1]),
.sda_o (i2c_sda_out[1]),
.sda_oe_o (i2c_sda_oe[1]),
.sda_i (i2c_sda_in[1]),
.irq_o (i2c1_irq),
.req_i (slave_req[I2c1]),
.we_i (slave_we[I2c1]),
.be_i (slave_be[I2c1]),
.addr_i (slave_addr[I2c1]),
.data_i (slave_wdata[I2c1]),
.gnt_o (slave_gnt[I2c1]),
.rvalid_o (slave_rvalid[I2c1]),
.data_o (slave_rdata[I2c1])
);
assign slave_addr_mask[Spi0] = `SPI0_ADDR_MASK;
assign slave_addr_base[Spi0] = `SPI0_ADDR_BASE;
// 13.SPI0模块
spi_top spi0(
.clk_i (clk),
.rst_ni (ndmreset_n),
.spi_clk_i (spi_clk_in[0]),
.spi_clk_o (spi_clk_out[0]),
.spi_clk_oe_o(spi_clk_oe[0]),
.spi_ss_i (spi_ss_in[0]),
.spi_ss_o (spi_ss_out[0]),
.spi_ss_oe_o(spi_ss_oe[0]),
.spi_dq0_i (spi_dq_in[0][0]),
.spi_dq0_o (spi_dq_out[0][0]),
.spi_dq0_oe_o(spi_dq_oe[0][0]),
.spi_dq1_i (spi_dq_in[0][1]),
.spi_dq1_o (spi_dq_out[0][1]),
.spi_dq1_oe_o(spi_dq_oe[0][1]),
.spi_dq2_i (spi_dq_in[0][2]),
.spi_dq2_o (spi_dq_out[0][2]),
.spi_dq2_oe_o(spi_dq_oe[0][2]),
.spi_dq3_i (spi_dq_in[0][3]),
.spi_dq3_o (spi_dq_out[0][3]),
.spi_dq3_oe_o(spi_dq_oe[0][3]),
.irq_o (spi0_irq),
.req_i (slave_req[Spi0]),
.we_i (slave_we[Spi0]),
.be_i (slave_be[Spi0]),
.addr_i (slave_addr[Spi0]),
.data_i (slave_wdata[Spi0]),
.gnt_o (slave_gnt[Spi0]),
.rvalid_o (slave_rvalid[Spi0]),
.data_o (slave_rdata[Spi0])
);
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_io_data
assign io_pins[i] = io_oe[i] ? io_data_out[i] : 1'bz;
assign io_data_in[i] = io_pins[i];
end
assign slave_addr_mask[Pinmux] = `PINMUX_ADDR_MASK;
assign slave_addr_base[Pinmux] = `PINMUX_ADDR_BASE;
// 14.PINMUX模块
pinmux_top #(
.GPIO_NUM(GPIO_NUM),
.I2C_NUM(I2C_NUM),
.UART_NUM(UART_NUM),
.SPI_NUM(SPI_NUM)
) u_pinmux (
.clk_i (clk),
.rst_ni (ndmreset_n),
.gpio_oe_i (gpio_oe),
.gpio_val_i (gpio_data_out),
.gpio_val_o (gpio_data_in),
.i2c_sda_oe_i (i2c_sda_oe),
.i2c_sda_val_i (i2c_sda_out),
.i2c_sda_val_o (i2c_sda_in),
.i2c_scl_oe_i (i2c_scl_oe),
.i2c_scl_val_i (i2c_scl_out),
.i2c_scl_val_o (i2c_scl_in),
.uart_tx_oe_i ({UART_NUM{1'b1}}),
.uart_tx_val_i (uart_tx),
.uart_tx_val_o (),
.uart_rx_oe_i ({UART_NUM{1'b0}}),
.uart_rx_val_i (),
.uart_rx_val_o (uart_rx),
.spi_clk_oe_i (spi_clk_oe),
.spi_clk_val_i (spi_clk_out),
.spi_clk_val_o (spi_clk_in),
.spi_ss_oe_i (spi_ss_oe),
.spi_ss_val_i (spi_ss_out),
.spi_ss_val_o (spi_ss_in),
.spi_dq_oe_i (spi_dq_oe),
.spi_dq_val_i (spi_dq_out),
.spi_dq_val_o (spi_dq_in),
.io_val_i (io_data_in),
.io_val_o (io_data_out),
.io_oe_o (io_oe),
.req_i (slave_req[Pinmux]),
.we_i (slave_we[Pinmux]),
.be_i (slave_be[Pinmux]),
.addr_i (slave_addr[Pinmux]),
.data_i (slave_wdata[Pinmux]),
.gnt_o (slave_gnt[Pinmux]),
.rvalid_o (slave_rvalid[Pinmux]),
.data_o (slave_rdata[Pinmux])
);
for (genvar j = 0; j < 4; j = j + 1) begin : g_spi_pin_data
assign flash_spi_dq_pin[j] = flash_spi_dq_oe[j] ? flash_spi_dq_out[j] : 1'bz;
assign flash_spi_dq_in[j] = flash_spi_dq_pin[j];
end
assign slave_addr_mask[FlashCtrl] = `FLASH_CTRL_ADDR_MASK;
assign slave_addr_base[FlashCtrl] = `FLASH_CTRL_ADDR_BASE;
// 15.flash ctrl模块
flash_ctrl_top flash_ctrl (
.clk_i (clk),
.rst_ni (ndmreset_n),
.spi_clk_o (flash_spi_clk_pin),
.spi_clk_oe_o (),
.spi_ss_o (flash_spi_ss_pin),
.spi_ss_oe_o (),
.spi_dq0_i (flash_spi_dq_in[0]),
.spi_dq0_o (flash_spi_dq_out[0]),
.spi_dq0_oe_o (flash_spi_dq_oe[0]),
.spi_dq1_i (flash_spi_dq_in[1]),
.spi_dq1_o (flash_spi_dq_out[1]),
.spi_dq1_oe_o (flash_spi_dq_oe[1]),
.spi_dq2_i (flash_spi_dq_in[2]),
.spi_dq2_o (flash_spi_dq_out[2]),
.spi_dq2_oe_o (flash_spi_dq_oe[2]),
.spi_dq3_i (flash_spi_dq_in[3]),
.spi_dq3_o (flash_spi_dq_out[3]),
.spi_dq3_oe_o (flash_spi_dq_oe[3]),
.req_i (slave_req[FlashCtrl]),
.we_i (slave_we[FlashCtrl]),
.be_i (slave_be[FlashCtrl]),
.addr_i (slave_addr[FlashCtrl]),
.data_i (slave_wdata[FlashCtrl]),
.gnt_o (slave_gnt[FlashCtrl]),
.rvalid_o (slave_rvalid[FlashCtrl]),
.data_o (slave_rdata[FlashCtrl])
);
// 内部总线
obi_interconnect #(
.MASTERS(MASTERS),
.SLAVES(SLAVES)
) bus (
.clk_i (clk),
.rst_ni (ndmreset_n),
.master_req_i (master_req),
.master_gnt_o (master_gnt),
.master_rvalid_o (master_rvalid),
.master_we_i (master_we),
.master_be_i (master_be),
.master_addr_i (master_addr),
.master_wdata_i (master_wdata),
.master_rdata_o (master_rdata),
.slave_addr_mask_i (slave_addr_mask),
.slave_addr_base_i (slave_addr_base),
.slave_req_o (slave_req),
.slave_gnt_i (slave_gnt),
.slave_rvalid_i (slave_rvalid),
.slave_we_o (slave_we),
.slave_be_o (slave_be),
.slave_addr_o (slave_addr),
.slave_wdata_o (slave_wdata),
.slave_rdata_i (slave_rdata)
);
// 使用xilinx vivado中的mmcm IP进行分频
// 输入为50MHZ输出为25MHZ
mmcm_main_clk u_mmcm_main_clk(
.clk_out1(clk),
.resetn(rst_ext_ni),
.clk_in1(clk_50m_i)
);
// 复位信号产生
rst_gen #(
.RESET_FIFO_DEPTH(5)
) u_rst (
.clk (clk),
.rst_ni (rst_ext_ni & (~ndmreset)),
.rst_no (ndmreset_n)
);
assign slave_addr_mask[JtagDevice] = `DEBUG_ADDR_MASK;
assign slave_addr_base[JtagDevice] = `DEBUG_ADDR_BASE;
// JTAG模块
jtag_top #(
) u_jtag (
.clk_i (clk),
.rst_ni (rst_ext_ni),
.debug_req_o (debug_req),
.ndmreset_o (ndmreset),
.halted_o (core_halted),
.jtag_tck_i (jtag_TCK_pin),
.jtag_tdi_i (jtag_TDI_pin),
.jtag_tms_i (jtag_TMS_pin),
.jtag_trst_ni (rst_ext_ni),
.jtag_tdo_o (jtag_TDO_pin),
.master_req_o (master_req[JtagHost]),
.master_gnt_i (master_gnt[JtagHost]),
.master_rvalid_i (master_rvalid[JtagHost]),
.master_we_o (master_we[JtagHost]),
.master_be_o (master_be[JtagHost]),
.master_addr_o (master_addr[JtagHost]),
.master_wdata_o (master_wdata[JtagHost]),
.master_rdata_i (master_rdata[JtagHost]),
.master_err_i (1'b0),
.slave_req_i (slave_req[JtagDevice]),
.slave_we_i (slave_we[JtagDevice]),
.slave_addr_i (slave_addr[JtagDevice]),
.slave_be_i (slave_be[JtagDevice]),
.slave_wdata_i (slave_wdata[JtagDevice]),
.slave_gnt_o (slave_gnt[JtagDevice]),
.slave_rvalid_o (slave_rvalid[JtagDevice]),
.slave_rdata_o (slave_rdata[JtagDevice])
);
endmodule

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

BIN
pic/gdb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
pic/make_run.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

BIN
pic/openocd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

BIN
pic/telnet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

94
rtl.flist Normal file
View File

@ -0,0 +1,94 @@
+incdir+../rtl/core
+incdir+../rtl/debug
../rtl/core/csr_reg.sv
../rtl/core/csr.sv
../rtl/core/defines.sv
../rtl/core/divider.sv
../rtl/core/exception.sv
../rtl/core/exu.sv
../rtl/core/exu_alu_datapath.sv
../rtl/core/exu_commit.sv
../rtl/core/exu_dispatch.sv
../rtl/core/exu_mem.sv
../rtl/core/exu_muldiv.sv
../rtl/core/gpr_reg.sv
../rtl/core/idu.sv
../rtl/core/idu_exu.sv
../rtl/core/ifu.sv
../rtl/core/ifu_idu.sv
../rtl/core/pipe_ctrl.sv
../rtl/core/rst_gen.sv
../rtl/core/tinyriscv_core.sv
../rtl/core/tracer.sv
../rtl/core/bpu.sv
../rtl/debug/jtag_def.sv
../rtl/debug/jtag_tap.sv
../rtl/debug/jtag_dtm.sv
../rtl/debug/jtag_dmi.sv
../rtl/debug/jtag_dm.sv
../rtl/debug/jtag_mem.sv
../rtl/debug/jtag_sba.sv
../rtl/debug/jtag_top.sv
../rtl/debug/debug_rom.sv
../rtl/perips/ram.sv
../rtl/perips/rom.sv
../rtl/perips/uart/uart_reg_pkg.sv
../rtl/perips/uart/uart_reg_top.sv
../rtl/perips/uart/uart_core.sv
../rtl/perips/uart/uart_rx.sv
../rtl/perips/uart/uart_top.sv
../rtl/perips/uart/uart_tx.sv
../rtl/perips/timer/timer_reg_pkg.sv
../rtl/perips/timer/timer_reg_top.sv
../rtl/perips/timer/timer_core.sv
../rtl/perips/timer/timer_top.sv
../rtl/perips/gpio/gpio_reg_pkg.sv
../rtl/perips/gpio/gpio_reg_top.sv
../rtl/perips/gpio/gpio_core.sv
../rtl/perips/gpio/gpio_top.sv
../rtl/perips/rvic/rvic_reg_pkg.sv
../rtl/perips/rvic/rvic_reg_top.sv
../rtl/perips/rvic/rvic_core.sv
../rtl/perips/rvic/rvic_top.sv
../rtl/perips/i2c/i2c_reg_pkg.sv
../rtl/perips/i2c/i2c_reg_top.sv
../rtl/perips/i2c/i2c_core.sv
../rtl/perips/i2c/i2c_top.sv
../rtl/perips/i2c/i2c_master.sv
../rtl/perips/i2c/i2c_slave.sv
../rtl/perips/spi/spi_reg_pkg.sv
../rtl/perips/spi/spi_reg_top.sv
../rtl/perips/spi/spi_core.sv
../rtl/perips/spi/spi_top.sv
../rtl/perips/spi/spi_master.sv
../rtl/perips/spi/spi_transmit_byte.sv
../rtl/perips/pinmux/pinmux_reg_pkg.sv
../rtl/perips/pinmux/pinmux_reg_top.sv
../rtl/perips/pinmux/pinmux_core.sv
../rtl/perips/pinmux/pinmux_top.sv
../rtl/perips/xip/xip_top.sv
../rtl/perips/xip/xip_core.sv
../rtl/perips/xip/xip_w25q64_ctrl.sv
../rtl/perips/xip/spi_master_transmit.sv
../rtl/perips/bootrom/bootrom_top.sv
../rtl/sys_bus/obi_interconnect.sv
../rtl/sys_bus/obi_interconnect_master_sel.sv
../rtl/sys_bus/obi_interconnect_slave_sel.sv
../rtl/utils/gen_buf.sv
../rtl/utils/gen_dff.sv
../rtl/utils/gen_ram.sv
../rtl/utils/cdc_2phase.sv
../rtl/utils/sync_fifo.sv
../rtl/utils/clk_div.sv
../rtl/utils/edge_detect.sv
../rtl/utils/prim_subreg.sv
../rtl/utils/prim_subreg_arb.sv
../rtl/utils/prim_subreg_ext.sv
../rtl/utils/prim_filter.sv
../rtl/utils/up_counter.sv
../rtl/utils/async_fifo.sv

62
rtl/core/bpu.sv Normal file
View File

@ -0,0 +1,62 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// 静态分支预测模块
module bpu(
input wire clk,
input wire rst_n,
input wire[31:0] inst_i,
input wire inst_valid_i,
input wire[31:0] pc_i,
output wire prdt_taken_o,
output wire[31:0] prdt_addr_o
);
wire[6:0] opcode = inst_i[6:0];
wire opcode_1100011 = (opcode == 7'b1100011);
wire opcode_1101111 = (opcode == 7'b1101111);
wire inst_type_branch = opcode_1100011;
wire inst_jal = opcode_1101111;
wire[31:0] inst_b_type_imm = {{20{inst_i[31]}}, inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0};
wire[31:0] inst_j_type_imm = {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};
wire prdt_taken = (inst_type_branch & inst_b_type_imm[31]) | inst_jal;
reg[31:0] prdt_imm;
always @ (*) begin
prdt_imm = inst_b_type_imm;
case (1'b1)
inst_type_branch: prdt_imm = inst_b_type_imm;
inst_jal: prdt_imm = inst_j_type_imm;
default: ;
endcase
end
assign prdt_taken_o = inst_valid_i ? prdt_taken : 1'b0;
assign prdt_addr_o = pc_i + prdt_imm;
endmodule

View File

@ -1,242 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.v"
// core local interruptor module
//
module clint(
input wire clk,
input wire rst,
// from core
input wire[`INT_BUS] int_flag_i, //
// from id
input wire[`InstBus] inst_i, //
input wire[`InstAddrBus] inst_addr_i, //
// from ex
input wire jump_flag_i,
input wire[`InstAddrBus] jump_addr_i,
input wire div_started_i,
// from ctrl
input wire[`Hold_Flag_Bus] hold_flag_i, // 线
// from csr_reg
input wire[`RegBus] data_i, // CSR
input wire[`RegBus] csr_mtvec, // mtvec
input wire[`RegBus] csr_mepc, // mepc
input wire[`RegBus] csr_mstatus, // mstatus
input wire global_int_en_i, // 使
// to ctrl
output wire hold_flag_o, // 线
// to csr_reg
output reg we_o, // CSR
output reg[`MemAddrBus] waddr_o, // CSR
output reg[`MemAddrBus] raddr_o, // CSR
output reg[`RegBus] data_o, // CSR
// to ex
output reg[`InstAddrBus] int_addr_o, //
output reg int_assert_o //
);
//
localparam S_INT_IDLE = 4'b0001;
localparam S_INT_SYNC_ASSERT = 4'b0010;
localparam S_INT_ASYNC_ASSERT = 4'b0100;
localparam S_INT_MRET = 4'b1000;
// CSR
localparam S_CSR_IDLE = 5'b00001;
localparam S_CSR_MSTATUS = 5'b00010;
localparam S_CSR_MEPC = 5'b00100;
localparam S_CSR_MSTATUS_MRET = 5'b01000;
localparam S_CSR_MCAUSE = 5'b10000;
reg[3:0] int_state;
reg[4:0] csr_state;
reg[`InstAddrBus] inst_addr;
reg[31:0] cause;
assign hold_flag_o = ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? `HoldEnable: `HoldDisable;
//
always @ (*) begin
if (rst == `RstEnable) begin
int_state = S_INT_IDLE;
end else begin
if (inst_i == `INST_ECALL || inst_i == `INST_EBREAK) begin
//
if (div_started_i == `DivStop) begin
int_state = S_INT_SYNC_ASSERT;
end else begin
int_state = S_INT_IDLE;
end
end else if (int_flag_i != `INT_NONE && global_int_en_i == `True) begin
int_state = S_INT_ASYNC_ASSERT;
end else if (inst_i == `INST_MRET) begin
int_state = S_INT_MRET;
end else begin
int_state = S_INT_IDLE;
end
end
end
// CSR
always @ (posedge clk) begin
if (rst == `RstEnable) begin
csr_state <= S_CSR_IDLE;
cause <= `ZeroWord;
inst_addr <= `ZeroWord;
end else begin
case (csr_state)
S_CSR_IDLE: begin
//
if (int_state == S_INT_SYNC_ASSERT) begin
csr_state <= S_CSR_MEPC;
// 4
if (jump_flag_i == `JumpEnable) begin
inst_addr <= jump_addr_i - 4'h4;
end else begin
inst_addr <= inst_addr_i;
end
case (inst_i)
`INST_ECALL: begin
cause <= 32'd11;
end
`INST_EBREAK: begin
cause <= 32'd3;
end
default: begin
cause <= 32'd10;
end
endcase
//
end else if (int_state == S_INT_ASYNC_ASSERT) begin
//
cause <= 32'h80000004;
csr_state <= S_CSR_MEPC;
if (jump_flag_i == `JumpEnable) begin
inst_addr <= jump_addr_i;
//
end else if (div_started_i == `DivStart) begin
inst_addr <= inst_addr_i - 4'h4;
end else begin
inst_addr <= inst_addr_i;
end
//
end else if (int_state == S_INT_MRET) begin
csr_state <= S_CSR_MSTATUS_MRET;
end
end
S_CSR_MEPC: begin
csr_state <= S_CSR_MSTATUS;
end
S_CSR_MSTATUS: begin
csr_state <= S_CSR_MCAUSE;
end
S_CSR_MCAUSE: begin
csr_state <= S_CSR_IDLE;
end
S_CSR_MSTATUS_MRET: begin
csr_state <= S_CSR_IDLE;
end
default: begin
csr_state <= S_CSR_IDLE;
end
endcase
end
end
// CSR
always @ (posedge clk) begin
if (rst == `RstEnable) begin
we_o <= `WriteDisable;
waddr_o <= `ZeroWord;
data_o <= `ZeroWord;
end else begin
case (csr_state)
// mepc
S_CSR_MEPC: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MEPC};
data_o <= inst_addr;
end
//
S_CSR_MCAUSE: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MCAUSE};
data_o <= cause;
end
//
S_CSR_MSTATUS: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MSTATUS};
data_o <= {csr_mstatus[31:4], 1'b0, csr_mstatus[2:0]};
end
//
S_CSR_MSTATUS_MRET: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MSTATUS};
data_o <= {csr_mstatus[31:4], csr_mstatus[7], csr_mstatus[2:0]};
end
default: begin
we_o <= `WriteDisable;
waddr_o <= `ZeroWord;
data_o <= `ZeroWord;
end
endcase
end
end
// ex
always @ (posedge clk) begin
if (rst == `RstEnable) begin
int_assert_o <= `INT_DEASSERT;
int_addr_o <= `ZeroWord;
end else begin
case (csr_state)
// .mcause
S_CSR_MCAUSE: begin
int_assert_o <= `INT_ASSERT;
int_addr_o <= csr_mtvec;
end
//
S_CSR_MSTATUS_MRET: begin
int_assert_o <= `INT_ASSERT;
int_addr_o <= csr_mepc;
end
default: begin
int_assert_o <= `INT_DEASSERT;
int_addr_o <= `ZeroWord;
end
endcase
end
end
endmodule

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,37 +14,30 @@
limitations under the License.
*/
`include "../core/defines.v"
// ram module
module ram(
module csr #(
parameter RESET_VAL = 32'h0,
parameter WIDTH = 32
)(
input wire clk,
input wire rst,
input wire rst_n,
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 [WIDTH-1:0] wdata_i,
input wire we_i,
output wire [WIDTH-1:0] rdata_o
);
reg[`MemBus] _ram[0:`MemNum - 1];
reg[WIDTH-1:0] rdata_q;
always @ (posedge clk) begin
if (we_i == `WriteEnable) begin
_ram[addr_i[31:2]] <= data_i;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
rdata_q <= RESET_VAL;
end else if (we_i) begin
rdata_q <= wdata_i;
end
end
always @ (*) begin
if (rst == `RstEnable) begin
data_o = `ZeroWord;
end else begin
data_o = _ram[addr_i[31:2]];
end
end
assign rdata_o = rdata_q;
endmodule

517
rtl/core/csr_reg.sv Normal file
View File

@ -0,0 +1,517 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// CSR寄存器模块
module csr_reg(
input wire clk,
input wire rst_n,
// from exu
input wire exu_we_i, // exu模块写寄存器标志
input wire[31:0] exu_waddr_i, // exu模块写寄存器地址
input wire[31:0] exu_wdata_i, // exu模块写寄存器数据
input wire[31:0] exu_raddr_i, // exu模块读寄存器地址
output wire[31:0] exu_rdata_o, // exu模块读寄存器数据
input wire[31:0] pc_if_i, // 取指地址
output wire trigger_match_o, // 断点
// form exception
input wire excep_we_i, // exception模块写寄存器标志
input wire[31:0] excep_waddr_i, // exception模块写寄存器地址
input wire[31:0] excep_wdata_i, // exception模块写寄存器数据
output wire[31:0] mtvec_o, // mtvec寄存器值
output wire[31:0] mepc_o, // mepc寄存器值
output wire[31:0] mstatus_o, // mstatus寄存器值
output wire[31:0] mie_o, // mie寄存器值
output wire[31:0] dpc_o, // dpc寄存器值
output wire[31:0] dcsr_o // dcsr寄存器值
);
// 硬件断点个数(必须大于等于1)
localparam HwBpNum = 3;
localparam DbgHwNumLen = HwBpNum > 1 ? $clog2(HwBpNum) : 1;
localparam MaxTselect = HwBpNum - 1;
wire[31:0] max_tselect = MaxTselect;
wire[31:0] misa = 32'h40001100; // 32bits, IM
// for verification result
reg[31:0] sstatus_d;
wire[31:0] sstatus_q;
reg sstatus_we;
reg[31:0] mtvec_d;
wire[31:0] mtvec_q;
reg mtvec_we;
reg[31:0] mcause_d;
wire[31:0] mcause_q;
reg mcause_we;
reg[31:0] mepc_d;
wire[31:0] mepc_q;
reg mepc_we;
reg[31:0] mie_d;
wire[31:0] mie_q;
reg mie_we;
reg[31:0] mstatus_d;
wire[31:0] mstatus_q;
reg mstatus_we;
reg[31:0] mscratch_d;
wire[31:0] mscratch_q;
reg mscratch_we;
reg[31:0] dscratch0_d;
wire[31:0] dscratch0_q;
reg dscratch0_we;
reg[31:0] dscratch1_d;
wire[31:0] dscratch1_q;
reg dscratch1_we;
reg[31:0] mhartid_d;
wire[31:0] mhartid_q;
reg mhartid_we;
reg[31:0] dpc_d;
wire[31:0] dpc_q;
reg dpc_we;
reg[31:0] dcsr_d;
wire[31:0] dcsr_q;
reg dcsr_we;
reg[31:0] tselect_d;
wire[31:0] tselect_q;
reg tselect_we;
wire tmatch_control_d;
wire[HwBpNum-1:0] tmatch_control_q;
wire[HwBpNum-1:0] tmatch_control_we;
wire[31:0] tmatch_value_d;
wire[31:0] tmatch_value_q[HwBpNum];
wire[HwBpNum-1:0] tmatch_value_we;
wire[HwBpNum-1:0] trigger_match;
wire[31:0] tmatch_control_rdata;
wire[31:0] tmatch_value_rdata;
wire selected_tmatch_control;
wire[31:0] selected_tmatch_value;
reg[63:0] cycle;
// cycle counter
// 复位撤销后就一直计数
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
cycle <= {32'h0, 32'h0};
end else begin
cycle <= cycle + 1'b1;
end
end
assign mtvec_o = mtvec_q;
assign mepc_o = mepc_q;
assign mstatus_o = mstatus_q;
assign mie_o = mie_q;
assign dpc_o = dpc_q;
assign dcsr_o = dcsr_q;
reg[31:0] exu_rdata;
// exu模块读CSR寄存器
always @ (*) begin
case (exu_raddr_i[11:0])
`CSR_CYCLE: begin
exu_rdata = cycle[31:0];
end
`CSR_CYCLEH: begin
exu_rdata = cycle[63:32];
end
`CSR_MTVEC: begin
exu_rdata = mtvec_q;
end
`CSR_MCAUSE: begin
exu_rdata = mcause_q;
end
`CSR_MEPC: begin
exu_rdata = mepc_q;
end
`CSR_MIE: begin
exu_rdata = mie_q;
end
`CSR_MSTATUS: begin
exu_rdata = mstatus_q;
end
`CSR_MSCRATCH: begin
exu_rdata = mscratch_q;
end
`CSR_DSCRATCH0: begin
exu_rdata = dscratch0_q;
end
`CSR_DSCRATCH1: begin
exu_rdata = dscratch1_q;
end
`CSR_MHARTID: begin
exu_rdata = mhartid_q;
end
`CSR_DPC: begin
exu_rdata = dpc_q;
end
`CSR_DCSR: begin
exu_rdata = dcsr_q;
end
`CSR_MISA: begin
exu_rdata = misa;
end
`CSR_TSELECT: begin
exu_rdata = tselect_q;
end
`CSR_TDATA1: begin
exu_rdata = tmatch_control_rdata;
end
`CSR_TDATA2: begin
exu_rdata = tmatch_value_rdata;
end
default: begin
exu_rdata = 32'h0;
end
endcase
end
assign exu_rdata_o = exu_rdata;
// 写CSR寄存器
wire we = exu_we_i | excep_we_i;
wire[31:0] waddr = exu_we_i? exu_waddr_i: excep_waddr_i;
wire[31:0] wdata = exu_we_i? exu_wdata_i: excep_wdata_i;
always @ (*) begin
mtvec_d = mtvec_q;
mtvec_we = 1'b0;
mcause_d = mcause_q;
mcause_we = 1'b0;
mepc_d = mepc_q;
mepc_we = 1'b0;
mie_d = mie_q;
mie_we = 1'b0;
mstatus_d = mstatus_q;
mstatus_we = 1'b0;
mscratch_d = mscratch_q;
mscratch_we = 1'b0;
dscratch0_d = dscratch0_q;
dscratch0_we = 1'b0;
dscratch1_d = dscratch1_q;
dscratch1_we = 1'b0;
mhartid_d = mhartid_q;
mhartid_we = 1'b0;
dpc_d = dpc_q;
dpc_we = 1'b0;
dcsr_d = dcsr_q;
dcsr_we = 1'b0;
sstatus_d = sstatus_q;
sstatus_we = 1'b0;
if (we) begin
case (waddr[11:0])
`CSR_MTVEC: begin
mtvec_d = wdata;
mtvec_we = 1'b1;
end
`CSR_MCAUSE: begin
mcause_d = wdata;
mcause_we = 1'b1;
end
`CSR_MEPC: begin
mepc_d = wdata;
mepc_we = 1'b1;
end
`CSR_MIE: begin
mie_d = wdata;
mie_we = 1'b1;
end
`CSR_MSTATUS: begin
mstatus_d = wdata;
mstatus_we = 1'b1;
end
`CSR_MSCRATCH: begin
mscratch_d = wdata;
mscratch_we = 1'b1;
end
`CSR_DSCRATCH0: begin
dscratch0_d = wdata;
dscratch0_we = 1'b1;
end
`CSR_DSCRATCH1: begin
dscratch1_d = wdata;
dscratch1_we = 1'b1;
end
`CSR_MHARTID: begin
mhartid_d = wdata;
mhartid_we = 1'b1;
end
`CSR_SSTATUS: begin
sstatus_d = wdata;
sstatus_we = 1'b1;
end
`CSR_DPC: begin
dpc_d = wdata;
dpc_we = 1'b1;
end
`CSR_DCSR: begin
// Not all bits in DCSR are writable by exu
if (exu_we_i) begin
dcsr_d = {dcsr_q[31:28], wdata[27:9], dcsr_q[8:6], wdata[5:4], dcsr_q[3], wdata[2:0]};
end else begin
dcsr_d = wdata;
end
dcsr_we = 1'b1;
end
default:;
endcase
end
end
// trigger control
assign tselect_we = (exu_waddr_i[11:0] == `CSR_TSELECT) & exu_we_i;
for (genvar i = 0; i < HwBpNum; i = i + 1) begin : dbg_tmatch_we
assign tmatch_control_we[i] = (i == tselect_q) &
exu_we_i &
(exu_waddr_i[11:0] == `CSR_TDATA1);
assign tmatch_value_we[i] = (i == tselect_q) &
exu_we_i &
(exu_waddr_i[11:0] == `CSR_TDATA2);
end
assign tselect_d = (exu_wdata_i < HwBpNum) ? exu_wdata_i : max_tselect;
assign tmatch_control_d = exu_wdata_i[2];
assign tmatch_value_d = exu_wdata_i;
if (HwBpNum > 1) begin : dbg_tmatch_multiple_select
assign selected_tmatch_control = tmatch_control_q[tselect_q];
assign selected_tmatch_value = tmatch_value_q[tselect_q];
end else begin : dbg_tmatch_single_select
assign selected_tmatch_control = tmatch_control_q[0];
assign selected_tmatch_value = tmatch_value_q[0];
end
// TDATA0 - only support simple address matching
assign tmatch_control_rdata = {4'h2, // type : address/data match
1'b1, // dmode : access from D mode only
6'h00, // maskmax : exact match only
1'b0, // hit : not supported
1'b0, // select : address match only
1'b0, // timing : match before execution
2'b00, // sizelo : match any access
4'h1, // action : enter debug mode
1'b0, // chain : not supported
4'h0, // match : simple match
1'b1, // m : match in m-mode
1'b0, // 0 : zero
1'b0, // s : not supported
1'b1, // u : match in u-mode
selected_tmatch_control, // execute : match instruction address
1'b0, // store : not supported
1'b0}; // load : not supported
// TDATA1 - address match value only
assign tmatch_value_rdata = selected_tmatch_value;
// Breakpoint matching
// We match against the next address, as the breakpoint must be taken before execution
for (genvar i = 0; i < HwBpNum; i = i + 1) begin : dbg_trigger_match
assign trigger_match[i] = tmatch_control_q[i] & (pc_if_i == tmatch_value_q[i]);
end
assign trigger_match_o = |trigger_match;
// mtvec
csr #(
.RESET_VAL(32'h0)
) mtvec_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(mtvec_d),
.we_i(mtvec_we),
.rdata_o(mtvec_q)
);
// mcause
csr #(
.RESET_VAL(32'h0)
) mcause_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(mcause_d),
.we_i(mcause_we),
.rdata_o(mcause_q)
);
// mepc
csr #(
.RESET_VAL(32'h0)
) mepc_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(mepc_d),
.we_i(mepc_we),
.rdata_o(mepc_q)
);
// mie
csr #(
.RESET_VAL(32'h0)
) mie_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(mie_d),
.we_i(mie_we),
.rdata_o(mie_q)
);
// mstatus
csr #(
.RESET_VAL(32'h0)
) mstatus_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(mstatus_d),
.we_i(mstatus_we),
.rdata_o(mstatus_q)
);
// mscratch
csr #(
.RESET_VAL(32'h0)
) mscratch_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(mscratch_d),
.we_i(mscratch_we),
.rdata_o(mscratch_q)
);
// dscratch0
csr #(
.RESET_VAL(32'h0)
) dscratch0_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(dscratch0_d),
.we_i(dscratch0_we),
.rdata_o(dscratch0_q)
);
// dscratch1
csr #(
.RESET_VAL(32'h0)
) dscratch1_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(dscratch1_d),
.we_i(dscratch1_we),
.rdata_o(dscratch1_q)
);
// mhartid
csr #(
.RESET_VAL(32'h0)
) mhartid_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(mhartid_d),
.we_i(mhartid_we),
.rdata_o(mhartid_q)
);
// dpc
csr #(
.RESET_VAL(32'h0)
) dpc_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(dpc_d),
.we_i(dpc_we),
.rdata_o(dpc_q)
);
// dcsr
csr #(
.RESET_VAL(32'h40000000)
) dcsr_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(dcsr_d),
.we_i(dcsr_we),
.rdata_o(dcsr_q)
);
// tselect
csr #(
.RESET_VAL(32'h0)
) tselect_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(tselect_d),
.we_i(tselect_we),
.rdata_o(tselect_q)
);
// sstatus
csr #(
.RESET_VAL(32'h0)
) sstatus_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(sstatus_d),
.we_i(sstatus_we),
.rdata_o(sstatus_q)
);
for (genvar i = 0; i < HwBpNum; i = i + 1) begin : dbg_tmatch_reg
// tdata1
csr #(
.RESET_VAL(1'b0),
.WIDTH(1)
) tmatch_control_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(tmatch_control_d),
.we_i(tmatch_control_we[i]),
.rdata_o(tmatch_control_q[i])
);
// tdata2
csr #(
.RESET_VAL(32'h0)
) tmatch_value_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(tmatch_value_d),
.we_i(tmatch_value_we[i]),
.rdata_o(tmatch_value_q[i])
);
end
// for debug
wire[31:0] mtvec = mtvec_q;
wire[31:0] mstatus = mstatus_q;
wire[31:0] mepc = mepc_q;
wire[31:0] mie = mie_q;
wire[31:0] dpc = dpc_q;
wire[31:0] dcsr = dcsr_q;
endmodule

View File

@ -1,215 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.v"
// CSR
module csr_reg(
input wire clk,
input wire rst,
// form ex
input wire we_i, // ex
input wire[`MemAddrBus] raddr_i, // ex
input wire[`MemAddrBus] waddr_i, // ex
input wire[`RegBus] data_i, // ex
// from clint
input wire clint_we_i, // clint
input wire[`MemAddrBus] clint_raddr_i, // clint
input wire[`MemAddrBus] clint_waddr_i, // clint
input wire[`RegBus] clint_data_i, // clint
output wire global_int_en_o, // 使
// to clint
output reg[`RegBus] clint_data_o, // clint
output wire[`RegBus] clint_csr_mtvec, // mtvec
output wire[`RegBus] clint_csr_mepc, // mepc
output wire[`RegBus] clint_csr_mstatus, // mstatus
// to ex
output reg[`RegBus] data_o // ex
);
reg[`DoubleRegBus] cycle;
reg[`RegBus] mtvec;
reg[`RegBus] mcause;
reg[`RegBus] mepc;
reg[`RegBus] mie;
reg[`RegBus] mstatus;
reg[`RegBus] mscratch;
assign global_int_en_o = (mstatus[3] == 1'b1)? `True: `False;
assign clint_csr_mtvec = mtvec;
assign clint_csr_mepc = mepc;
assign clint_csr_mstatus = mstatus;
// cycle counter
//
always @ (posedge clk) begin
if (rst == `RstEnable) begin
cycle <= {`ZeroWord, `ZeroWord};
end else begin
cycle <= cycle + 1'b1;
end
end
// write reg
//
always @ (posedge clk) begin
if (rst == `RstEnable) begin
mtvec <= `ZeroWord;
mcause <= `ZeroWord;
mepc <= `ZeroWord;
mie <= `ZeroWord;
mstatus <= `ZeroWord;
mscratch <= `ZeroWord;
end else begin
// ex
if (we_i == `WriteEnable) begin
case (waddr_i[11:0])
`CSR_MTVEC: begin
mtvec <= data_i;
end
`CSR_MCAUSE: begin
mcause <= data_i;
end
`CSR_MEPC: begin
mepc <= data_i;
end
`CSR_MIE: begin
mie <= data_i;
end
`CSR_MSTATUS: begin
mstatus <= data_i;
end
`CSR_MSCRATCH: begin
mscratch <= data_i;
end
default: begin
end
endcase
// clint
end else if (clint_we_i == `WriteEnable) begin
case (clint_waddr_i[11:0])
`CSR_MTVEC: begin
mtvec <= clint_data_i;
end
`CSR_MCAUSE: begin
mcause <= clint_data_i;
end
`CSR_MEPC: begin
mepc <= clint_data_i;
end
`CSR_MIE: begin
mie <= clint_data_i;
end
`CSR_MSTATUS: begin
mstatus <= clint_data_i;
end
`CSR_MSCRATCH: begin
mscratch <= clint_data_i;
end
default: begin
end
endcase
end
end
end
// read reg
// exCSR
always @ (*) begin
if ((waddr_i[11:0] == raddr_i[11:0]) && (we_i == `WriteEnable)) begin
data_o = data_i;
end else begin
case (raddr_i[11:0])
`CSR_CYCLE: begin
data_o = cycle[31:0];
end
`CSR_CYCLEH: begin
data_o = cycle[63:32];
end
`CSR_MTVEC: begin
data_o = mtvec;
end
`CSR_MCAUSE: begin
data_o = mcause;
end
`CSR_MEPC: begin
data_o = mepc;
end
`CSR_MIE: begin
data_o = mie;
end
`CSR_MSTATUS: begin
data_o = mstatus;
end
`CSR_MSCRATCH: begin
data_o = mscratch;
end
default: begin
data_o = `ZeroWord;
end
endcase
end
end
// read reg
// clintCSR
always @ (*) begin
if ((clint_waddr_i[11:0] == clint_raddr_i[11:0]) && (clint_we_i == `WriteEnable)) begin
clint_data_o = clint_data_i;
end else begin
case (clint_raddr_i[11:0])
`CSR_CYCLE: begin
clint_data_o = cycle[31:0];
end
`CSR_CYCLEH: begin
clint_data_o = cycle[63:32];
end
`CSR_MTVEC: begin
clint_data_o = mtvec;
end
`CSR_MCAUSE: begin
clint_data_o = mcause;
end
`CSR_MEPC: begin
clint_data_o = mepc;
end
`CSR_MIE: begin
clint_data_o = mie;
end
`CSR_MSTATUS: begin
clint_data_o = mstatus;
end
`CSR_MSCRATCH: begin
clint_data_o = mscratch;
end
default: begin
clint_data_o = `ZeroWord;
end
endcase
end
end
endmodule

View File

@ -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

196
rtl/core/defines.sv Normal file
View File

@ -0,0 +1,196 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 从Flash启动时打开下面这个宏
//`define FLASH_BOOT
`ifdef FLASH_BOOT
`define CPU_RESET_ADDR 32'h01000000 // CPU复位地址
`else
`define CPU_RESET_ADDR 32'h00000000 // CPU复位地址
`endif
`define CPU_CLOCK_HZ 25000000 // CPU时钟(25MHZ)
`define JTAG_RESET_FF_LEVELS 5
`define ROM_DEPTH (32 * 256) // 32KB指令存储器深度单位为word(4字节)
`define RAM_DEPTH (16 * 256) // 16KB数据存储器深度单位为word(4字节)
// 外设地址、大小
// ROM
`define ROM_ADDR_MASK ~32'hfffff
`define ROM_ADDR_BASE 32'h00000000
// Bootrom
`define BOOTROM_ADDR_MASK ~32'hffffff
`define BOOTROM_ADDR_BASE 32'h01000000
// Xip
`define XIP_ADDR_MASK ~32'hffffff
`define XIP_ADDR_BASE 32'h02000000
// DEBUG
`define DEBUG_ADDR_MASK ~32'hfffff
`define DEBUG_ADDR_BASE 32'h10000000
// RAM
`define RAM_ADDR_MASK ~32'hfffff
`define RAM_ADDR_BASE 32'h20000000
// GPIO
`define GPIO_ADDR_MASK ~32'hffff
`define GPIO_ADDR_BASE 32'h03000000
// Timer0
`define TIMER0_ADDR_MASK ~32'hffff
`define TIMER0_ADDR_BASE 32'h04000000
// UART0
`define UART0_ADDR_MASK ~32'hffff
`define UART0_ADDR_BASE 32'h05000000
// I2C0
`define I2C0_ADDR_MASK ~32'hffff
`define I2C0_ADDR_BASE 32'h06000000
// SPI0
`define SPI0_ADDR_MASK ~32'hffff
`define SPI0_ADDR_BASE 32'h07000000
// PINMUX
`define PINMUX_ADDR_MASK ~32'hffff
`define PINMUX_ADDR_BASE 32'h08000000
// UART1
`define UART1_ADDR_MASK ~32'hffff
`define UART1_ADDR_BASE 32'h09000000
// UART2
`define UART2_ADDR_MASK ~32'hffff
`define UART2_ADDR_BASE 32'h0A000000
// Timer1
`define TIMER1_ADDR_MASK ~32'hffff
`define TIMER1_ADDR_BASE 32'h0C000000
// Timer2
`define TIMER2_ADDR_MASK ~32'hffff
`define TIMER2_ADDR_BASE 32'h0D000000
// I2C1
`define I2C1_ADDR_MASK ~32'hffff
`define I2C1_ADDR_BASE 32'h0B000000
// Interrupt controller
`define RVIC_ADDR_MASK ~32'hffff
`define RVIC_ADDR_BASE 32'hD0000000
// SIM CTRL
`define SIM_CTRL_ADDR_MASK ~32'hffff
`define SIM_CTRL_ADDR_BASE 32'hE0000000
`define STALL_WIDTH 4
`define STALL_PC 2'd0
`define STALL_IF 2'd1
`define STALL_ID 2'd2
`define STALL_EX 2'd3
`define INST_NOP 32'h00000013
`define INST_MRET 32'h30200073
`define INST_ECALL 32'h00000073
`define INST_EBREAK 32'h00100073
`define INST_DRET 32'h7b200073
// 指令译码信息
`define DECINFO_GRP_BUS 2:0
`define DECINFO_GRP_WIDTH 3
`define DECINFO_GRP_ALU `DECINFO_GRP_WIDTH'd1
`define DECINFO_GRP_BJP `DECINFO_GRP_WIDTH'd2
`define DECINFO_GRP_MULDIV `DECINFO_GRP_WIDTH'd3
`define DECINFO_GRP_CSR `DECINFO_GRP_WIDTH'd4
`define DECINFO_GRP_MEM `DECINFO_GRP_WIDTH'd5
`define DECINFO_GRP_SYS `DECINFO_GRP_WIDTH'd6
`define DECINFO_ALU_BUS_WIDTH (`DECINFO_GRP_WIDTH+14)
`define DECINFO_ALU_LUI (`DECINFO_GRP_WIDTH+0)
`define DECINFO_ALU_AUIPC (`DECINFO_GRP_WIDTH+1)
`define DECINFO_ALU_ADD (`DECINFO_GRP_WIDTH+2)
`define DECINFO_ALU_SUB (`DECINFO_GRP_WIDTH+3)
`define DECINFO_ALU_SLL (`DECINFO_GRP_WIDTH+4)
`define DECINFO_ALU_SLT (`DECINFO_GRP_WIDTH+5)
`define DECINFO_ALU_SLTU (`DECINFO_GRP_WIDTH+6)
`define DECINFO_ALU_XOR (`DECINFO_GRP_WIDTH+7)
`define DECINFO_ALU_SRL (`DECINFO_GRP_WIDTH+8)
`define DECINFO_ALU_SRA (`DECINFO_GRP_WIDTH+9)
`define DECINFO_ALU_OR (`DECINFO_GRP_WIDTH+10)
`define DECINFO_ALU_AND (`DECINFO_GRP_WIDTH+11)
`define DECINFO_ALU_OP2IMM (`DECINFO_GRP_WIDTH+12)
`define DECINFO_ALU_OP1PC (`DECINFO_GRP_WIDTH+13)
`define DECINFO_BJP_BUS_WIDTH (`DECINFO_GRP_WIDTH+8)
`define DECINFO_BJP_JUMP (`DECINFO_GRP_WIDTH+0)
`define DECINFO_BJP_BEQ (`DECINFO_GRP_WIDTH+1)
`define DECINFO_BJP_BNE (`DECINFO_GRP_WIDTH+2)
`define DECINFO_BJP_BLT (`DECINFO_GRP_WIDTH+3)
`define DECINFO_BJP_BGE (`DECINFO_GRP_WIDTH+4)
`define DECINFO_BJP_BLTU (`DECINFO_GRP_WIDTH+5)
`define DECINFO_BJP_BGEU (`DECINFO_GRP_WIDTH+6)
`define DECINFO_BJP_OP1RS1 (`DECINFO_GRP_WIDTH+7)
`define DECINFO_MULDIV_BUS_WIDTH (`DECINFO_GRP_WIDTH+8)
`define DECINFO_MULDIV_MUL (`DECINFO_GRP_WIDTH+0)
`define DECINFO_MULDIV_MULH (`DECINFO_GRP_WIDTH+1)
`define DECINFO_MULDIV_MULHSU (`DECINFO_GRP_WIDTH+2)
`define DECINFO_MULDIV_MULHU (`DECINFO_GRP_WIDTH+3)
`define DECINFO_MULDIV_DIV (`DECINFO_GRP_WIDTH+4)
`define DECINFO_MULDIV_DIVU (`DECINFO_GRP_WIDTH+5)
`define DECINFO_MULDIV_REM (`DECINFO_GRP_WIDTH+6)
`define DECINFO_MULDIV_REMU (`DECINFO_GRP_WIDTH+7)
`define DECINFO_CSR_BUS_WIDTH (`DECINFO_GRP_WIDTH+16)
`define DECINFO_CSR_CSRRW (`DECINFO_GRP_WIDTH+0)
`define DECINFO_CSR_CSRRS (`DECINFO_GRP_WIDTH+1)
`define DECINFO_CSR_CSRRC (`DECINFO_GRP_WIDTH+2)
`define DECINFO_CSR_RS1IMM (`DECINFO_GRP_WIDTH+3)
`define DECINFO_CSR_CSRADDR `DECINFO_GRP_WIDTH+4+12-1:`DECINFO_GRP_WIDTH+4
`define DECINFO_MEM_BUS_WIDTH (`DECINFO_GRP_WIDTH+8)
`define DECINFO_MEM_LB (`DECINFO_GRP_WIDTH+0)
`define DECINFO_MEM_LH (`DECINFO_GRP_WIDTH+1)
`define DECINFO_MEM_LW (`DECINFO_GRP_WIDTH+2)
`define DECINFO_MEM_LBU (`DECINFO_GRP_WIDTH+3)
`define DECINFO_MEM_LHU (`DECINFO_GRP_WIDTH+4)
`define DECINFO_MEM_SB (`DECINFO_GRP_WIDTH+5)
`define DECINFO_MEM_SH (`DECINFO_GRP_WIDTH+6)
`define DECINFO_MEM_SW (`DECINFO_GRP_WIDTH+7)
`define DECINFO_SYS_BUS_WIDTH (`DECINFO_GRP_WIDTH+6)
`define DECINFO_SYS_ECALL (`DECINFO_GRP_WIDTH+0)
`define DECINFO_SYS_EBREAK (`DECINFO_GRP_WIDTH+1)
`define DECINFO_SYS_NOP (`DECINFO_GRP_WIDTH+2)
`define DECINFO_SYS_MRET (`DECINFO_GRP_WIDTH+3)
`define DECINFO_SYS_FENCE (`DECINFO_GRP_WIDTH+4)
`define DECINFO_SYS_DRET (`DECINFO_GRP_WIDTH+5)
// 最长的那组
`define DECINFO_WIDTH `DECINFO_CSR_BUS_WIDTH
// CSR寄存器地址
`define CSR_CYCLE 12'hc00
`define CSR_CYCLEH 12'hc80
`define CSR_MTVEC 12'h305
`define CSR_MCAUSE 12'h342
`define CSR_MEPC 12'h341
`define CSR_MIE 12'h304
`define CSR_MSTATUS 12'h300
`define CSR_MSCRATCH 12'h340
`define CSR_MHARTID 12'hF14
`define CSR_MISA 12'h301
// only used for verification
`define CSR_SSTATUS 12'h100
// Debug
`define CSR_DCSR 12'h7b0
`define CSR_DPC 12'h7b1
`define CSR_DSCRATCH0 12'h7b2
`define CSR_DSCRATCH1 12'h7b3
`define CSR_TSELECT 12'h7A0
`define CSR_TDATA1 12'h7A1
`define CSR_TDATA2 12'h7A2
`define CSR_TDATA3 12'h7A3
`define CSR_MCONTEXT 12'h7A8
`define CSR_SCONTEXT 12'h7AA

View File

@ -1,164 +0,0 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`define CpuResetAddr 32'h0
`define RstEnable 1'b0
`define RstDisable 1'b1
`define ZeroWord 32'h0
`define ZeroReg 5'h0
`define WriteEnable 1'b1
`define WriteDisable 1'b0
`define ReadEnable 1'b1
`define ReadDisable 1'b0
`define True 1'b1
`define False 1'b0
`define ChipEnable 1'b1
`define ChipDisable 1'b0
`define JumpEnable 1'b1
`define JumpDisable 1'b0
`define DivResultNotReady 1'b0
`define DivResultReady 1'b1
`define DivStart 1'b1
`define DivStop 1'b0
`define HoldEnable 1'b1
`define HoldDisable 1'b0
`define Stop 1'b1
`define NoStop 1'b0
`define RIB_ACK 1'b1
`define RIB_NACK 1'b0
`define RIB_REQ 1'b1
`define RIB_NREQ 1'b0
`define INT_ASSERT 1'b1
`define INT_DEASSERT 1'b0
`define INT_BUS 7:0
`define INT_NONE 8'h0
`define INT_RET 8'hff
`define INT_TIMER0 8'b00000001
`define INT_TIMER0_ENTRY_ADDR 32'h4
`define Hold_Flag_Bus 2:0
`define Hold_None 3'b000
`define Hold_Pc 3'b001
`define Hold_If 3'b010
`define Hold_Id 3'b011
// I type inst
`define INST_TYPE_I 7'b0010011
`define INST_ADDI 3'b000
`define INST_SLTI 3'b010
`define INST_SLTIU 3'b011
`define INST_XORI 3'b100
`define INST_ORI 3'b110
`define INST_ANDI 3'b111
`define INST_SLLI 3'b001
`define INST_SRI 3'b101
// L type inst
`define INST_TYPE_L 7'b0000011
`define INST_LB 3'b000
`define INST_LH 3'b001
`define INST_LW 3'b010
`define INST_LBU 3'b100
`define INST_LHU 3'b101
// S type inst
`define INST_TYPE_S 7'b0100011
`define INST_SB 3'b000
`define INST_SH 3'b001
`define INST_SW 3'b010
// R and M type inst
`define INST_TYPE_R_M 7'b0110011
// R type inst
`define INST_ADD_SUB 3'b000
`define INST_SLL 3'b001
`define INST_SLT 3'b010
`define INST_SLTU 3'b011
`define INST_XOR 3'b100
`define INST_SR 3'b101
`define INST_OR 3'b110
`define INST_AND 3'b111
// M type inst
`define INST_MUL 3'b000
`define INST_MULH 3'b001
`define INST_MULHSU 3'b010
`define INST_MULHU 3'b011
`define INST_DIV 3'b100
`define INST_DIVU 3'b101
`define INST_REM 3'b110
`define INST_REMU 3'b111
// J type inst
`define INST_JAL 7'b1101111
`define INST_JALR 7'b1100111
`define INST_LUI 7'b0110111
`define INST_AUIPC 7'b0010111
`define INST_NOP 32'h00000001
`define INST_NOP_OP 7'b0000001
`define INST_MRET 32'h30200073
`define INST_RET 32'h00008067
`define INST_FENCE 7'b0001111
`define INST_ECALL 32'h73
`define INST_EBREAK 32'h00100073
// J type inst
`define INST_TYPE_B 7'b1100011
`define INST_BEQ 3'b000
`define INST_BNE 3'b001
`define INST_BLT 3'b100
`define INST_BGE 3'b101
`define INST_BLTU 3'b110
`define INST_BGEU 3'b111
// CSR inst
`define INST_CSR 7'b1110011
`define INST_CSRRW 3'b001
`define INST_CSRRS 3'b010
`define INST_CSRRC 3'b011
`define INST_CSRRWI 3'b101
`define INST_CSRRSI 3'b110
`define INST_CSRRCI 3'b111
// CSR reg addr
`define CSR_CYCLE 12'hc00
`define CSR_CYCLEH 12'hc80
`define CSR_MTVEC 12'h305
`define CSR_MCAUSE 12'h342
`define CSR_MEPC 12'h341
`define CSR_MIE 12'h304
`define CSR_MSTATUS 12'h300
`define CSR_MSCRATCH 12'h340
`define RomNum 4096 // rom depth(how many words)
`define MemNum 4096 // memory depth(how many words)
`define MemBus 31:0
`define MemAddrBus 31:0
`define InstBus 31:0
`define InstAddrBus 31:0
// common regs
`define RegAddrBus 4:0
`define RegBus 31:0
`define DoubleRegBus 63:0
`define RegWidth 32
`define RegNum 32 // reg num
`define RegNumLog2 5

View File

@ -14,28 +14,23 @@
limitations under the License.
*/
`include "defines.v"
`include "defines.sv"
// 除法模块
// 试商法实现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[31:0] dividend_i, // 被除数
input wire[31:0] divisor_i, // 除数
input wire start_i, // 开始信号,运算期间这个信号需要一直保持有效
input wire[2:0] op_i, // 具体是哪一条指令
input wire[`RegAddrBus] reg_waddr_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, // 除法结果
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

View File

@ -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

308
rtl/core/exception.sv Normal file
View File

@ -0,0 +1,308 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
`define DCSR_CAUSE_NONE 3'h0
`define DCSR_CAUSE_STEP 3'h4
`define DCSR_CAUSE_DBGREQ 3'h3
`define DCSR_CAUSE_EBREAK 3'h1
`define DCSR_CAUSE_HALT 3'h5
`define DCSR_CAUSE_TRIGGER 3'h2
module exception (
input wire clk,
input wire rst_n,
input wire inst_valid_i,
input wire inst_executed_i,
input wire inst_ecall_i, // ecall指令
input wire inst_ebreak_i, // ebreak指令
input wire inst_mret_i, // mret指令
input wire inst_dret_i, // dret指令
input wire[31:0] inst_addr_i, // 指令地址
input wire illegal_inst_i, // 非法指令
input wire[31:0] mtvec_i, // mtvec寄存器
input wire[31:0] mepc_i, // mepc寄存器
input wire[31:0] mstatus_i, // mstatus寄存器
input wire[31:0] mie_i, // mie寄存器
input wire[31:0] dpc_i, // dpc寄存器
input wire[31:0] dcsr_i, // dcsr寄存器
input wire int_req_i,
input wire[7:0] int_id_i,
input wire trigger_match_i,
input wire[31:0] debug_halt_addr_i,
input wire debug_req_i,
output wire csr_we_o, // 写CSR寄存器标志
output wire[31:0] csr_waddr_o, // 写CSR寄存器地址
output wire[31:0] csr_wdata_o, // 写CSR寄存器数据
output wire stall_flag_o, // 流水线暂停标志
output wire[31:0] int_addr_o, // 中断入口地址
output wire int_assert_o // 中断标志
);
// 异常偏移
localparam ILLEGAL_INSTR_OFFSET = 0;
localparam INSTR_ADDR_MISA_OFFSET = 4;
localparam ECALL_OFFSET = 8;
localparam EBREAK_OFFSET = 12;
localparam LOAD_MISA_OFFSET = 16;
localparam STORE_MISA_OFFSET = 20;
localparam RESERVED1_EXCEPTION_OFFSET = 24;
localparam RESERVED2_EXCEPTION_OFFSET = 28;
// 中断偏移
localparam INT_OFFSET = 32;
localparam S_IDLE = 5'b00001;
localparam S_W_MEPC = 5'b00010;
localparam S_W_DCSR = 5'b00100;
localparam S_ASSERT = 5'b01000;
localparam S_W_MSTATUS = 5'b10000;
reg debug_mode_d, debug_mode_q;
reg[4:0] state_d, state_q;
reg[31:0] assert_addr_d, assert_addr_q;
reg[31:0] return_addr_d, return_addr_q;
reg trigger_match_d, trigger_match_q;
reg csr_we;
reg[31:0] csr_waddr;
reg[31:0] csr_wdata;
reg[7:0] int_id_d, int_id_q;
reg in_irq_context_d, in_irq_context_q;
wire global_int_en;
wire interrupt_req_valid;
assign global_int_en = mstatus_i[3];
assign interrupt_req_valid = inst_valid_i &
int_req_i &
((int_id_i != int_id_q) | (~in_irq_context_q));
reg exception_req;
reg[31:0] exception_cause;
always @ (*) begin
if (illegal_inst_i) begin
exception_req = 1'b1;
exception_cause = 32'h0;
end else if (inst_ecall_i & inst_valid_i) begin
exception_req = 1'b1;
exception_cause = 32'h2;
end else begin
exception_req = 1'b0;
exception_cause = 32'h0;
end
end
wire int_or_exception_req;
wire[31:0] int_or_exception_cause;
assign int_or_exception_req = (interrupt_req_valid & global_int_en & (~debug_mode_q)) | exception_req;
assign int_or_exception_cause = exception_req ? exception_cause : (32'h8 + {24'h0, int_id_i});
wire trigger_matching;
gen_ticks_sync #(
.DP(5),
.DW(1)
) gen_trigger_sync (
.rst_n(rst_n),
.clk(clk),
.din(trigger_match_q),
.dout(trigger_matching)
);
reg enter_debug_cause_debugger_req;
reg enter_debug_cause_single_step;
reg enter_debug_cause_ebreak;
reg enter_debug_cause_reset_halt;
reg enter_debug_cause_trigger;
reg[2:0] dcsr_cause_d, dcsr_cause_q;
always @ (*) begin
enter_debug_cause_debugger_req = 1'b0;
enter_debug_cause_single_step = 1'b0;
enter_debug_cause_ebreak = 1'b0;
enter_debug_cause_reset_halt = 1'b0;
enter_debug_cause_trigger = 1'b0;
dcsr_cause_d = `DCSR_CAUSE_NONE;
if (trigger_match_i & inst_valid_i & (~trigger_matching)) begin
enter_debug_cause_trigger = 1'b1;
dcsr_cause_d = `DCSR_CAUSE_TRIGGER;
end else if (inst_ebreak_i & inst_valid_i) begin
enter_debug_cause_ebreak = 1'b1;
dcsr_cause_d = `DCSR_CAUSE_EBREAK;
end else if ((inst_addr_i == `CPU_RESET_ADDR) & inst_valid_i & debug_req_i) begin
enter_debug_cause_reset_halt = 1'b1;
dcsr_cause_d = `DCSR_CAUSE_HALT;
end else if ((~debug_mode_q) & debug_req_i & inst_valid_i) begin
enter_debug_cause_debugger_req = 1'b1;
dcsr_cause_d = `DCSR_CAUSE_DBGREQ;
end else if ((~debug_mode_q) & dcsr_i[2] & inst_valid_i & inst_executed_i) begin
enter_debug_cause_single_step = 1'b1;
dcsr_cause_d = `DCSR_CAUSE_STEP;
end
end
wire debug_mode_req = enter_debug_cause_debugger_req |
enter_debug_cause_single_step |
enter_debug_cause_reset_halt |
enter_debug_cause_trigger |
enter_debug_cause_ebreak;
assign stall_flag_o = ((state_q != S_IDLE) & (state_q != S_ASSERT)) |
int_or_exception_req |
debug_mode_req |
inst_mret_i |
inst_dret_i;
always @ (*) begin
state_d = state_q;
assert_addr_d = assert_addr_q;
debug_mode_d = debug_mode_q;
return_addr_d = return_addr_q;
csr_we = 1'b0;
csr_waddr = 32'h0;
csr_wdata = 32'h0;
trigger_match_d = trigger_match_q;
int_id_d = int_id_q;
in_irq_context_d = in_irq_context_q;
case (state_q)
S_IDLE: begin
if (int_or_exception_req & (!debug_mode_q)) begin
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_MCAUSE};
csr_wdata = int_or_exception_cause;
assert_addr_d = mtvec_i;
return_addr_d = inst_addr_i;
state_d = S_W_MSTATUS;
int_id_d = int_id_i;
in_irq_context_d = 1'b1;
end else if (debug_mode_req) begin
debug_mode_d = 1'b1;
if (enter_debug_cause_debugger_req |
enter_debug_cause_single_step |
enter_debug_cause_trigger |
enter_debug_cause_reset_halt) begin
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_DPC};
csr_wdata = enter_debug_cause_reset_halt ? (`CPU_RESET_ADDR) : inst_addr_i;
// when run openocd compliance test, use it.
// openocd compliance test bug: It report test fail when the reset address is 0x0:
// "NDMRESET should move DPC to reset value."
//csr_wdata = enter_debug_cause_reset_halt ? (`CPU_RESET_ADDR + 4'h4) : inst_addr_i;
end
if (enter_debug_cause_trigger) begin
trigger_match_d = 1'b1;
end
assert_addr_d = debug_halt_addr_i;
// ebreak do not change dpc and dcsr value
if (enter_debug_cause_ebreak) begin
state_d = S_ASSERT;
end else begin
state_d = S_W_DCSR;
end
end else if (inst_mret_i) begin
in_irq_context_d = 1'b0;
assert_addr_d = mepc_i;
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_MSTATUS};
// 开全局中断
csr_wdata = {mstatus_i[31:4], 1'b1, mstatus_i[2:0]};
state_d = S_ASSERT;
end else if (inst_dret_i) begin
assert_addr_d = dpc_i;
state_d = S_ASSERT;
debug_mode_d = 1'b0;
trigger_match_d = 1'b0;
end
end
S_W_MSTATUS: begin
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_MSTATUS};
// 关全局中断
csr_wdata = {mstatus_i[31:4], 1'b0, mstatus_i[2:0]};
state_d = S_W_MEPC;
end
S_W_MEPC: begin
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_MEPC};
csr_wdata = return_addr_q;
state_d = S_ASSERT;
end
S_W_DCSR: begin
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_DCSR};
csr_wdata = {dcsr_i[31:9], dcsr_cause_q, dcsr_i[5:0]};
state_d = S_ASSERT;
end
S_ASSERT: begin
csr_we = 1'b0;
state_d = S_IDLE;
end
default:;
endcase
end
assign csr_we_o = csr_we;
assign csr_waddr_o = csr_waddr;
assign csr_wdata_o = csr_wdata;
assign int_assert_o = (state_q == S_ASSERT);
assign int_addr_o = assert_addr_q;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= S_IDLE;
assert_addr_q <= 32'h0;
debug_mode_q <= 1'b0;
return_addr_q <= 32'h0;
dcsr_cause_q <= `DCSR_CAUSE_NONE;
trigger_match_q <= 1'b0;
int_id_q <= 8'h0;
in_irq_context_q <= 1'b0;
end else begin
state_q <= state_d;
assert_addr_q <= assert_addr_d;
debug_mode_q <= debug_mode_d;
return_addr_q <= return_addr_d;
dcsr_cause_q <= dcsr_cause_d;
trigger_match_q <= trigger_match_d;
int_id_q <= int_id_d;
in_irq_context_q <= in_irq_context_d;
end
end
endmodule

428
rtl/core/exu.sv Normal file
View File

@ -0,0 +1,428 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// 执行模块
module exu #(
parameter bit BranchPredictor = 1'b1
)(
input wire clk, // 时钟
input wire rst_n, // 复位
// exception
input wire int_assert_i, // 中断发生标志
input wire[31:0] int_addr_i, // 中断跳转地址
input wire int_stall_i, // 暂停标志
output wire inst_ecall_o, // ecall指令
output wire inst_ebreak_o, // ebreak指令
output wire inst_mret_o, // mret指令
output wire inst_dret_o, // dret指令
// mem
input wire[31:0] mem_rdata_i, // 内存输入数据
input wire mem_gnt_i, // 总线授权
input wire mem_rvalid_i, // 总线响应
output wire[31:0] mem_wdata_o, // 写内存数据
output wire[31:0] mem_addr_o, // 读、写内存地址
output wire mem_we_o, // 是否要写内存
output wire[3:0] mem_be_o, // 字节位
output wire mem_req_o, // 访存请求
output wire mem_access_misaligned_o, // 访存不对齐
// to gpr_reg
output wire[31:0] reg_wdata_o, // 写寄存器数据
output wire reg_we_o, // 是否要写通用寄存器
output wire[4:0] reg_waddr_o, // 写通用寄存器地址
// csr_reg
input wire[31:0] csr_rdata_i, // CSR寄存器数据
output wire[31:0] csr_raddr_o, // 读CSR寄存器地址
output wire[31:0] csr_wdata_o, // 写CSR寄存器数据
output wire csr_we_o, // 是否要写CSR寄存器
output wire[31:0] csr_waddr_o, // 写CSR寄存器地址
// to pipe_ctrl
output wire hold_flag_o, // 是否暂停标志
output wire jump_flag_o, // 是否跳转标志
output wire[31:0] jump_addr_o, // 跳转目的地址
//
output wire inst_valid_o, // 指令有效
output wire inst_executed_o, // 指令已经执行完毕
// from idu_exu
input wire inst_valid_i,
input wire[31:0] inst_i,
input wire[`DECINFO_WIDTH-1:0] dec_info_bus_i,
input wire[31:0] dec_imm_i,
input wire[31:0] dec_pc_i,
input wire[31:0] next_pc_i,
input wire[4:0] rd_waddr_i,
input wire[31:0] reg1_rdata_i, // 通用寄存器1输入数据
input wire[31:0] reg2_rdata_i, // 通用寄存器2输入数据
input wire rd_we_i
);
wire[31:0] next_pc = dec_pc_i + 4'h4;
// dispatch to ALU
wire[31:0] alu_op1_o;
wire[31:0] alu_op2_o;
wire req_alu_o;
wire alu_op_lui_o;
wire alu_op_auipc_o;
wire alu_op_add_o;
wire alu_op_sub_o;
wire alu_op_sll_o;
wire alu_op_slt_o;
wire alu_op_sltu_o;
wire alu_op_xor_o;
wire alu_op_srl_o;
wire alu_op_sra_o;
wire alu_op_or_o;
wire alu_op_and_o;
// dispatch to BJP
wire[31:0] bjp_op1_o;
wire[31:0] bjp_op2_o;
wire[31:0] bjp_jump_op1_o;
wire[31:0] bjp_jump_op2_o;
wire req_bjp_o;
wire bjp_op_jump_o;
wire bjp_op_beq_o;
wire bjp_op_bne_o;
wire bjp_op_blt_o;
wire bjp_op_bltu_o;
wire bjp_op_bge_o;
wire bjp_op_bgeu_o;
wire bjp_op_jalr_o;
// dispatch to MULDIV
wire req_muldiv_o;
wire[31:0] muldiv_op1_o;
wire[31:0] muldiv_op2_o;
wire muldiv_op_mul_o;
wire muldiv_op_mulh_o;
wire muldiv_op_mulhsu_o;
wire muldiv_op_mulhu_o;
wire muldiv_op_div_o;
wire muldiv_op_divu_o;
wire muldiv_op_rem_o;
wire muldiv_op_remu_o;
// dispatch to CSR
wire req_csr_o;
wire[31:0] csr_op1_o;
wire[31:0] csr_addr_o;
wire csr_csrrw_o;
wire csr_csrrs_o;
wire csr_csrrc_o;
// dispatch to MEM
wire req_mem_o;
wire[31:0] mem_op1_o;
wire[31:0] mem_op2_o;
wire[31:0] mem_rs2_data_o;
wire mem_op_lb_o;
wire mem_op_lh_o;
wire mem_op_lw_o;
wire mem_op_lbu_o;
wire mem_op_lhu_o;
wire mem_op_sb_o;
wire mem_op_sh_o;
wire mem_op_sw_o;
// dispatch to SYS
wire sys_op_nop_o;
wire sys_op_mret_o;
wire sys_op_ecall_o;
wire sys_op_ebreak_o;
wire sys_op_fence_o;
wire sys_op_dret_o;
exu_dispatch u_exu_dispatch(
// input
.clk(clk),
.rst_n(rst_n),
.dec_info_bus_i(dec_info_bus_i),
.dec_imm_i(dec_imm_i),
.dec_pc_i(dec_pc_i),
.rs1_rdata_i(reg1_rdata_i),
.rs2_rdata_i(reg2_rdata_i),
// dispatch to ALU
.alu_op1_o(alu_op1_o),
.alu_op2_o(alu_op2_o),
.req_alu_o(req_alu_o),
.alu_op_lui_o(alu_op_lui_o),
.alu_op_auipc_o(alu_op_auipc_o),
.alu_op_add_o(alu_op_add_o),
.alu_op_sub_o(alu_op_sub_o),
.alu_op_sll_o(alu_op_sll_o),
.alu_op_slt_o(alu_op_slt_o),
.alu_op_sltu_o(alu_op_sltu_o),
.alu_op_xor_o(alu_op_xor_o),
.alu_op_srl_o(alu_op_srl_o),
.alu_op_sra_o(alu_op_sra_o),
.alu_op_or_o(alu_op_or_o),
.alu_op_and_o(alu_op_and_o),
// dispatch to BJP
.bjp_op1_o(bjp_op1_o),
.bjp_op2_o(bjp_op2_o),
.bjp_jump_op1_o(bjp_jump_op1_o),
.bjp_jump_op2_o(bjp_jump_op2_o),
.req_bjp_o(req_bjp_o),
.bjp_op_jump_o(bjp_op_jump_o),
.bjp_op_beq_o(bjp_op_beq_o),
.bjp_op_bne_o(bjp_op_bne_o),
.bjp_op_blt_o(bjp_op_blt_o),
.bjp_op_bltu_o(bjp_op_bltu_o),
.bjp_op_bge_o(bjp_op_bge_o),
.bjp_op_bgeu_o(bjp_op_bgeu_o),
.bjp_op_jalr_o(bjp_op_jalr_o),
// dispatch to MULDIV
.req_muldiv_o(req_muldiv_o),
.muldiv_op1_o(muldiv_op1_o),
.muldiv_op2_o(muldiv_op2_o),
.muldiv_op_mul_o(muldiv_op_mul_o),
.muldiv_op_mulh_o(muldiv_op_mulh_o),
.muldiv_op_mulhsu_o(muldiv_op_mulhsu_o),
.muldiv_op_mulhu_o(muldiv_op_mulhu_o),
.muldiv_op_div_o(muldiv_op_div_o),
.muldiv_op_divu_o(muldiv_op_divu_o),
.muldiv_op_rem_o(muldiv_op_rem_o),
.muldiv_op_remu_o(muldiv_op_remu_o),
// dispatch to CSR
.req_csr_o(req_csr_o),
.csr_op1_o(csr_op1_o),
.csr_addr_o(csr_addr_o),
.csr_csrrw_o(csr_csrrw_o),
.csr_csrrs_o(csr_csrrs_o),
.csr_csrrc_o(csr_csrrc_o),
// dispatch to MEM
.req_mem_o(req_mem_o),
.mem_op1_o(mem_op1_o),
.mem_op2_o(mem_op2_o),
.mem_rs2_data_o(mem_rs2_data_o),
.mem_op_lb_o(mem_op_lb_o),
.mem_op_lh_o(mem_op_lh_o),
.mem_op_lw_o(mem_op_lw_o),
.mem_op_lbu_o(mem_op_lbu_o),
.mem_op_lhu_o(mem_op_lhu_o),
.mem_op_sb_o(mem_op_sb_o),
.mem_op_sh_o(mem_op_sh_o),
.mem_op_sw_o(mem_op_sw_o),
// dispatch to SYS
.sys_op_nop_o(sys_op_nop_o),
.sys_op_mret_o(sys_op_mret_o),
.sys_op_ecall_o(sys_op_ecall_o),
.sys_op_ebreak_o(sys_op_ebreak_o),
.sys_op_fence_o(sys_op_fence_o),
.sys_op_dret_o(sys_op_dret_o)
);
assign inst_ecall_o = sys_op_ecall_o;
assign inst_ebreak_o = sys_op_ebreak_o;
assign inst_mret_o = sys_op_mret_o;
assign inst_dret_o = sys_op_dret_o;
wire[31:0] alu_res_o;
wire[31:0] bjp_res_o;
wire bjp_cmp_res_o;
wire[31:0] csr_op1 = csr_csrrc_o? (~csr_op1_o): csr_op1_o;
wire[31:0] csr_op2 = csr_csrrw_o? (32'h0): csr_rdata_i;
exu_alu_datapath u_exu_alu_datapath(
.clk(clk),
.rst_n(rst_n),
// ALU
.req_alu_i(req_alu_o),
.alu_op1_i(alu_op1_o),
.alu_op2_i(alu_op2_o),
.alu_op_add_i(alu_op_add_o | alu_op_lui_o | alu_op_auipc_o),
.alu_op_sub_i(alu_op_sub_o),
.alu_op_sll_i(alu_op_sll_o),
.alu_op_slt_i(alu_op_slt_o),
.alu_op_sltu_i(alu_op_sltu_o),
.alu_op_xor_i(alu_op_xor_o),
.alu_op_srl_i(alu_op_srl_o),
.alu_op_sra_i(alu_op_sra_o),
.alu_op_or_i(alu_op_or_o),
.alu_op_and_i(alu_op_and_o),
// BJP
.req_bjp_i(req_bjp_o),
.bjp_op1_i(bjp_op1_o),
.bjp_op2_i(bjp_op2_o),
.bjp_op_beq_i(bjp_op_beq_o),
.bjp_op_bne_i(bjp_op_bne_o),
.bjp_op_blt_i(bjp_op_blt_o),
.bjp_op_bltu_i(bjp_op_bltu_o),
.bjp_op_bge_i(bjp_op_bge_o),
.bjp_op_bgeu_i(bjp_op_bgeu_o),
.bjp_op_jump_i(bjp_op_jump_o),
.bjp_jump_op1_i(bjp_jump_op1_o),
.bjp_jump_op2_i(bjp_jump_op2_o),
// MEM
.req_mem_i(req_mem_o),
.mem_op1_i(mem_op1_o),
.mem_op2_i(mem_op2_o),
// CSR
.req_csr_i(req_csr_o),
.csr_op1_i(csr_op1),
.csr_op2_i(csr_op2),
.csr_csrrw_i(csr_csrrw_o),
.csr_csrrs_i(csr_csrrs_o),
.csr_csrrc_i(csr_csrrc_o),
.alu_res_o(alu_res_o),
.bjp_res_o(bjp_res_o),
.bjp_cmp_res_o(bjp_cmp_res_o)
);
wire mem_reg_we_o;
wire mem_mem_we_o;
wire[31:0] mem_wdata;
wire mem_stall_o;
exu_mem u_exu_mem(
.clk(clk),
.rst_n(rst_n),
.req_mem_i(req_mem_o),
.mem_addr_i(alu_res_o),
.mem_rs2_data_i(mem_rs2_data_o),
.mem_gnt_i(mem_gnt_i),
.mem_rvalid_i(mem_rvalid_i),
.mem_rdata_i(mem_rdata_i),
.mem_op_lb_i(mem_op_lb_o),
.mem_op_lh_i(mem_op_lh_o),
.mem_op_lw_i(mem_op_lw_o),
.mem_op_lbu_i(mem_op_lbu_o),
.mem_op_lhu_i(mem_op_lhu_o),
.mem_op_sb_i(mem_op_sb_o),
.mem_op_sh_i(mem_op_sh_o),
.mem_op_sw_i(mem_op_sw_o),
.mem_access_misaligned_o(mem_access_misaligned_o),
.mem_stall_o(mem_stall_o),
.mem_addr_o(mem_addr_o),
.mem_wdata_o(mem_wdata),
.mem_reg_we_o(mem_reg_we_o),
.mem_mem_we_o(mem_mem_we_o),
.mem_be_o(mem_be_o),
.mem_req_o(mem_req_o)
);
wire[31:0] muldiv_reg_wdata_o;
wire muldiv_reg_we_o;
wire muldiv_stall_o;
exu_muldiv u_exu_muldiv(
.clk(clk),
.rst_n(rst_n),
.muldiv_op1_i(muldiv_op1_o),
.muldiv_op2_i(muldiv_op2_o),
.muldiv_op_mul_i(muldiv_op_mul_o),
.muldiv_op_mulh_i(muldiv_op_mulh_o),
.muldiv_op_mulhsu_i(muldiv_op_mulhsu_o),
.muldiv_op_mulhu_i(muldiv_op_mulhu_o),
.muldiv_op_div_i(muldiv_op_div_o),
.muldiv_op_divu_i(muldiv_op_divu_o),
.muldiv_op_rem_i(muldiv_op_rem_o),
.muldiv_op_remu_i(muldiv_op_remu_o),
.int_stall_i(int_stall_i),
.muldiv_reg_wdata_o(muldiv_reg_wdata_o),
.muldiv_reg_we_o(muldiv_reg_we_o),
.muldiv_stall_o(muldiv_stall_o)
);
wire commit_reg_we_o;
exu_commit u_exu_commit(
.clk(clk),
.rst_n(rst_n),
.req_muldiv_i(req_muldiv_o),
.muldiv_reg_we_i(muldiv_reg_we_o),
.muldiv_reg_waddr_i(rd_waddr_i),
.muldiv_reg_wdata_i(muldiv_reg_wdata_o),
.req_mem_i(req_mem_o),
.mem_reg_we_i(mem_reg_we_o),
.mem_reg_waddr_i(rd_waddr_i),
.mem_reg_wdata_i(mem_wdata),
.req_csr_i(req_csr_o),
.csr_reg_we_i(req_csr_o),
.csr_reg_waddr_i(rd_waddr_i),
.csr_reg_wdata_i(csr_rdata_i),
.req_bjp_i(req_bjp_o),
.bjp_reg_we_i(bjp_op_jump_o),
.bjp_reg_wdata_i(next_pc),
.bjp_reg_waddr_i(rd_waddr_i),
.rd_we_i(rd_we_i),
.rd_waddr_i(rd_waddr_i),
.alu_reg_wdata_i(alu_res_o),
.reg_we_o(commit_reg_we_o),
.reg_waddr_o(reg_waddr_o),
.reg_wdata_o(reg_wdata_o)
);
assign reg_we_o = commit_reg_we_o & (~int_stall_i);
wire prdt_taken;
if (BranchPredictor) begin: g_branch_predictor
// jal
assign prdt_taken = ((~bjp_op_jalr_o) & bjp_op_jump_o) |
// bxx & imm[31]
(req_bjp_o & (~bjp_op_jump_o) & dec_imm_i[31]);
end else begin: g_no_branch_predictor
assign prdt_taken = 1'b0;
end
// bxx分支预测错误
wire prdt_taken_error = prdt_taken & (~bjp_cmp_res_o) & req_bjp_o & (~bjp_op_jump_o);
wire inst_jump = (bjp_cmp_res_o & (~prdt_taken)) |
(bjp_op_jump_o & (~prdt_taken)) |
sys_op_fence_o;
assign jump_flag_o = ((inst_jump | prdt_taken_error) & (~int_stall_i)) | int_assert_i;
assign jump_addr_o = int_assert_i? int_addr_i:
sys_op_fence_o? next_pc:
prdt_taken_error? next_pc:
bjp_res_o;
assign hold_flag_o = muldiv_stall_o | mem_stall_o;
assign csr_raddr_o = csr_addr_o;
assign csr_waddr_o = csr_addr_o;
assign csr_we_o = req_csr_o & (~int_stall_i);
assign csr_wdata_o = alu_res_o;
assign mem_we_o = mem_mem_we_o & (~int_stall_i);
assign mem_wdata_o = mem_wdata;
assign inst_valid_o = hold_flag_o? 1'b0: inst_valid_i;
reg inst_executed_q;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
inst_executed_q <= 1'b0;
end else begin
if (inst_valid_i) begin
inst_executed_q <= (inst_jump & (~int_stall_i)) |
reg_we_o |
csr_we_o |
mem_we_o;
end
end
end
assign inst_executed_o = inst_executed_q;
endmodule

View File

@ -0,0 +1,254 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
`define DATAPATH_MUX_WIDTH (32+32+16)
module exu_alu_datapath(
input wire clk,
input wire rst_n,
// ALU
input wire req_alu_i,
input wire[31:0] alu_op1_i,
input wire[31:0] alu_op2_i,
input wire alu_op_add_i,
input wire alu_op_sub_i,
input wire alu_op_sll_i,
input wire alu_op_slt_i,
input wire alu_op_sltu_i,
input wire alu_op_xor_i,
input wire alu_op_srl_i,
input wire alu_op_sra_i,
input wire alu_op_or_i,
input wire alu_op_and_i,
// BJP
input wire req_bjp_i,
input wire[31:0] bjp_op1_i,
input wire[31:0] bjp_op2_i,
input wire bjp_op_beq_i,
input wire bjp_op_bne_i,
input wire bjp_op_blt_i,
input wire bjp_op_bltu_i,
input wire bjp_op_bge_i,
input wire bjp_op_bgeu_i,
input wire bjp_op_jump_i,
input wire[31:0] bjp_jump_op1_i,
input wire[31:0] bjp_jump_op2_i,
// MEM
input wire req_mem_i,
input wire[31:0] mem_op1_i,
input wire[31:0] mem_op2_i,
// CSR
input wire req_csr_i,
input wire[31:0] csr_op1_i,
input wire[31:0] csr_op2_i,
input wire csr_csrrw_i,
input wire csr_csrrs_i,
input wire csr_csrrc_i,
output wire[31:0] alu_res_o,
output wire[31:0] bjp_res_o,
output wire bjp_cmp_res_o
);
wire[31:0] mux_op1;
wire[31:0] mux_op2;
wire op_add;
wire op_sub;
wire op_sll;
wire op_slt;
wire op_sltu;
wire op_xor;
wire op_srl;
wire op_sra;
wire op_or;
wire op_and;
wire op_beq;
wire op_bne;
wire op_blt;
wire op_bltu;
wire op_bge;
wire op_bgeu;
// 异或
wire[31:0] xor_res = mux_op1 ^ mux_op2;
// 或
wire[31:0] or_res = mux_op1 | mux_op2;
// 与
wire[31:0] and_res = mux_op1 & mux_op2;
// 加、减
wire[31:0] add_op1 = req_bjp_i? bjp_jump_op1_i: mux_op1;
wire[31:0] add_op2 = req_bjp_i? bjp_jump_op2_i: mux_op2;
wire[31:0] add_sub_res = add_op1 + (op_sub? (-add_op2): add_op2);
// 左移
wire[31:0] sll_res = mux_op1 << mux_op2[4:0];
// 逻辑右移
wire[31:0] srl_res = mux_op1 >> mux_op2[4:0];
// 算数右移
wire[31:0] sr_shift_mask = 32'hffffffff >> mux_op2[4:0];
wire[31:0] sra_res = (srl_res & sr_shift_mask) | ({32{mux_op1[31]}} & (~sr_shift_mask));
// 有符号数比较
wire op1_ge_op2_signed = ($signed(mux_op1) >= $signed(mux_op2));
// 无符号数比较
wire op1_ge_op2_unsigned = (mux_op1 >= mux_op2);
wire op1_neq_op2 = (|xor_res);
wire op1_eq_op2 = (~op1_neq_op2);
wire cmp_res_eq = op_beq & op1_eq_op2;
wire cmp_res_neq = op_bne & op1_neq_op2;
wire cmp_res_lt = op_blt & (~op1_ge_op2_signed);
wire cmp_res_ltu = op_bltu & (~op1_ge_op2_unsigned);
wire cmp_res_gt = op_bge & op1_ge_op2_signed;
wire cmp_res_gtu = op_bgeu & op1_ge_op2_unsigned;
wire[31:0] slt_res = (~op1_ge_op2_signed)? 32'h1: 32'h0;
wire[31:0] sltu_res = (~op1_ge_op2_unsigned)? 32'h1: 32'h0;
reg[31:0] alu_datapath_res;
always @ (*) begin
alu_datapath_res = 32'h0;
case (1'b1)
op_xor: alu_datapath_res = xor_res;
op_or: alu_datapath_res = or_res;
op_and: alu_datapath_res = and_res;
op_add: alu_datapath_res = add_sub_res;
op_sub: alu_datapath_res = add_sub_res;
op_sll: alu_datapath_res = sll_res;
op_srl: alu_datapath_res = srl_res;
op_sra: alu_datapath_res = sra_res;
op_slt: alu_datapath_res = slt_res;
op_sltu: alu_datapath_res = sltu_res;
endcase
end
assign alu_res_o = alu_datapath_res;
assign bjp_res_o = alu_datapath_res;
assign bjp_cmp_res_o = cmp_res_eq | cmp_res_neq | cmp_res_lt | cmp_res_ltu | cmp_res_gt | cmp_res_gtu;
assign {mux_op1,
mux_op2,
op_add,
op_sub,
op_sll,
op_slt,
op_sltu,
op_xor,
op_srl,
op_sra,
op_or,
op_and,
op_beq,
op_bne,
op_blt,
op_bltu,
op_bge,
op_bgeu
} = ({`DATAPATH_MUX_WIDTH{req_alu_i}} & {
alu_op1_i,
alu_op2_i,
alu_op_add_i,
alu_op_sub_i,
alu_op_sll_i,
alu_op_slt_i,
alu_op_sltu_i,
alu_op_xor_i,
alu_op_srl_i,
alu_op_sra_i,
alu_op_or_i,
alu_op_and_i,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0
}) |
({`DATAPATH_MUX_WIDTH{req_bjp_i}} & {
bjp_op1_i,
bjp_op2_i,
1'b1,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
bjp_op_beq_i,
bjp_op_bne_i,
bjp_op_blt_i,
bjp_op_bltu_i,
bjp_op_bge_i,
bjp_op_bgeu_i
}) |
({`DATAPATH_MUX_WIDTH{req_mem_i}} & {
mem_op1_i,
mem_op2_i,
1'b1,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0
}) |
({`DATAPATH_MUX_WIDTH{req_csr_i}} & {
csr_op1_i,
csr_op2_i,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
csr_csrrw_i | csr_csrrs_i,
csr_csrrc_i,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0,
1'b0
});
endmodule

92
rtl/core/exu_commit.sv Normal file
View File

@ -0,0 +1,92 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
module exu_commit(
input wire clk,
input wire rst_n,
input wire req_muldiv_i,
input wire muldiv_reg_we_i,
input wire[4:0] muldiv_reg_waddr_i,
input wire[31:0] muldiv_reg_wdata_i,
input wire req_mem_i,
input wire mem_reg_we_i,
input wire[4:0] mem_reg_waddr_i,
input wire[31:0] mem_reg_wdata_i,
input wire req_csr_i,
input wire csr_reg_we_i,
input wire[4:0] csr_reg_waddr_i,
input wire[31:0] csr_reg_wdata_i,
input wire req_bjp_i,
input wire bjp_reg_we_i,
input wire[31:0] bjp_reg_wdata_i,
input wire[4:0] bjp_reg_waddr_i,
input wire rd_we_i,
input wire[4:0] rd_waddr_i,
input wire[31:0] alu_reg_wdata_i,
output wire reg_we_o,
output wire[4:0] reg_waddr_o,
output wire[31:0] reg_wdata_o
);
wire use_alu_res = (~req_muldiv_i) &
(~req_mem_i) &
(~req_csr_i) &
(~req_bjp_i);
assign reg_we_o = muldiv_reg_we_i | mem_reg_we_i | csr_reg_we_i | use_alu_res | bjp_reg_we_i;
reg[4:0] reg_waddr;
always @ (*) begin
reg_waddr = 5'h0;
case (1'b1)
muldiv_reg_we_i: reg_waddr = muldiv_reg_waddr_i;
mem_reg_we_i: reg_waddr = mem_reg_waddr_i;
csr_reg_we_i: reg_waddr = csr_reg_waddr_i;
bjp_reg_we_i: reg_waddr = bjp_reg_waddr_i;
rd_we_i: reg_waddr = rd_waddr_i;
endcase
end
assign reg_waddr_o = reg_waddr;
reg[31:0] reg_wdata;
always @ (*) begin
reg_wdata = 32'h0;
case (1'b1)
muldiv_reg_we_i: reg_wdata = muldiv_reg_wdata_i;
mem_reg_we_i: reg_wdata = mem_reg_wdata_i;
csr_reg_we_i: reg_wdata = csr_reg_wdata_i;
bjp_reg_we_i: reg_wdata = bjp_reg_wdata_i;
use_alu_res: reg_wdata = alu_reg_wdata_i;
endcase
end
assign reg_wdata_o = reg_wdata;
endmodule

214
rtl/core/exu_dispatch.sv Normal file
View File

@ -0,0 +1,214 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
module exu_dispatch(
input wire clk,
input wire rst_n,
input wire[`DECINFO_WIDTH-1:0] dec_info_bus_i,
input wire[31:0] dec_imm_i,
input wire[31:0] dec_pc_i,
input wire[31:0] rs1_rdata_i,
input wire[31:0] rs2_rdata_i,
// dispatch to ALU
output wire req_alu_o,
output wire[31:0] alu_op1_o,
output wire[31:0] alu_op2_o,
output wire alu_op_lui_o,
output wire alu_op_auipc_o,
output wire alu_op_add_o,
output wire alu_op_sub_o,
output wire alu_op_sll_o,
output wire alu_op_slt_o,
output wire alu_op_sltu_o,
output wire alu_op_xor_o,
output wire alu_op_srl_o,
output wire alu_op_sra_o,
output wire alu_op_or_o,
output wire alu_op_and_o,
// dispatch to BJP
output wire req_bjp_o,
output wire[31:0] bjp_op1_o,
output wire[31:0] bjp_op2_o,
output wire[31:0] bjp_jump_op1_o,
output wire[31:0] bjp_jump_op2_o,
output wire bjp_op_jump_o,
output wire bjp_op_beq_o,
output wire bjp_op_bne_o,
output wire bjp_op_blt_o,
output wire bjp_op_bltu_o,
output wire bjp_op_bge_o,
output wire bjp_op_bgeu_o,
output wire bjp_op_jalr_o,
// dispatch to MULDIV
output wire req_muldiv_o,
output wire[31:0] muldiv_op1_o,
output wire[31:0] muldiv_op2_o,
output wire muldiv_op_mul_o,
output wire muldiv_op_mulh_o,
output wire muldiv_op_mulhsu_o,
output wire muldiv_op_mulhu_o,
output wire muldiv_op_div_o,
output wire muldiv_op_divu_o,
output wire muldiv_op_rem_o,
output wire muldiv_op_remu_o,
// dispatch to CSR
output wire req_csr_o,
output wire[31:0] csr_op1_o,
output wire[31:0] csr_addr_o,
output wire csr_csrrw_o,
output wire csr_csrrs_o,
output wire csr_csrrc_o,
// dispatch to MEM
output wire req_mem_o,
output wire[31:0] mem_op1_o,
output wire[31:0] mem_op2_o,
output wire[31:0] mem_rs2_data_o,
output wire mem_op_lb_o,
output wire mem_op_lh_o,
output wire mem_op_lw_o,
output wire mem_op_lbu_o,
output wire mem_op_lhu_o,
output wire mem_op_sb_o,
output wire mem_op_sh_o,
output wire mem_op_sw_o,
// dispatch to SYS
output wire sys_op_nop_o,
output wire sys_op_mret_o,
output wire sys_op_ecall_o,
output wire sys_op_ebreak_o,
output wire sys_op_fence_o,
output wire sys_op_dret_o
);
wire[`DECINFO_GRP_WIDTH-1:0] disp_info_grp = dec_info_bus_i[`DECINFO_GRP_BUS];
// ALU info
wire op_alu = (disp_info_grp == `DECINFO_GRP_ALU);
wire[`DECINFO_WIDTH-1:0] alu_info = {`DECINFO_WIDTH{op_alu}} & dec_info_bus_i;
// ALU op1
wire alu_op1_pc = alu_info[`DECINFO_ALU_OP1PC];
wire alu_op1_zero = alu_info[`DECINFO_ALU_LUI];
wire[31:0] alu_op1 = alu_op1_pc? dec_pc_i: alu_op1_zero? 32'h0: rs1_rdata_i;
assign alu_op1_o = op_alu? alu_op1: 32'h0;
// ALU op2
wire alu_op2_imm = alu_info[`DECINFO_ALU_OP2IMM];
wire[31:0] alu_op2 = alu_op2_imm? dec_imm_i: rs2_rdata_i;
assign alu_op2_o = op_alu? alu_op2: 32'h0;
assign alu_op_lui_o = alu_info[`DECINFO_ALU_LUI];
assign alu_op_auipc_o = alu_info[`DECINFO_ALU_AUIPC];
assign alu_op_add_o = alu_info[`DECINFO_ALU_ADD];
assign alu_op_sub_o = alu_info[`DECINFO_ALU_SUB];
assign alu_op_sll_o = alu_info[`DECINFO_ALU_SLL];
assign alu_op_slt_o = alu_info[`DECINFO_ALU_SLT];
assign alu_op_sltu_o = alu_info[`DECINFO_ALU_SLTU];
assign alu_op_xor_o = alu_info[`DECINFO_ALU_XOR];
assign alu_op_srl_o = alu_info[`DECINFO_ALU_SRL];
assign alu_op_sra_o = alu_info[`DECINFO_ALU_SRA];
assign alu_op_or_o = alu_info[`DECINFO_ALU_OR];
assign alu_op_and_o = alu_info[`DECINFO_ALU_AND];
assign req_alu_o = op_alu;
// BJP info
wire op_bjp = (disp_info_grp == `DECINFO_GRP_BJP);
wire[`DECINFO_WIDTH-1:0] bjp_info = {`DECINFO_WIDTH{op_bjp}} & dec_info_bus_i;
// BJP op1
wire bjp_op1_rs1 = bjp_info[`DECINFO_BJP_OP1RS1];
wire[31:0] bjp_op1 = bjp_op1_rs1? rs1_rdata_i: dec_pc_i;
assign bjp_jump_op1_o = op_bjp? bjp_op1: 32'h0;
// BJP op2
wire[31:0] bjp_op2 = dec_imm_i;
assign bjp_jump_op2_o = op_bjp? bjp_op2: 32'h0;
assign bjp_op1_o = op_bjp? rs1_rdata_i: 32'h0;
assign bjp_op2_o = op_bjp? rs2_rdata_i: 32'h0;
assign bjp_op_jump_o = bjp_info[`DECINFO_BJP_JUMP];
assign bjp_op_beq_o = bjp_info[`DECINFO_BJP_BEQ];
assign bjp_op_bne_o = bjp_info[`DECINFO_BJP_BNE];
assign bjp_op_blt_o = bjp_info[`DECINFO_BJP_BLT];
assign bjp_op_bltu_o = bjp_info[`DECINFO_BJP_BLTU];
assign bjp_op_bge_o = bjp_info[`DECINFO_BJP_BGE];
assign bjp_op_bgeu_o = bjp_info[`DECINFO_BJP_BGEU];
assign req_bjp_o = op_bjp;
assign bjp_op_jalr_o = bjp_op1_rs1;
// MULDIV info
wire op_muldiv = (disp_info_grp == `DECINFO_GRP_MULDIV);
wire[`DECINFO_WIDTH-1:0] muldiv_info = {`DECINFO_WIDTH{op_muldiv}} & dec_info_bus_i;
// MULDIV op1
assign muldiv_op1_o = op_muldiv? rs1_rdata_i: 32'h0;
// MULDIV op2
assign muldiv_op2_o = op_muldiv? rs2_rdata_i: 32'h0;
assign muldiv_op_mul_o = muldiv_info[`DECINFO_MULDIV_MUL];
assign muldiv_op_mulh_o = muldiv_info[`DECINFO_MULDIV_MULH];
assign muldiv_op_mulhu_o = muldiv_info[`DECINFO_MULDIV_MULHU];
assign muldiv_op_mulhsu_o = muldiv_info[`DECINFO_MULDIV_MULHSU];
assign muldiv_op_div_o = muldiv_info[`DECINFO_MULDIV_DIV];
assign muldiv_op_divu_o = muldiv_info[`DECINFO_MULDIV_DIVU];
assign muldiv_op_rem_o = muldiv_info[`DECINFO_MULDIV_REM];
assign muldiv_op_remu_o = muldiv_info[`DECINFO_MULDIV_REMU];
assign req_muldiv_o = op_muldiv;
// CSR info
wire op_csr = (disp_info_grp == `DECINFO_GRP_CSR);
wire[`DECINFO_WIDTH-1:0] csr_info = {`DECINFO_WIDTH{op_csr}} & dec_info_bus_i;
// CSR op1
wire csr_rs1imm = csr_info[`DECINFO_CSR_RS1IMM];
wire[31:0] csr_rs1 = csr_rs1imm? dec_imm_i: rs1_rdata_i;
assign csr_op1_o = op_csr? csr_rs1: 32'h0;
assign csr_addr_o = {{20{1'b0}}, csr_info[`DECINFO_CSR_CSRADDR]};
assign csr_csrrw_o = csr_info[`DECINFO_CSR_CSRRW];
assign csr_csrrs_o = csr_info[`DECINFO_CSR_CSRRS];
assign csr_csrrc_o = csr_info[`DECINFO_CSR_CSRRC];
assign req_csr_o = op_csr;
// MEM info
wire op_mem = (disp_info_grp == `DECINFO_GRP_MEM);
wire[`DECINFO_WIDTH-1:0] mem_info = {`DECINFO_WIDTH{op_mem}} & dec_info_bus_i;
assign mem_op_lb_o = mem_info[`DECINFO_MEM_LB];
assign mem_op_lh_o = mem_info[`DECINFO_MEM_LH];
assign mem_op_lw_o = mem_info[`DECINFO_MEM_LW];
assign mem_op_lbu_o = mem_info[`DECINFO_MEM_LBU];
assign mem_op_lhu_o = mem_info[`DECINFO_MEM_LHU];
assign mem_op_sb_o = mem_info[`DECINFO_MEM_SB];
assign mem_op_sh_o = mem_info[`DECINFO_MEM_SH];
assign mem_op_sw_o = mem_info[`DECINFO_MEM_SW];
assign mem_op1_o = op_mem? rs1_rdata_i: 32'h0;
assign mem_op2_o = op_mem? dec_imm_i: 32'h0;
assign mem_rs2_data_o = op_mem? rs2_rdata_i: 32'h0;
assign req_mem_o = op_mem;
// SYS info
wire op_sys = (disp_info_grp == `DECINFO_GRP_SYS);
wire[`DECINFO_WIDTH-1:0] sys_info = {`DECINFO_WIDTH{op_sys}} & dec_info_bus_i;
assign sys_op_nop_o = sys_info[`DECINFO_SYS_NOP];
assign sys_op_mret_o = sys_info[`DECINFO_SYS_MRET];
assign sys_op_ecall_o = sys_info[`DECINFO_SYS_ECALL];
assign sys_op_ebreak_o = sys_info[`DECINFO_SYS_EBREAK];
assign sys_op_fence_o = sys_info[`DECINFO_SYS_FENCE];
assign sys_op_dret_o = sys_info[`DECINFO_SYS_DRET];
endmodule

214
rtl/core/exu_mem.sv Normal file
View File

@ -0,0 +1,214 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
module exu_mem(
input wire clk,
input wire rst_n,
input req_mem_i,
input wire[31:0] mem_addr_i,
input wire[31:0] mem_rs2_data_i,
input wire[31:0] mem_rdata_i,
input wire mem_gnt_i,
input wire mem_rvalid_i,
input wire mem_op_lb_i,
input wire mem_op_lh_i,
input wire mem_op_lw_i,
input wire mem_op_lbu_i,
input wire mem_op_lhu_i,
input wire mem_op_sb_i,
input wire mem_op_sh_i,
input wire mem_op_sw_i,
output wire mem_access_misaligned_o,
output wire mem_stall_o,
output wire[31:0] mem_addr_o,
output wire[31:0] mem_wdata_o,
output wire mem_reg_we_o,
output wire mem_mem_we_o,
output wire[3:0] mem_be_o,
output wire mem_req_o
);
wire[1:0] mem_addr_index = mem_addr_i[1:0];
wire mem_addr_index00 = (mem_addr_index == 2'b00);
wire mem_addr_index01 = (mem_addr_index == 2'b01);
wire mem_addr_index10 = (mem_addr_index == 2'b10);
wire mem_addr_index11 = (mem_addr_index == 2'b11);
assign mem_be_o[0] = mem_addr_index00 | mem_op_sw_i;
assign mem_be_o[1] = mem_addr_index01 | (mem_op_sh_i & mem_addr_index00) | mem_op_sw_i;
assign mem_be_o[2] = mem_addr_index10 | mem_op_sw_i;
assign mem_be_o[3] = mem_addr_index11 | (mem_op_sh_i & mem_addr_index10) | mem_op_sw_i;
reg[31:0] sb_res;
always @ (*) begin
sb_res = 32'h0;
case (1'b1)
mem_addr_index00: sb_res = {24'h0, mem_rs2_data_i[7:0]};
mem_addr_index01: sb_res = {16'h0, mem_rs2_data_i[7:0], 8'h0};
mem_addr_index10: sb_res = {8'h0, mem_rs2_data_i[7:0], 16'h0};
mem_addr_index11: sb_res = {mem_rs2_data_i[7:0], 24'h0};
endcase
end
reg[31:0] sh_res;
always @ (*) begin
sh_res = 32'h0;
case (1'b1)
mem_addr_index00: sh_res = {16'h0, mem_rs2_data_i[15:0]};
mem_addr_index10: sh_res = {mem_rs2_data_i[15:0], 16'h0};
endcase
end
wire[31:0] sw_res = mem_rs2_data_i;
reg[31:0] lb_res;
always @ (*) begin
lb_res = 32'h0;
case (1'b1)
mem_addr_index00: lb_res = {{24{mem_op_lb_i & mem_rdata_i[7]}}, mem_rdata_i[7:0]};
mem_addr_index01: lb_res = {{24{mem_op_lb_i & mem_rdata_i[15]}}, mem_rdata_i[15:8]};
mem_addr_index10: lb_res = {{24{mem_op_lb_i & mem_rdata_i[23]}}, mem_rdata_i[23:16]};
mem_addr_index11: lb_res = {{24{mem_op_lb_i & mem_rdata_i[31]}}, mem_rdata_i[31:24]};
endcase
end
reg[31:0] lh_res;
always @ (*) begin
lh_res = 32'h0;
case (1'b1)
mem_addr_index00: lh_res = {{24{mem_op_lh_i & mem_rdata_i[15]}}, mem_rdata_i[15:0]};
mem_addr_index10: lh_res = {{24{mem_op_lh_i & mem_rdata_i[31]}}, mem_rdata_i[31:16]};
endcase
end
wire[31:0] lw_res = mem_rdata_i;
reg[31:0] mem_wdata;
always @ (*) begin
mem_wdata = 32'h0;
case (1'b1)
mem_op_sb_i: mem_wdata = sb_res;
mem_op_sh_i: mem_wdata = sh_res;
mem_op_sw_i: mem_wdata = sw_res;
mem_op_lb_i: mem_wdata = lb_res;
mem_op_lbu_i: mem_wdata = lb_res;
mem_op_lh_i: mem_wdata = lh_res;
mem_op_lhu_i: mem_wdata = lh_res;
mem_op_lw_i: mem_wdata = lw_res;
endcase
end
assign mem_wdata_o = mem_wdata;
wire op_load = mem_op_lb_i | mem_op_lh_i | mem_op_lw_i | mem_op_lbu_i | mem_op_lhu_i;
wire op_store = mem_op_sb_i | mem_op_sh_i | mem_op_sw_i;
localparam S_IDLE = 3'b001;
localparam S_WAIT_READ = 3'b010;
localparam S_WAIT_WRITE = 3'b100;
reg[2:0] state_d, state_q;
reg mem_stall_d;
reg mem_reg_we_d;
reg mem_mem_we_d;
reg req_mem_d;
// 访存状态机
always @ (*) begin
state_d = state_q;
mem_stall_d = 1'b0;
mem_reg_we_d = 1'b0;
mem_mem_we_d = 1'b0;
req_mem_d = 1'b0;
case (state_q)
S_IDLE: begin
if (req_mem_i) begin
mem_stall_d = 1'b1;
req_mem_d = 1'b1;
if (mem_gnt_i) begin
if (op_load) begin
state_d = S_WAIT_READ;
end else if (op_store) begin
state_d = S_WAIT_WRITE;
mem_mem_we_d = 1'b1;
end
end
end
end
// 读内存
S_WAIT_READ: begin
mem_stall_d = 1'b1;
if (mem_rvalid_i) begin
state_d = S_IDLE;
mem_reg_we_d = 1'b1;
mem_stall_d = 1'b0;
end
end
// 写内存
S_WAIT_WRITE: begin
mem_stall_d = 1'b1;
if (mem_rvalid_i) begin
state_d = S_IDLE;
mem_stall_d = 1'b0;
end
end
default: ;
endcase
end
// 访存请求
assign mem_req_o = req_mem_d;
// 访存地址
assign mem_addr_o = mem_addr_i;
// 暂停流水线
assign mem_stall_o = mem_stall_d;
// 写寄存器使能
assign mem_reg_we_o = mem_reg_we_d;
// 写内存使能
assign mem_mem_we_o = mem_mem_we_d;
assign mem_access_misaligned_o = (mem_op_sw_i | mem_op_lw_i)? (mem_addr_i[0] | mem_addr_i[1]):
(mem_op_sh_i | mem_op_lh_i | mem_op_lhu_i)? mem_addr_i[0]:
0;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= S_IDLE;
end else begin
state_q <= state_d;
end
end
endmodule

108
rtl/core/exu_muldiv.sv Normal file
View File

@ -0,0 +1,108 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
module exu_muldiv(
input wire clk,
input wire rst_n,
input wire[31:0] muldiv_op1_i,
input wire[31:0] muldiv_op2_i,
input wire muldiv_op_mul_i,
input wire muldiv_op_mulh_i,
input wire muldiv_op_mulhsu_i,
input wire muldiv_op_mulhu_i,
input wire muldiv_op_div_i,
input wire muldiv_op_divu_i,
input wire muldiv_op_rem_i,
input wire muldiv_op_remu_i,
input wire int_stall_i,
output wire[31:0] muldiv_reg_wdata_o,
output wire muldiv_reg_we_o,
output wire muldiv_stall_o
);
// 除法操作
wire op_div = muldiv_op_div_i | muldiv_op_divu_i | muldiv_op_rem_i | muldiv_op_remu_i;
wire div_start = op_div & (!div_ready) & (~int_stall_i);
wire[3:0] div_op = {muldiv_op_div_i, muldiv_op_divu_i, muldiv_op_rem_i, muldiv_op_remu_i};
wire[31:0] div_result;
wire div_ready;
divider u_divider(
.clk(clk),
.rst_n(rst_n),
.dividend_i(muldiv_op1_i),
.divisor_i(muldiv_op2_i),
.start_i(div_start),
.op_i(div_op),
.result_o(div_result),
.ready_o(div_ready)
);
// 乘法操作
wire op_mul = muldiv_op_mul_i | muldiv_op_mulh_i | muldiv_op_mulhsu_i | muldiv_op_mulhu_i;
wire[31:0] muldiv_op1_r;
gen_en_dff #(32) mul_op1_ff(clk, rst_n, op_mul, muldiv_op1_i, muldiv_op1_r);
wire[31:0] muldiv_op2_r;
gen_en_dff #(32) mul_op2_ff(clk, rst_n, op_mul, muldiv_op2_i, muldiv_op2_r);
wire mul_ready_r;
wire mul_ready = (~mul_ready_r) & op_mul;
gen_rst_0_dff #(1) mul_ready_ff(clk, rst_n, mul_ready, mul_ready_r);
wire mul_start = (~mul_ready_r) & op_mul;
wire op1_is_signed = muldiv_op1_r[31];
wire op2_is_signed = muldiv_op2_r[31];
wire[31:0] op1_complcode = op1_is_signed? (-muldiv_op1_r): muldiv_op1_r;
wire[31:0] op2_complcode = op2_is_signed? (-muldiv_op2_r): muldiv_op2_r;
wire[31:0] op1_mul = ({32{(muldiv_op_mul_i | muldiv_op_mulhu_i)}} & muldiv_op1_r) |
({32{(muldiv_op_mulh_i | muldiv_op_mulhsu_i)}} & op1_complcode);
wire[31:0] op2_mul = ({32{(muldiv_op_mul_i | muldiv_op_mulhu_i | muldiv_op_mulhsu_i)}} & muldiv_op2_r) |
({32{(muldiv_op_mulh_i)}} & op2_complcode);
wire[63:0] mul_res_tmp = op1_mul * op2_mul;
wire[63:0] mul_res_tmp_complcode = -mul_res_tmp;
wire[31:0] mul_res = mul_res_tmp[31:0];
wire[31:0] mulhu_res = mul_res_tmp[63:32];
wire[31:0] mulh_res = (op1_is_signed ^ op2_is_signed)? mul_res_tmp_complcode[63:32]: mul_res_tmp[63:32];
wire[31:0] mulhsu_res = (op1_is_signed)? mul_res_tmp_complcode[63:32]: mul_res_tmp[63:32];
reg[31:0] mul_op_res;
always @ (*) begin
mul_op_res = 32'h0;
case (1'b1)
muldiv_op_mul_i: mul_op_res = mul_res;
muldiv_op_mulhu_i: mul_op_res = mulhu_res;
muldiv_op_mulh_i: mul_op_res = mulh_res;
muldiv_op_mulhsu_i: mul_op_res = mulhsu_res;
endcase
end
// 运算结果
assign muldiv_reg_wdata_o = div_result | mul_op_res;
assign muldiv_reg_we_o = div_ready | mul_ready_r;
assign muldiv_stall_o = div_start | mul_start;
endmodule

92
rtl/core/gpr_reg.sv Normal file
View File

@ -0,0 +1,92 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// 通用寄存器模块
module gpr_reg(
input wire clk,
input wire rst_n,
input wire we_i, // 写寄存器使能
input wire[4:0] waddr_i, // 写寄存器地址
input wire[31:0] wdata_i, // 写寄存器数据
input wire[4:0] raddr1_i, // 读寄存器1地址
output wire[31:0] rdata1_o, // 读寄存器1数据
input wire[4:0] raddr2_i, // 读寄存器2地址
output wire[31:0] rdata2_o // 读寄存器2数据
);
wire[32-1:0] regs[32-1:0];
wire[32-1:0] we;
genvar i;
generate
for (i = 0; i < 32; i = i + 1) begin: gpr_rw
// x0 cannot be wrote since it is constant-zeros
if (i == 0) begin: is_x0
assign we[i] = 1'b0;
assign regs[i] = 32'h0;
end else begin: not_x0
assign we[i] = we_i & (waddr_i == i);
gen_en_dffnr #(32) rf_dff(clk, we[i], wdata_i, regs[i]);
end
end
endgenerate
assign rdata1_o = (|raddr1_i)? ((we_i & (waddr_i == raddr1_i))? wdata_i: regs[raddr1_i]): 32'h0;
assign rdata2_o = (|raddr2_i)? ((we_i & (waddr_i == raddr2_i))? wdata_i: regs[raddr2_i]): 32'h0;
// for debug
wire[31:0] ra = regs[1];
wire[31:0] sp = regs[2];
wire[31:0] gp = regs[3];
wire[31:0] tp = regs[4];
wire[31:0] t0 = regs[5];
wire[31:0] t1 = regs[6];
wire[31:0] t2 = regs[7];
wire[31:0] s0 = regs[8];
wire[31:0] fp = regs[8];
wire[31:0] s1 = regs[9];
wire[31:0] a0 = regs[10];
wire[31:0] a1 = regs[11];
wire[31:0] a2 = regs[12];
wire[31:0] a3 = regs[13];
wire[31:0] a4 = regs[14];
wire[31:0] a5 = regs[15];
wire[31:0] a6 = regs[16];
wire[31:0] a7 = regs[17];
wire[31:0] s2 = regs[18];
wire[31:0] s3 = regs[19];
wire[31:0] s4 = regs[20];
wire[31:0] s5 = regs[21];
wire[31:0] s6 = regs[22];
wire[31:0] s7 = regs[23];
wire[31:0] s8 = regs[24];
wire[31:0] s9 = regs[25];
wire[31:0] s10 = regs[26];
wire[31:0] s11 = regs[27];
wire[31:0] t3 = regs[28];
wire[31:0] t4 = regs[29];
wire[31:0] t5 = regs[30];
wire[31:0] t6 = regs[31];
endmodule

View File

@ -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

View File

@ -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

316
rtl/core/idu.sv Normal file
View File

@ -0,0 +1,316 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// 译码模块
// 纯组合逻辑电路
module idu(
input wire clk, // 时钟
input wire rst_n, // 复位
// from ifu_idu
input wire[31:0] inst_i, // 指令内容
input wire[31:0] inst_addr_i, // 指令地址
input wire inst_valid_i, // 指令有效
// from gpr_reg
input wire[31:0] rs1_rdata_i, // 通用寄存器1输入数据
input wire[31:0] rs2_rdata_i, // 通用寄存器2输入数据
output wire stall_o, // 流水线暂停
output wire illegal_inst_o, // 非法指令
// to gpr_reg
output wire[4:0] rs1_raddr_o, // 寄存器1地址
output wire[4:0] rs2_raddr_o, // 寄存器2地址
// to idu_exu
output wire inst_valid_o, // 指令有效
output wire[31:0] inst_o, // 指令内容
output wire[`DECINFO_WIDTH-1:0] dec_info_bus_o, // 译码信息
output wire[31:0] dec_imm_o, // 立即数
output wire[31:0] dec_pc_o, // 指令地址
output wire[31:0] rs1_rdata_o, // 寄存器1数据
output wire[31:0] rs2_rdata_o, // 寄存器2数据
output wire[4:0] rd_waddr_o, // 写寄存器地址
output wire rd_we_o // 写寄存器使能
);
wire[31:0] inst = inst_valid_i? inst_i: `INST_NOP;
assign inst_valid_o = inst_valid_i;
assign inst_o = inst;
assign rs1_rdata_o = rs1_rdata_i;
assign rs2_rdata_o = rs2_rdata_i;
// 取出指令中的每一个域
wire[6:0] opcode = inst[6:0];
wire[2:0] funct3 = inst[14:12];
wire[6:0] funct7 = inst[31:25];
wire[4:0] rd = inst[11:7];
wire[4:0] rs1 = inst[19:15];
wire[4:0] rs2 = inst[24:20];
wire[11:0] type_i_imm_11_0 = inst[31:20];
wire[6:0] type_s_imm_11_5 = inst[31:25];
wire[4:0] type_s_imm_4_0 = inst[11:7];
wire[6:0] type_b_imm_12_10_5 = inst[31:25];
wire[4:0] type_b_imm_4_1_11 = inst[11:7];
wire[19:0] type_u_imm_31_12 = inst[31:12];
wire[19:0] type_j_imm_31_12 = inst[31:12];
// 指令opcode域的取值
wire opcode_0110111 = (opcode == 7'b0110111);
wire opcode_0010111 = (opcode == 7'b0010111);
wire opcode_1101111 = (opcode == 7'b1101111);
wire opcode_1100111 = (opcode == 7'b1100111);
wire opcode_1100011 = (opcode == 7'b1100011);
wire opcode_0000011 = (opcode == 7'b0000011);
wire opcode_0100011 = (opcode == 7'b0100011);
wire opcode_0010011 = (opcode == 7'b0010011);
wire opcode_0110011 = (opcode == 7'b0110011);
wire opcode_0001111 = (opcode == 7'b0001111);
wire opcode_1110011 = (opcode == 7'b1110011);
// 指令funct3域的取值
wire funct3_000 = (funct3 == 3'b000);
wire funct3_001 = (funct3 == 3'b001);
wire funct3_010 = (funct3 == 3'b010);
wire funct3_011 = (funct3 == 3'b011);
wire funct3_100 = (funct3 == 3'b100);
wire funct3_101 = (funct3 == 3'b101);
wire funct3_110 = (funct3 == 3'b110);
wire funct3_111 = (funct3 == 3'b111);
// 指令funct7域的取值
wire funct7_0000000 = (funct7 == 7'b0000000);
wire funct7_0100000 = (funct7 == 7'b0100000);
wire funct7_0000001 = (funct7 == 7'b0000001);
// I类型指令imm域的取值
wire type_i_imm_000000000000 = (type_i_imm_11_0 == 12'b000000000000);
wire type_i_imm_000000000001 = (type_i_imm_11_0 == 12'b000000000001);
// 译码出具体指令
wire inst_lui = opcode_0110111;
wire inst_auipc = opcode_0010111;
wire inst_jal = opcode_1101111;
wire inst_jalr = opcode_1100111 & funct3_000;
wire inst_beq = opcode_1100011 & funct3_000;
wire inst_bne = opcode_1100011 & funct3_001;
wire inst_blt = opcode_1100011 & funct3_100;
wire inst_bge = opcode_1100011 & funct3_101;
wire inst_bltu = opcode_1100011 & funct3_110;
wire inst_bgeu = opcode_1100011 & funct3_111;
wire inst_lb = opcode_0000011 & funct3_000;
wire inst_lh = opcode_0000011 & funct3_001;
wire inst_lw = opcode_0000011 & funct3_010;
wire inst_lbu = opcode_0000011 & funct3_100;
wire inst_lhu = opcode_0000011 & funct3_101;
wire inst_sb = opcode_0100011 & funct3_000;
wire inst_sh = opcode_0100011 & funct3_001;
wire inst_sw = opcode_0100011 & funct3_010;
wire inst_addi = opcode_0010011 & funct3_000;
wire inst_slti = opcode_0010011 & funct3_010;
wire inst_sltiu = opcode_0010011 & funct3_011;
wire inst_xori = opcode_0010011 & funct3_100;
wire inst_ori = opcode_0010011 & funct3_110;
wire inst_andi = opcode_0010011 & funct3_111;
wire inst_slli = opcode_0010011 & funct3_001 & funct7_0000000;
wire inst_srli = opcode_0010011 & funct3_101 & funct7_0000000;
wire inst_srai = opcode_0010011 & funct3_101 & funct7_0100000;
wire inst_add = opcode_0110011 & funct3_000 & funct7_0000000;
wire inst_sub = opcode_0110011 & funct3_000 & funct7_0100000;
wire inst_sll = opcode_0110011 & funct3_001 & funct7_0000000;
wire inst_slt = opcode_0110011 & funct3_010 & funct7_0000000;
wire inst_sltu = opcode_0110011 & funct3_011 & funct7_0000000;
wire inst_xor = opcode_0110011 & funct3_100 & funct7_0000000;
wire inst_srl = opcode_0110011 & funct3_101 & funct7_0000000;
wire inst_sra = opcode_0110011 & funct3_101 & funct7_0100000;
wire inst_or = opcode_0110011 & funct3_110 & funct7_0000000;
wire inst_and = opcode_0110011 & funct3_111 & funct7_0000000;
wire inst_fence = opcode_0001111 & funct3_000;
wire inst_ecall = (inst == `INST_ECALL);
wire inst_ebreak = (inst == `INST_EBREAK);
wire inst_fence_i = opcode_0001111 & funct3_001;
wire inst_csrrw = opcode_1110011 & funct3_001;
wire inst_csrrs = opcode_1110011 & funct3_010;
wire inst_csrrc = opcode_1110011 & funct3_011;
wire inst_csrrwi = opcode_1110011 & funct3_101;
wire inst_csrrsi = opcode_1110011 & funct3_110;
wire inst_csrrci = opcode_1110011 & funct3_111;
wire inst_mul = opcode_0110011 & funct3_000 & funct7_0000001;
wire inst_mulh = opcode_0110011 & funct3_001 & funct7_0000001;
wire inst_mulhsu = opcode_0110011 & funct3_010 & funct7_0000001;
wire inst_mulhu = opcode_0110011 & funct3_011 & funct7_0000001;
wire inst_div = opcode_0110011 & funct3_100 & funct7_0000001;
wire inst_divu = opcode_0110011 & funct3_101 & funct7_0000001;
wire inst_rem = opcode_0110011 & funct3_110 & funct7_0000001;
wire inst_remu = opcode_0110011 & funct3_111 & funct7_0000001;
wire inst_nop = (inst == `INST_NOP);
wire inst_mret = (inst == `INST_MRET);
wire inst_dret = (inst == `INST_DRET);
// 将指令分类
wire inst_type_load = opcode_0000011;
wire inst_type_store = opcode_0100011;
wire inst_type_branch = opcode_1100011;
wire inst_type_muldiv = inst_mul | inst_mulh | inst_mulhsu | inst_mulhu | inst_div | inst_divu | inst_rem | inst_remu;
wire inst_type_div = inst_div | inst_divu | inst_rem | inst_remu;
wire[`DECINFO_ALU_BUS_WIDTH-1:0] dec_alu_info_bus;
assign dec_alu_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_ALU;
assign dec_alu_info_bus[`DECINFO_ALU_LUI] = inst_lui;
assign dec_alu_info_bus[`DECINFO_ALU_AUIPC] = inst_auipc;
assign dec_alu_info_bus[`DECINFO_ALU_ADD] = inst_add | inst_addi;
assign dec_alu_info_bus[`DECINFO_ALU_SUB] = inst_sub;
assign dec_alu_info_bus[`DECINFO_ALU_SLL] = inst_sll | inst_slli;
assign dec_alu_info_bus[`DECINFO_ALU_SLT] = inst_slt | inst_slti;
assign dec_alu_info_bus[`DECINFO_ALU_SLTU] = inst_sltu | inst_sltiu;
assign dec_alu_info_bus[`DECINFO_ALU_XOR] = inst_xor | inst_xori;
assign dec_alu_info_bus[`DECINFO_ALU_SRL] = inst_srl | inst_srli;
assign dec_alu_info_bus[`DECINFO_ALU_SRA] = inst_sra | inst_srai;
assign dec_alu_info_bus[`DECINFO_ALU_OR] = inst_or | inst_ori;
assign dec_alu_info_bus[`DECINFO_ALU_AND] = inst_and | inst_andi;
assign dec_alu_info_bus[`DECINFO_ALU_OP2IMM] = opcode_0010011 | inst_lui | inst_auipc;
assign dec_alu_info_bus[`DECINFO_ALU_OP1PC] = inst_auipc;
wire[`DECINFO_BJP_BUS_WIDTH-1:0] dec_bjp_info_bus;
assign dec_bjp_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_BJP;
assign dec_bjp_info_bus[`DECINFO_BJP_JUMP] = inst_jal | inst_jalr;
assign dec_bjp_info_bus[`DECINFO_BJP_BEQ] = inst_beq;
assign dec_bjp_info_bus[`DECINFO_BJP_BNE] = inst_bne;
assign dec_bjp_info_bus[`DECINFO_BJP_BLT] = inst_blt;
assign dec_bjp_info_bus[`DECINFO_BJP_BGE] = inst_bge;
assign dec_bjp_info_bus[`DECINFO_BJP_BLTU] = inst_bltu;
assign dec_bjp_info_bus[`DECINFO_BJP_BGEU] = inst_bgeu;
assign dec_bjp_info_bus[`DECINFO_BJP_OP1RS1] = inst_jalr;
wire[`DECINFO_MULDIV_BUS_WIDTH-1:0] dec_muldiv_info_bus;
assign dec_muldiv_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_MULDIV;
assign dec_muldiv_info_bus[`DECINFO_MULDIV_MUL] = inst_mul;
assign dec_muldiv_info_bus[`DECINFO_MULDIV_MULH] = inst_mulh;
assign dec_muldiv_info_bus[`DECINFO_MULDIV_MULHSU] = inst_mulhsu;
assign dec_muldiv_info_bus[`DECINFO_MULDIV_MULHU] = inst_mulhu;
assign dec_muldiv_info_bus[`DECINFO_MULDIV_DIV] = inst_div;
assign dec_muldiv_info_bus[`DECINFO_MULDIV_DIVU] = inst_divu;
assign dec_muldiv_info_bus[`DECINFO_MULDIV_REM] = inst_rem;
assign dec_muldiv_info_bus[`DECINFO_MULDIV_REMU] = inst_remu;
wire[`DECINFO_CSR_BUS_WIDTH-1:0] dec_csr_info_bus;
assign dec_csr_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_CSR;
assign dec_csr_info_bus[`DECINFO_CSR_CSRRW] = inst_csrrw | inst_csrrwi;
assign dec_csr_info_bus[`DECINFO_CSR_CSRRS] = inst_csrrs | inst_csrrsi;
assign dec_csr_info_bus[`DECINFO_CSR_CSRRC] = inst_csrrc | inst_csrrci;
assign dec_csr_info_bus[`DECINFO_CSR_RS1IMM] = inst_csrrwi | inst_csrrsi | inst_csrrci;
assign dec_csr_info_bus[`DECINFO_CSR_CSRADDR] = inst[31:20];
wire[`DECINFO_MEM_BUS_WIDTH-1:0] dec_mem_info_bus;
assign dec_mem_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_MEM;
assign dec_mem_info_bus[`DECINFO_MEM_LB] = inst_lb;
assign dec_mem_info_bus[`DECINFO_MEM_LH] = inst_lh;
assign dec_mem_info_bus[`DECINFO_MEM_LW] = inst_lw;
assign dec_mem_info_bus[`DECINFO_MEM_LBU] = inst_lbu;
assign dec_mem_info_bus[`DECINFO_MEM_LHU] = inst_lhu;
assign dec_mem_info_bus[`DECINFO_MEM_SB] = inst_sb;
assign dec_mem_info_bus[`DECINFO_MEM_SH] = inst_sh;
assign dec_mem_info_bus[`DECINFO_MEM_SW] = inst_sw;
wire[`DECINFO_SYS_BUS_WIDTH-1:0] dec_sys_info_bus;
assign dec_sys_info_bus[`DECINFO_GRP_BUS] = `DECINFO_GRP_SYS;
assign dec_sys_info_bus[`DECINFO_SYS_ECALL] = inst_ecall;
assign dec_sys_info_bus[`DECINFO_SYS_EBREAK] = inst_ebreak;
assign dec_sys_info_bus[`DECINFO_SYS_NOP] = inst_nop;
assign dec_sys_info_bus[`DECINFO_SYS_MRET] = inst_mret;
assign dec_sys_info_bus[`DECINFO_SYS_DRET] = inst_dret;
assign dec_sys_info_bus[`DECINFO_SYS_FENCE] = inst_fence | inst_fence_i;
// 指令中的立即数
wire[31:0] inst_u_type_imm = {inst[31:12], 12'b0};
wire[31:0] inst_j_type_imm = {{12{inst[31]}}, inst[19:12], inst[20], inst[30:21], 1'b0};
wire[31:0] inst_b_type_imm = {{20{inst[31]}}, inst[7], inst[30:25], inst[11:8], 1'b0};
wire[31:0] inst_s_type_imm = {{20{inst[31]}}, inst[31:25], inst[11:7]};
wire[31:0] inst_i_type_imm = {{20{inst[31]}}, inst[31:20]};
wire[31:0] inst_csr_type_imm = {27'h0, inst[19:15]};
wire[31:0] inst_shift_type_imm = {27'h0, inst[24:20]};
wire inst_sel_u_imm = inst_lui | inst_auipc;
wire inst_sel_j_imm = inst_jal;
wire inst_sel_b_imm = inst_type_branch;
wire inst_sel_s_imm = inst_type_store;
wire inst_sel_i_imm = inst_addi | inst_slti | inst_sltiu | inst_xori | inst_ori | inst_andi | inst_type_load | inst_jalr;
wire inst_sel_csr_imm = inst_csrrwi | inst_csrrsi | inst_csrrci;
wire inst_sel_shift_imm = inst_slli | inst_srli | inst_srai;
assign dec_imm_o = ({32{inst_sel_u_imm}} & inst_u_type_imm) |
({32{inst_sel_j_imm}} & inst_j_type_imm) |
({32{inst_sel_b_imm}} & inst_b_type_imm) |
({32{inst_sel_s_imm}} & inst_s_type_imm) |
({32{inst_sel_i_imm}} & inst_i_type_imm) |
({32{inst_sel_csr_imm}} & inst_csr_type_imm) |
({32{inst_sel_shift_imm}} & inst_shift_type_imm);
wire op_alu = inst_lui | inst_auipc | opcode_0010011 | (opcode_0110011 & (~inst_type_muldiv));
wire op_bjp = inst_jal | inst_jalr | inst_type_branch;
wire op_muldiv = inst_type_muldiv;
wire op_csr = inst_csrrw | inst_csrrwi | inst_csrrs | inst_csrrsi | inst_csrrc | inst_csrrci;
wire op_sys = inst_ebreak | inst_ecall | inst_nop | inst_mret | inst_fence | inst_fence_i | inst_dret;
wire op_mem = inst_type_load | inst_type_store;
assign dec_info_bus_o = ({`DECINFO_WIDTH{op_alu}} & {{`DECINFO_WIDTH-`DECINFO_ALU_BUS_WIDTH{1'b0}}, dec_alu_info_bus}) |
({`DECINFO_WIDTH{op_bjp}} & {{`DECINFO_WIDTH-`DECINFO_BJP_BUS_WIDTH{1'b0}}, dec_bjp_info_bus}) |
({`DECINFO_WIDTH{op_muldiv}} & {{`DECINFO_WIDTH-`DECINFO_MULDIV_BUS_WIDTH{1'b0}}, dec_muldiv_info_bus}) |
({`DECINFO_WIDTH{op_csr}} & {{`DECINFO_WIDTH-`DECINFO_CSR_BUS_WIDTH{1'b0}}, dec_csr_info_bus}) |
({`DECINFO_WIDTH{op_mem}} & {{`DECINFO_WIDTH-`DECINFO_MEM_BUS_WIDTH{1'b0}}, dec_mem_info_bus}) |
({`DECINFO_WIDTH{op_sys}} & {{`DECINFO_WIDTH-`DECINFO_SYS_BUS_WIDTH{1'b0}}, dec_sys_info_bus});
assign dec_pc_o = inst_addr_i;
// 是否需要访问rs1寄存器
wire access_rs1 = (~inst_lui) &
(~inst_auipc) &
(~inst_jal) &
(~inst_ecall) &
(~inst_ebreak) &
(~inst_csrrwi) &
(~inst_csrrsi) &
(~inst_csrrci) &
(~inst_nop) &
(~inst_fence) &
(~inst_fence_i) &
(~inst_mret);
assign rs1_raddr_o = access_rs1? rs1: 5'h0;
// 是否需要访问rs2寄存器
wire access_rs2 = opcode_0110011 | inst_type_store | inst_type_branch;
assign rs2_raddr_o = access_rs2? rs2: 5'h0;
// 是否需要访问rd寄存器
wire access_rd = inst_lui | inst_auipc | inst_jal | inst_jalr | inst_type_load | opcode_0010011 | opcode_0110011 | op_csr;
assign rd_waddr_o = access_rd? rd: 5'h0;
assign rd_we_o = access_rd;
assign stall_o = 1'b0;
//assign illegal_inst_o = ~(|dec_info_bus_o);
assign illegal_inst_o = 1'b0;
endmodule

99
rtl/core/idu_exu.sv Normal file
View File

@ -0,0 +1,99 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// 将译码结果向执行模块传递
module idu_exu(
input wire clk, // 时钟
input wire rst_n, // 复位
input wire[`STALL_WIDTH-1:0] stall_i, // 流水线暂停
input wire flush_i, // 流水线冲刷
// 输入
input wire[31:0] inst_i,
input wire inst_valid_i,
input wire[`DECINFO_WIDTH-1:0] dec_info_bus_i,
input wire[31:0] dec_imm_i,
input wire[31:0] dec_pc_i,
input wire[31:0] rs1_rdata_i,
input wire[31:0] rs2_rdata_i,
input wire[4:0] rd_waddr_i,
input wire rd_we_i,
// 输出
output wire[31:0] inst_o,
output wire inst_valid_o,
output wire[`DECINFO_WIDTH-1:0] dec_info_bus_o,
output wire[31:0] dec_imm_o,
output wire[31:0] dec_pc_o,
output wire[31:0] rs1_rdata_o,
output wire[31:0] rs2_rdata_o,
output wire[4:0] rd_waddr_o,
output wire rd_we_o
);
wire en = (~stall_i[`STALL_EX]) | flush_i;
wire[`DECINFO_WIDTH-1:0] i_dec_info_bus = flush_i? {`DECINFO_WIDTH{1'b0}}: dec_info_bus_i;
wire[`DECINFO_WIDTH-1:0] dec_info_bus;
gen_en_dff #(`DECINFO_WIDTH) info_bus_ff(clk, rst_n, en, i_dec_info_bus, dec_info_bus);
assign dec_info_bus_o = dec_info_bus;
wire[31:0] i_dec_imm = flush_i? 32'h0: dec_imm_i;
wire[31:0] dec_imm;
gen_en_dff #(32) imm_ff(clk, rst_n, en, i_dec_imm, dec_imm);
assign dec_imm_o = dec_imm;
wire[31:0] i_dec_pc = flush_i? 32'h0: dec_pc_i;
wire[31:0] dec_pc;
gen_en_dff #(32) pc_ff(clk, rst_n, en, i_dec_pc, dec_pc);
assign dec_pc_o = dec_pc;
wire[31:0] i_rs1_rdata = flush_i? 32'h0: rs1_rdata_i;
wire[31:0] rs1_rdata;
gen_en_dff #(32) rs1_rdata_ff(clk, rst_n, en, i_rs1_rdata, rs1_rdata);
assign rs1_rdata_o = rs1_rdata;
wire[31:0] i_rs2_rdata = flush_i? 32'h0: rs2_rdata_i;
wire[31:0] rs2_rdata;
gen_en_dff #(32) rs2_rdata_ff(clk, rst_n, en, i_rs2_rdata, rs2_rdata);
assign rs2_rdata_o = rs2_rdata;
wire[4:0] i_rd_waddr = flush_i? 5'h0: rd_waddr_i;
wire[4:0] rd_waddr;
gen_en_dff #(5) rd_waddr_ff(clk, rst_n, en, i_rd_waddr, rd_waddr);
assign rd_waddr_o = rd_waddr;
wire i_rd_we = flush_i? 1'b0: rd_we_i;
wire rd_we;
gen_en_dff #(1) rd_we_ff(clk, rst_n, en, i_rd_we, rd_we);
assign rd_we_o = rd_we;
wire[31:0] i_inst = flush_i? `INST_NOP: inst_i;
wire[31:0] inst;
gen_en_dff #(32) inst_ff(clk, rst_n, en, i_inst, inst);
assign inst_o = inst;
wire i_inst_valid = flush_i? 1'b0: inst_valid_i;
wire inst_valid;
gen_en_dff #(1) inst_valid_ff(clk, rst_n, en, i_inst_valid, inst_valid);
assign inst_valid_o = inst_valid;
endmodule

View File

@ -1,52 +0,0 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.v"
//
module if_id(
input wire clk,
input wire rst,
input wire[`InstBus] inst_i, //
input wire[`InstAddrBus] inst_addr_i, //
input wire[`Hold_Flag_Bus] hold_flag_i, // 线
input wire[`INT_BUS] int_flag_i, //
output wire[`INT_BUS] int_flag_o,
output wire[`InstBus] inst_o, //
output wire[`InstAddrBus] inst_addr_o //
);
wire hold_en = (hold_flag_i >= `Hold_If);
wire[`InstBus] inst;
gen_pipe_dff #(32) inst_ff(clk, rst, hold_en, `INST_NOP, inst_i, inst);
assign inst_o = inst;
wire[`InstAddrBus] inst_addr;
gen_pipe_dff #(32) inst_addr_ff(clk, rst, hold_en, `ZeroWord, inst_addr_i, inst_addr);
assign inst_addr_o = inst_addr;
wire[`INT_BUS] int_flag;
gen_pipe_dff #(8) int_ff(clk, rst, hold_en, `INT_NONE, int_flag_i, int_flag);
assign int_flag_o = int_flag;
endmodule

155
rtl/core/ifu.sv Normal file
View File

@ -0,0 +1,155 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// 取指模块
module ifu #(
parameter bit BranchPredictor = 1'b1
)(
input wire clk,
input wire rst_n,
input wire flush_i, // 冲刷标志
input wire[31:0] flush_addr_i, // 冲刷地址
input wire[`STALL_WIDTH-1:0] stall_i, // 流水线暂停标志
input wire id_ready_i, // ID模块可以接收指令
// to ifu_idu
output wire[31:0] inst_o,
output wire[31:0] pc_o,
output wire inst_valid_o,
// 指令总线信号
output wire instr_req_o,
input wire instr_gnt_i,
input wire instr_rvalid_i,
output wire[31:0] instr_addr_o,
input wire[31:0] instr_rdata_i,
input wire instr_err_i
);
localparam S_RESET = 3'b001;
localparam S_FETCH = 3'b010;
localparam S_VALID = 3'b100;
reg[2:0] state_d, state_q;
wire inst_valid;
wire req_valid;
wire[31:0] fetch_addr_n;
reg[31:0] fetch_addr_q;
reg inst_valid_d;
reg instr_req_d;
wire prdt_taken;
wire[31:0] prdt_addr;
// 取指请求有效
assign req_valid = instr_gnt_i;
// 状态切换
// 取指模块需要实现连续不断地取指
always @ (*) begin
state_d = state_q;
inst_valid_d = 0;
instr_req_d = 1'b0;
case (state_q)
// 复位
S_RESET: begin
// 复位撤销后转到取指状态
if (rst_n) begin
state_d = S_FETCH;
end
end
// 取指
S_FETCH: begin
instr_req_d = 1'b1;
// 取指有效
if (req_valid) begin
state_d = S_VALID;
end
end
// 指令有效
S_VALID: begin
if (instr_rvalid_i | flush_i) begin
if (instr_rvalid_i) begin
inst_valid_d = 1'b1;
end
instr_req_d = 1'b1;
if (~req_valid) begin
state_d = S_FETCH;
end
end
end
default: ;
endcase
end
// 指令有效
assign inst_valid = inst_valid_d & id_ready_i;
assign inst_valid_o = inst_valid;
// 指令无效时用nop指令代替
assign inst_o = inst_valid ? instr_rdata_i: `INST_NOP;
assign pc_o = fetch_addr_q;
// 更新取指地址
assign fetch_addr_n = flush_i ? flush_addr_i:
prdt_taken ? prdt_addr:
inst_valid ? fetch_addr_q + 4'h4:
fetch_addr_q;
// 取指请求
assign instr_req_o = instr_req_d;
// 取指地址(4字节对齐)
assign instr_addr_o = {fetch_addr_n[31:2], 2'b00};
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= S_RESET;
fetch_addr_q <= `CPU_RESET_ADDR;
end else begin
state_q <= state_d;
// 取指有效时保存当前取指地址
if (req_valid | flush_i) begin
fetch_addr_q <= fetch_addr_n;
end
end
end
// 分支预测
if (BranchPredictor) begin: g_branch_predictor
bpu u_bpu(
.clk(clk),
.rst_n(rst_n),
.inst_i(inst_o),
.inst_valid_i(inst_valid_o),
.pc_i(pc_o),
.prdt_taken_o(prdt_taken),
.prdt_addr_o(prdt_addr)
);
end else begin: g_no_branch_predictor
assign prdt_taken = 1'b0;
assign prdt_addr = 32'h0;
end
endmodule

62
rtl/core/ifu_idu.sv Normal file
View File

@ -0,0 +1,62 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// 将指令信息向译码模块(通过寄存器)传递
module ifu_idu(
input wire clk, // 时钟
input wire rst_n, // 复位
input wire[`STALL_WIDTH-1:0] stall_i, // 流水线暂停
input wire flush_i, // 流水线冲刷
input wire[31:0] inst_i, // 指令内容
input wire[31:0] inst_addr_i, // 指令地址
input wire inst_valid_i, // 指令有效
output wire ready_o, // 可以接收指令
output wire[31:0] inst_o, // 指令内容
output wire[31:0] inst_addr_o, // 指令地址
output wire inst_valid_o // 指令有效
);
// 使能信号,只要流水线不暂停就传递
wire en = (~stall_i[`STALL_ID]) | flush_i;
assign ready_o = en;
// 指令内容传递冲刷或指令无效时传递NOP指令
wire[31:0] i_inst = (flush_i | (~inst_valid_i))? `INST_NOP: inst_i;
wire[31:0] inst;
gen_en_dff #(32) inst_ff(clk, rst_n, en, i_inst, inst);
assign inst_o = inst;
// 指令地址传递
wire[31:0] i_inst_addr = flush_i? 32'h0: inst_addr_i;
wire[31:0] inst_addr;
gen_en_dff #(32) inst_addr_ff(clk, rst_n, en, i_inst_addr, inst_addr);
assign inst_addr_o = inst_addr;
// 指令有效性传递,冲刷时无效
wire i_inst_valid = flush_i? 1'b0: inst_valid_i;
wire inst_valid;
gen_en_dff #(1) inst_valid_ff(clk, rst_n, en, i_inst_valid, inst_valid);
assign inst_valid_o = inst_valid;
endmodule

72
rtl/core/pipe_ctrl.sv Normal file
View File

@ -0,0 +1,72 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// 流水线控制模块
// 发出暂停、冲刷流水线信号
module pipe_ctrl(
input wire clk,
input wire rst_n,
input wire stall_from_id_i,
input wire stall_from_ex_i,
input wire stall_from_jtag_i,
input wire stall_from_clint_i,
input wire jump_assert_i,
input wire[31:0] jump_addr_i,
output wire flush_o, // 冲刷标志
output wire[`STALL_WIDTH-1:0] stall_o, // 暂停标志
output wire[31:0] flush_addr_o // 冲刷地址
);
assign flush_addr_o = jump_addr_i;
assign flush_o = jump_assert_i;
reg[`STALL_WIDTH-1:0] stall;
always @ (*) begin
stall[`STALL_EX] = 1'b0;
stall[`STALL_ID] = 1'b0;
stall[`STALL_IF] = 1'b0;
stall[`STALL_PC] = 1'b0;
if (stall_from_clint_i) begin
stall[`STALL_EX] = 1'b1;
stall[`STALL_ID] = 1'b1;
stall[`STALL_IF] = 1'b1;
stall[`STALL_PC] = 1'b1;
end
if (stall_from_ex_i) begin
stall[`STALL_EX] = 1'b1;
stall[`STALL_ID] = 1'b1;
stall[`STALL_IF] = 1'b1;
stall[`STALL_PC] = 1'b1;
end
if (stall_from_id_i) begin
stall[`STALL_IF] = 1'b1;
stall[`STALL_PC] = 1'b1;
end
end
assign stall_o = stall;
endmodule

View File

@ -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

View File

@ -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};
//
//
// 3021
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

View File

@ -14,37 +14,30 @@
limitations under the License.
*/
`include "../core/defines.v"
`include "defines.sv"
module rom(
// 复位控制模块
module rst_gen #(
parameter RESET_FIFO_DEPTH = 5
)(
input wire clk,
input wire rst,
input wire rst_ni,
input wire we_i, // write enable
input wire[`MemAddrBus] addr_i, // addr
input wire[`MemBus] data_i,
output reg[`MemBus] data_o // read data
output wire rst_no
);
reg[`MemBus] _rom[0:`RomNum - 1];
reg[RESET_FIFO_DEPTH-1:0] synch_regs_q;
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;
always @ (posedge clk or negedge rst_ni) begin
if (~rst_ni) begin
synch_regs_q <= 0;
end else begin
data_o = _rom[addr_i[31:2]];
synch_regs_q <= {synch_regs_q[RESET_FIFO_DEPTH-2:0], 1'b1};
end
end
assign rst_no = synch_regs_q[RESET_FIFO_DEPTH-1];
endmodule

View File

@ -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, // jtagPC
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

366
rtl/core/tinyriscv_core.sv Normal file
View File

@ -0,0 +1,366 @@
/*
Copyright 2019 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// tinyriscv处理器核顶层模块
module tinyriscv_core #(
parameter int unsigned DEBUG_HALT_ADDR = 32'h10000800,
parameter int unsigned DEBUG_EXCEPTION_ADDR = 32'h10000808,
parameter bit BranchPredictor = 1'b1,
parameter bit TRACE_ENABLE = 1'b0
)(
input wire clk,
input wire rst_n,
// instr fetch interface
output wire instr_req_o,
input wire instr_gnt_i,
input wire instr_rvalid_i,
output wire[31:0] instr_addr_o,
input wire[31:0] instr_rdata_i,
input wire instr_err_i,
// data access interface
output wire data_req_o,
input wire data_gnt_i,
input wire data_rvalid_i,
output wire data_we_o,
output wire[3:0] data_be_o,
output wire[31:0] data_addr_o,
output wire[31:0] data_wdata_o,
input wire[31:0] data_rdata_i,
input wire data_err_i,
// interrupt input
input wire int_req_i,
input wire[7:0] int_id_i,
// debug request signal
input wire debug_req_i
);
// ifu模块输出信号
wire[31:0] ifetch_inst_o;
wire[31:0] ifetch_pc_o;
wire ifetch_inst_valid_o;
// ifu_idu模块输出信号
wire[31:0] if_inst_o;
wire[31:0] if_inst_addr_o;
wire if_inst_valid_o;
wire if_ready_o;
// idu模块输出信号
wire[31:0] id_inst_o;
wire[31:0] id_inst_addr_o;
wire[`DECINFO_WIDTH-1:0] id_dec_info_bus_o;
wire[31:0] id_dec_imm_o;
wire[31:0] id_dec_pc_o;
wire[4:0] id_rs1_raddr_o;
wire[4:0] id_rs2_raddr_o;
wire[4:0] id_rd_waddr_o;
wire id_rd_we_o;
wire id_stall_o;
wire[31:0] id_rs1_rdata_o;
wire[31:0] id_rs2_rdata_o;
wire id_illegal_inst_o;
wire id_inst_valid_o;
// idu_exu模块输出信号
wire[31:0] ie_inst_o;
wire[31:0] ie_inst_addr_o;
wire[`DECINFO_WIDTH-1:0] ie_dec_info_bus_o;
wire[31:0] ie_dec_imm_o;
wire[31:0] ie_dec_pc_o;
wire[31:0] ie_rs1_rdata_o;
wire[31:0] ie_rs2_rdata_o;
wire[4:0] ie_rd_waddr_o;
wire ie_rd_we_o;
wire ie_inst_valid_o;
// exu模块输出信号
wire[31:0] ex_mem_wdata_o;
wire[31:0] ex_mem_addr_o;
wire ex_mem_we_o;
wire[3:0] ex_mem_sel_o;
wire ex_mem_req_valid_o;
wire ex_mem_rsp_ready_o;
wire ex_mem_access_misaligned_o;
wire[31:0] ex_reg_wdata_o;
wire ex_reg_we_o;
wire[4:0] ex_reg_waddr_o;
wire ex_hold_flag_o;
wire ex_jump_flag_o;
wire[31:0] ex_jump_addr_o;
wire[31:0] ex_csr_wdata_o;
wire ex_csr_we_o;
wire[31:0] ex_csr_waddr_o;
wire[31:0] ex_csr_raddr_o;
wire ex_inst_ecall_o;
wire ex_inst_ebreak_o;
wire ex_inst_mret_o;
wire ex_inst_dret_o;
wire ex_inst_valid_o;
wire ex_inst_executed_o;
// gpr_reg模块输出信号
wire[31:0] regs_rdata1_o;
wire[31:0] regs_rdata2_o;
// csr_reg模块输出信号
wire[31:0] csr_ex_data_o;
wire[31:0] csr_clint_data_o;
wire[31:0] csr_mtvec_o;
wire[31:0] csr_mepc_o;
wire[31:0] csr_mstatus_o;
wire[31:0] csr_mie_o;
wire[31:0] csr_dpc_o;
wire[31:0] csr_dcsr_o;
wire csr_trigger_match_o;
// pipe_ctrl模块输出信号
wire[31:0] ctrl_flush_addr_o;
wire ctrl_flush_o;
wire[`STALL_WIDTH-1:0] ctrl_stall_o;
// exception模块输出信号
wire excep_csr_we_o;
wire[31:0] excep_csr_waddr_o;
wire[31:0] excep_csr_wdata_o;
wire excep_stall_flag_o;
wire[31:0] excep_int_addr_o;
wire excep_int_assert_o;
ifu #(
.BranchPredictor(BranchPredictor)
) u_ifu (
.clk(clk),
.rst_n(rst_n),
.flush_addr_i(ctrl_flush_addr_o),
.stall_i(ctrl_stall_o),
.flush_i(ctrl_flush_o),
.id_ready_i(if_ready_o),
.inst_o(ifetch_inst_o),
.pc_o(ifetch_pc_o),
.inst_valid_o(ifetch_inst_valid_o),
.instr_req_o(instr_req_o),
.instr_gnt_i(instr_gnt_i),
.instr_rvalid_i(instr_rvalid_i),
.instr_addr_o(instr_addr_o),
.instr_rdata_i(instr_rdata_i),
.instr_err_i(instr_err_i)
);
pipe_ctrl u_pipe_ctrl(
.clk(clk),
.rst_n(rst_n),
.stall_from_id_i(id_stall_o),
.stall_from_ex_i(ex_hold_flag_o),
.stall_from_jtag_i(1'b0),
.stall_from_clint_i(excep_stall_flag_o),
.jump_assert_i(ex_jump_flag_o),
.jump_addr_i(ex_jump_addr_o),
.flush_o(ctrl_flush_o),
.stall_o(ctrl_stall_o),
.flush_addr_o(ctrl_flush_addr_o)
);
gpr_reg u_gpr_reg(
.clk(clk),
.rst_n(rst_n),
.we_i(ex_reg_we_o),
.waddr_i(ex_reg_waddr_o),
.wdata_i(ex_reg_wdata_o),
.raddr1_i(id_rs1_raddr_o),
.rdata1_o(regs_rdata1_o),
.raddr2_i(id_rs2_raddr_o),
.rdata2_o(regs_rdata2_o)
);
csr_reg u_csr_reg(
.clk(clk),
.rst_n(rst_n),
.pc_if_i(ie_dec_pc_o),
.trigger_match_o(csr_trigger_match_o),
.exu_we_i(ex_csr_we_o),
.exu_raddr_i(ex_csr_raddr_o),
.exu_waddr_i(ex_csr_waddr_o),
.exu_wdata_i(ex_csr_wdata_o),
.exu_rdata_o(csr_ex_data_o),
.excep_we_i(excep_csr_we_o),
.excep_waddr_i(excep_csr_waddr_o),
.excep_wdata_i(excep_csr_wdata_o),
.mtvec_o(csr_mtvec_o),
.mepc_o(csr_mepc_o),
.mstatus_o(csr_mstatus_o),
.mie_o(csr_mie_o),
.dpc_o(csr_dpc_o),
.dcsr_o(csr_dcsr_o)
);
ifu_idu u_ifu_idu(
.clk(clk),
.rst_n(rst_n),
.inst_i(ifetch_inst_o),
.inst_addr_i(ifetch_pc_o),
.stall_i(ctrl_stall_o),
.flush_i(ctrl_flush_o),
.inst_valid_i(ifetch_inst_valid_o),
.ready_o(if_ready_o),
.inst_valid_o(if_inst_valid_o),
.inst_o(if_inst_o),
.inst_addr_o(if_inst_addr_o)
);
idu u_idu(
.clk(clk),
.rst_n(rst_n),
.inst_i(if_inst_o),
.inst_valid_i(if_inst_valid_o),
.rs1_rdata_i(regs_rdata1_o),
.rs2_rdata_i(regs_rdata2_o),
.inst_o(id_inst_o),
.inst_valid_o(id_inst_valid_o),
.inst_addr_i(if_inst_addr_o),
.rs1_rdata_o(id_rs1_rdata_o),
.rs2_rdata_o(id_rs2_rdata_o),
.stall_o(id_stall_o),
.illegal_inst_o(id_illegal_inst_o),
.dec_info_bus_o(id_dec_info_bus_o),
.dec_imm_o(id_dec_imm_o),
.dec_pc_o(id_dec_pc_o),
.rs1_raddr_o(id_rs1_raddr_o),
.rs2_raddr_o(id_rs2_raddr_o),
.rd_waddr_o(id_rd_waddr_o),
.rd_we_o(id_rd_we_o)
);
idu_exu u_idu_exu(
.clk(clk),
.rst_n(rst_n),
.inst_i(id_inst_o),
.stall_i(ctrl_stall_o),
.flush_i(ctrl_flush_o),
.dec_info_bus_i(id_dec_info_bus_o),
.dec_imm_i(id_dec_imm_o),
.dec_pc_i(id_dec_pc_o),
.rs1_rdata_i(id_rs1_rdata_o),
.rs2_rdata_i(id_rs2_rdata_o),
.rd_waddr_i(id_rd_waddr_o),
.rd_we_i(id_rd_we_o),
.inst_valid_i(id_inst_valid_o),
.inst_valid_o(ie_inst_valid_o),
.inst_o(ie_inst_o),
.dec_info_bus_o(ie_dec_info_bus_o),
.dec_imm_o(ie_dec_imm_o),
.dec_pc_o(ie_dec_pc_o),
.rs1_rdata_o(ie_rs1_rdata_o),
.rs2_rdata_o(ie_rs2_rdata_o),
.rd_waddr_o(ie_rd_waddr_o),
.rd_we_o(ie_rd_we_o)
);
exu #(
.BranchPredictor(BranchPredictor)
) u_exu (
.clk(clk),
.rst_n(rst_n),
.reg1_rdata_i(ie_rs1_rdata_o),
.reg2_rdata_i(ie_rs2_rdata_o),
.mem_rdata_i(data_rdata_i),
.mem_gnt_i(data_gnt_i),
.mem_rvalid_i(data_rvalid_i),
.mem_wdata_o(data_wdata_o),
.mem_addr_o(data_addr_o),
.mem_we_o(data_we_o),
.mem_be_o(data_be_o),
.mem_req_o(data_req_o),
.mem_access_misaligned_o(ex_mem_access_misaligned_o),
.reg_wdata_o(ex_reg_wdata_o),
.reg_we_o(ex_reg_we_o),
.reg_waddr_o(ex_reg_waddr_o),
.hold_flag_o(ex_hold_flag_o),
.jump_flag_o(ex_jump_flag_o),
.jump_addr_o(ex_jump_addr_o),
.int_assert_i(excep_int_assert_o),
.int_addr_i(excep_int_addr_o),
.inst_ecall_o(ex_inst_ecall_o),
.inst_ebreak_o(ex_inst_ebreak_o),
.inst_mret_o(ex_inst_mret_o),
.inst_dret_o(ex_inst_dret_o),
.int_stall_i(excep_stall_flag_o),
.csr_raddr_o(ex_csr_raddr_o),
.csr_rdata_i(csr_ex_data_o),
.csr_wdata_o(ex_csr_wdata_o),
.csr_we_o(ex_csr_we_o),
.csr_waddr_o(ex_csr_waddr_o),
.inst_valid_o(ex_inst_valid_o),
.inst_valid_i(ie_inst_valid_o),
.inst_executed_o(ex_inst_executed_o),
.inst_i(ie_inst_o),
.dec_info_bus_i(ie_dec_info_bus_o),
.dec_imm_i(ie_dec_imm_o),
.dec_pc_i(ie_dec_pc_o),
.next_pc_i(if_inst_addr_o),
.rd_waddr_i(ie_rd_waddr_o),
.rd_we_i(ie_rd_we_o)
);
exception u_exception(
.clk(clk),
.rst_n(rst_n),
.illegal_inst_i(id_illegal_inst_o),
.inst_valid_i(ie_inst_valid_o),
.inst_executed_i(ex_inst_executed_o),
.inst_ecall_i(ex_inst_ecall_o),
.inst_ebreak_i(ex_inst_ebreak_o),
.inst_mret_i(ex_inst_mret_o),
.inst_dret_i(ex_inst_dret_o),
.inst_addr_i(ie_dec_pc_o),
.mtvec_i(csr_mtvec_o),
.mepc_i(csr_mepc_o),
.mstatus_i(csr_mstatus_o),
.mie_i(csr_mie_o),
.dpc_i(csr_dpc_o),
.dcsr_i(csr_dcsr_o),
.trigger_match_i(csr_trigger_match_o),
.int_req_i(int_req_i),
.int_id_i(int_id_i),
.debug_halt_addr_i(DEBUG_HALT_ADDR),
.debug_req_i(debug_req_i),
.csr_we_o(excep_csr_we_o),
.csr_waddr_o(excep_csr_waddr_o),
.csr_wdata_o(excep_csr_wdata_o),
.stall_flag_o(excep_stall_flag_o),
.int_addr_o(excep_int_addr_o),
.int_assert_o(excep_int_assert_o)
);
if (TRACE_ENABLE) begin: instr_trace
tracer u_tracer(
.clk(clk),
.rst_n(rst_n),
.inst_i(ie_inst_o),
.pc_i(ie_dec_pc_o),
.inst_valid_i(ex_inst_valid_o)
);
end
endmodule

613
rtl/core/tracer.sv Normal file
View File

@ -0,0 +1,613 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module tracer(
input logic clk,
input logic rst_n,
input logic[31:0] inst_i,
input logic[31:0] pc_i,
input logic inst_valid_i
);
typedef enum logic [6:0] {
OPCODE_LOAD = 7'h03,
OPCODE_MISC_MEM = 7'h0f,
OPCODE_OP_IMM = 7'h13,
OPCODE_AUIPC = 7'h17,
OPCODE_STORE = 7'h23,
OPCODE_OP = 7'h33,
OPCODE_LUI = 7'h37,
OPCODE_BRANCH = 7'h63,
OPCODE_JALR = 7'h67,
OPCODE_JAL = 7'h6f,
OPCODE_SYSTEM = 7'h73
} opcode_e;
// instruction masks (for tracer)
parameter logic [31:0] INSN_LUI = { 25'h?, {OPCODE_LUI } };
parameter logic [31:0] INSN_AUIPC = { 25'h?, {OPCODE_AUIPC} };
parameter logic [31:0] INSN_JAL = { 25'h?, {OPCODE_JAL } };
parameter logic [31:0] INSN_JALR = { 17'h?, 3'b000, 5'h?, {OPCODE_JALR } };
// BRANCH
parameter logic [31:0] INSN_BEQ = { 17'h?, 3'b000, 5'h?, {OPCODE_BRANCH} };
parameter logic [31:0] INSN_BNE = { 17'h?, 3'b001, 5'h?, {OPCODE_BRANCH} };
parameter logic [31:0] INSN_BLT = { 17'h?, 3'b100, 5'h?, {OPCODE_BRANCH} };
parameter logic [31:0] INSN_BGE = { 17'h?, 3'b101, 5'h?, {OPCODE_BRANCH} };
parameter logic [31:0] INSN_BLTU = { 17'h?, 3'b110, 5'h?, {OPCODE_BRANCH} };
parameter logic [31:0] INSN_BGEU = { 17'h?, 3'b111, 5'h?, {OPCODE_BRANCH} };
// OPIMM
parameter logic [31:0] INSN_ADDI = { 17'h?, 3'b000, 5'h?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_SLTI = { 17'h?, 3'b010, 5'h?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_SLTIU = { 17'h?, 3'b011, 5'h?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_XORI = { 17'h?, 3'b100, 5'h?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_ORI = { 17'h?, 3'b110, 5'h?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_ANDI = { 17'h?, 3'b111, 5'h?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_SLLI = { 7'b0000000, 10'h?, 3'b001, 5'h?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_SRLI = { 7'b0000000, 10'h?, 3'b101, 5'h?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_SRAI = { 7'b0100000, 10'h?, 3'b101, 5'h?, {OPCODE_OP_IMM} };
// OP
parameter logic [31:0] INSN_ADD = { 7'b0000000, 10'h?, 3'b000, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_SUB = { 7'b0100000, 10'h?, 3'b000, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_SLL = { 7'b0000000, 10'h?, 3'b001, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_SLT = { 7'b0000000, 10'h?, 3'b010, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_SLTU = { 7'b0000000, 10'h?, 3'b011, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_XOR = { 7'b0000000, 10'h?, 3'b100, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_SRL = { 7'b0000000, 10'h?, 3'b101, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_SRA = { 7'b0100000, 10'h?, 3'b101, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_OR = { 7'b0000000, 10'h?, 3'b110, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_AND = { 7'b0000000, 10'h?, 3'b111, 5'h?, {OPCODE_OP} };
// SYSTEM
parameter logic [31:0] INSN_CSRRW = { 17'h?, 3'b001, 5'h?, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_CSRRS = { 17'h?, 3'b010, 5'h?, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_CSRRC = { 17'h?, 3'b011, 5'h?, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_CSRRWI = { 17'h?, 3'b101, 5'h?, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_CSRRSI = { 17'h?, 3'b110, 5'h?, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_CSRRCI = { 17'h?, 3'b111, 5'h?, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_ECALL = { 12'b000000000000, 13'b0, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_EBREAK = { 12'b000000000001, 13'b0, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_MRET = { 12'b001100000010, 13'b0, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_DRET = { 12'b011110110010, 13'b0, {OPCODE_SYSTEM} };
parameter logic [31:0] INSN_WFI = { 12'b000100000101, 13'b0, {OPCODE_SYSTEM} };
// RV32M
parameter logic [31:0] INSN_MUL = { 7'b0000001, 10'h?, 3'b000, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_MULH = { 7'b0000001, 10'h?, 3'b001, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_MULHSU = { 7'b0000001, 10'h?, 3'b010, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_MULHU = { 7'b0000001, 10'h?, 3'b011, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_DIV = { 7'b0000001, 10'h?, 3'b100, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_DIVU = { 7'b0000001, 10'h?, 3'b101, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_REM = { 7'b0000001, 10'h?, 3'b110, 5'h?, {OPCODE_OP} };
parameter logic [31:0] INSN_REMU = { 7'b0000001, 10'h?, 3'b111, 5'h?, {OPCODE_OP} };
// LOAD & STORE
parameter logic [31:0] INSN_LOAD = {25'h?, {OPCODE_LOAD } };
parameter logic [31:0] INSN_STORE = {25'h?, {OPCODE_STORE} };
// MISC-MEM
parameter logic [31:0] INSN_FENCE = { 17'h?, 3'b000, 5'h?, {OPCODE_MISC_MEM} };
parameter logic [31:0] INSN_FENCEI = { 17'h0, 3'b001, 5'h0, {OPCODE_MISC_MEM} };
// Get a CSR name for a CSR address.
function automatic string get_csr_name(input logic [11:0] csr_addr);
unique case (csr_addr)
12'd0: return "ustatus";
12'd4: return "uie";
12'd5: return "utvec";
12'd64: return "uscratch";
12'd65: return "uepc";
12'd66: return "ucause";
12'd67: return "utval";
12'd68: return "uip";
12'd1: return "fflags";
12'd2: return "frm";
12'd3: return "fcsr";
12'd3072: return "cycle";
12'd3073: return "time";
12'd3074: return "instret";
12'd3075: return "hpmcounter3";
12'd3076: return "hpmcounter4";
12'd3077: return "hpmcounter5";
12'd3078: return "hpmcounter6";
12'd3079: return "hpmcounter7";
12'd3080: return "hpmcounter8";
12'd3081: return "hpmcounter9";
12'd3082: return "hpmcounter10";
12'd3083: return "hpmcounter11";
12'd3084: return "hpmcounter12";
12'd3085: return "hpmcounter13";
12'd3086: return "hpmcounter14";
12'd3087: return "hpmcounter15";
12'd3088: return "hpmcounter16";
12'd3089: return "hpmcounter17";
12'd3090: return "hpmcounter18";
12'd3091: return "hpmcounter19";
12'd3092: return "hpmcounter20";
12'd3093: return "hpmcounter21";
12'd3094: return "hpmcounter22";
12'd3095: return "hpmcounter23";
12'd3096: return "hpmcounter24";
12'd3097: return "hpmcounter25";
12'd3098: return "hpmcounter26";
12'd3099: return "hpmcounter27";
12'd3100: return "hpmcounter28";
12'd3101: return "hpmcounter29";
12'd3102: return "hpmcounter30";
12'd3103: return "hpmcounter31";
12'd3200: return "cycleh";
12'd3201: return "timeh";
12'd3202: return "instreth";
12'd3203: return "hpmcounter3h";
12'd3204: return "hpmcounter4h";
12'd3205: return "hpmcounter5h";
12'd3206: return "hpmcounter6h";
12'd3207: return "hpmcounter7h";
12'd3208: return "hpmcounter8h";
12'd3209: return "hpmcounter9h";
12'd3210: return "hpmcounter10h";
12'd3211: return "hpmcounter11h";
12'd3212: return "hpmcounter12h";
12'd3213: return "hpmcounter13h";
12'd3214: return "hpmcounter14h";
12'd3215: return "hpmcounter15h";
12'd3216: return "hpmcounter16h";
12'd3217: return "hpmcounter17h";
12'd3218: return "hpmcounter18h";
12'd3219: return "hpmcounter19h";
12'd3220: return "hpmcounter20h";
12'd3221: return "hpmcounter21h";
12'd3222: return "hpmcounter22h";
12'd3223: return "hpmcounter23h";
12'd3224: return "hpmcounter24h";
12'd3225: return "hpmcounter25h";
12'd3226: return "hpmcounter26h";
12'd3227: return "hpmcounter27h";
12'd3228: return "hpmcounter28h";
12'd3229: return "hpmcounter29h";
12'd3230: return "hpmcounter30h";
12'd3231: return "hpmcounter31h";
12'd256: return "sstatus";
12'd258: return "sedeleg";
12'd259: return "sideleg";
12'd260: return "sie";
12'd261: return "stvec";
12'd262: return "scounteren";
12'd320: return "sscratch";
12'd321: return "sepc";
12'd322: return "scause";
12'd323: return "stval";
12'd324: return "sip";
12'd384: return "satp";
12'd3857: return "mvendorid";
12'd3858: return "marchid";
12'd3859: return "mimpid";
12'd3860: return "mhartid";
12'd768: return "mstatus";
12'd769: return "misa";
12'd770: return "medeleg";
12'd771: return "mideleg";
12'd772: return "mie";
12'd773: return "mtvec";
12'd774: return "mcounteren";
12'd832: return "mscratch";
12'd833: return "mepc";
12'd834: return "mcause";
12'd835: return "mtval";
12'd836: return "mip";
12'd928: return "pmpcfg0";
12'd929: return "pmpcfg1";
12'd930: return "pmpcfg2";
12'd931: return "pmpcfg3";
12'd944: return "pmpaddr0";
12'd945: return "pmpaddr1";
12'd946: return "pmpaddr2";
12'd947: return "pmpaddr3";
12'd948: return "pmpaddr4";
12'd949: return "pmpaddr5";
12'd950: return "pmpaddr6";
12'd951: return "pmpaddr7";
12'd952: return "pmpaddr8";
12'd953: return "pmpaddr9";
12'd954: return "pmpaddr10";
12'd955: return "pmpaddr11";
12'd956: return "pmpaddr12";
12'd957: return "pmpaddr13";
12'd958: return "pmpaddr14";
12'd959: return "pmpaddr15";
12'd2816: return "mcycle";
12'd2818: return "minstret";
12'd2819: return "mhpmcounter3";
12'd2820: return "mhpmcounter4";
12'd2821: return "mhpmcounter5";
12'd2822: return "mhpmcounter6";
12'd2823: return "mhpmcounter7";
12'd2824: return "mhpmcounter8";
12'd2825: return "mhpmcounter9";
12'd2826: return "mhpmcounter10";
12'd2827: return "mhpmcounter11";
12'd2828: return "mhpmcounter12";
12'd2829: return "mhpmcounter13";
12'd2830: return "mhpmcounter14";
12'd2831: return "mhpmcounter15";
12'd2832: return "mhpmcounter16";
12'd2833: return "mhpmcounter17";
12'd2834: return "mhpmcounter18";
12'd2835: return "mhpmcounter19";
12'd2836: return "mhpmcounter20";
12'd2837: return "mhpmcounter21";
12'd2838: return "mhpmcounter22";
12'd2839: return "mhpmcounter23";
12'd2840: return "mhpmcounter24";
12'd2841: return "mhpmcounter25";
12'd2842: return "mhpmcounter26";
12'd2843: return "mhpmcounter27";
12'd2844: return "mhpmcounter28";
12'd2845: return "mhpmcounter29";
12'd2846: return "mhpmcounter30";
12'd2847: return "mhpmcounter31";
12'd2944: return "mcycleh";
12'd2946: return "minstreth";
12'd2947: return "mhpmcounter3h";
12'd2948: return "mhpmcounter4h";
12'd2949: return "mhpmcounter5h";
12'd2950: return "mhpmcounter6h";
12'd2951: return "mhpmcounter7h";
12'd2952: return "mhpmcounter8h";
12'd2953: return "mhpmcounter9h";
12'd2954: return "mhpmcounter10h";
12'd2955: return "mhpmcounter11h";
12'd2956: return "mhpmcounter12h";
12'd2957: return "mhpmcounter13h";
12'd2958: return "mhpmcounter14h";
12'd2959: return "mhpmcounter15h";
12'd2960: return "mhpmcounter16h";
12'd2961: return "mhpmcounter17h";
12'd2962: return "mhpmcounter18h";
12'd2963: return "mhpmcounter19h";
12'd2964: return "mhpmcounter20h";
12'd2965: return "mhpmcounter21h";
12'd2966: return "mhpmcounter22h";
12'd2967: return "mhpmcounter23h";
12'd2968: return "mhpmcounter24h";
12'd2969: return "mhpmcounter25h";
12'd2970: return "mhpmcounter26h";
12'd2971: return "mhpmcounter27h";
12'd2972: return "mhpmcounter28h";
12'd2973: return "mhpmcounter29h";
12'd2974: return "mhpmcounter30h";
12'd2975: return "mhpmcounter31h";
12'd803: return "mhpmevent3";
12'd804: return "mhpmevent4";
12'd805: return "mhpmevent5";
12'd806: return "mhpmevent6";
12'd807: return "mhpmevent7";
12'd808: return "mhpmevent8";
12'd809: return "mhpmevent9";
12'd810: return "mhpmevent10";
12'd811: return "mhpmevent11";
12'd812: return "mhpmevent12";
12'd813: return "mhpmevent13";
12'd814: return "mhpmevent14";
12'd815: return "mhpmevent15";
12'd816: return "mhpmevent16";
12'd817: return "mhpmevent17";
12'd818: return "mhpmevent18";
12'd819: return "mhpmevent19";
12'd820: return "mhpmevent20";
12'd821: return "mhpmevent21";
12'd822: return "mhpmevent22";
12'd823: return "mhpmevent23";
12'd824: return "mhpmevent24";
12'd825: return "mhpmevent25";
12'd826: return "mhpmevent26";
12'd827: return "mhpmevent27";
12'd828: return "mhpmevent28";
12'd829: return "mhpmevent29";
12'd830: return "mhpmevent30";
12'd831: return "mhpmevent31";
12'd1952: return "tselect";
12'd1953: return "tdata1";
12'd1954: return "tdata2";
12'd1955: return "tdata3";
12'd1968: return "dcsr";
12'd1969: return "dpc";
12'd1970: return "dscratch0";
12'd1971: return "dscratch1";
12'd512: return "hstatus";
12'd514: return "hedeleg";
12'd515: return "hideleg";
12'd516: return "hie";
12'd517: return "htvec";
12'd576: return "hscratch";
12'd577: return "hepc";
12'd578: return "hcause";
12'd579: return "hbadaddr";
12'd580: return "hip";
12'd896: return "mbase";
12'd897: return "mbound";
12'd898: return "mibase";
12'd899: return "mibound";
12'd900: return "mdbase";
12'd901: return "mdbound";
12'd800: return "mcountinhibit";
default: return $sformatf("0x%x", csr_addr);
endcase
endfunction
int unsigned cycle;
string decoded_str;
int file_handle;
string file_name;
logic[4:0] rd_addr = inst_i[11:7];
logic[4:0] rs1_addr = inst_i[19:15];
logic[4:0] rs2_addr = inst_i[24:20];
function automatic void decode_u_insn(input string mnemonic);
decoded_str = $sformatf("%s x%0d,0x%0x", mnemonic, rd_addr, {inst_i[31:12]});
endfunction
function automatic void decode_j_insn(input string mnemonic);
decoded_str = $sformatf("%s x%0d,%0x", mnemonic, rd_addr,
{{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0});
endfunction
function automatic void decode_i_jalr_insn(input string mnemonic);
decoded_str = $sformatf("%s x%0d,%0d(x%0d)", mnemonic, rd_addr,
$signed({{20 {inst_i[31]}}, inst_i[31:20]}), rs1_addr);
endfunction
function automatic void decode_b_insn(input string mnemonic);
logic [31:0] branch_target;
logic [31:0] imm;
// We cannot use rvfi_pc_wdata for conditional jumps.
imm = $signed({ {19 {inst_i[31]}}, inst_i[31], inst_i[7],
inst_i[30:25], inst_i[11:8], 1'b0 });
branch_target = pc_i + imm;
decoded_str = $sformatf("%s x%0d,x%0d,%0x", mnemonic, rs1_addr, rs2_addr, branch_target);
endfunction
function automatic void decode_i_insn(input string mnemonic);
decoded_str = $sformatf("%s x%0d,x%0d,%0d", mnemonic, rd_addr, rs1_addr,
$signed({{20 {inst_i[31]}}, inst_i[31:20]}));
endfunction
function automatic void decode_i_shift_insn(input string mnemonic);
logic [4:0] shamt;
shamt = {inst_i[24:20]};
decoded_str = $sformatf("%s x%0d,x%0d,0x%0x", mnemonic, rd_addr, rs1_addr, shamt);
endfunction
function automatic void decode_r_insn(input string mnemonic);
decoded_str = $sformatf("%s x%0d,x%0d,x%0d", mnemonic, rd_addr, rs1_addr, rs2_addr);
endfunction
function automatic void decode_csr_insn(input string mnemonic);
logic [11:0] csr;
string csr_name;
csr = inst_i[31:20];
csr_name = get_csr_name(csr);
if (!inst_i[14]) begin
decoded_str = $sformatf("%s x%0d,%s,x%0d", mnemonic, rd_addr, csr_name, rs1_addr);
end else begin
decoded_str = $sformatf("%s x%0d,%s,%0d", mnemonic, rd_addr, csr_name, { 27'b0, inst_i[19:15]});
end
endfunction
function automatic void decode_mnemonic(input string mnemonic);
decoded_str = mnemonic;
endfunction
function automatic void decode_load_insn();
string mnemonic;
logic [2:0] size;
size = inst_i[14:12];
if (size == 3'b000) begin
mnemonic = "lb";
end else if (size == 3'b001) begin
mnemonic = "lh";
end else if (size == 3'b010) begin
mnemonic = "lw";
end else if (size == 3'b100) begin
mnemonic = "lbu";
end else if (size == 3'b101) begin
mnemonic = "lhu";
end else begin
decode_mnemonic("INVALID");
return;
end
decoded_str = $sformatf("%s x%0d,%0d(x%0d)", mnemonic, rd_addr,
$signed({{20 {inst_i[31]}}, inst_i[31:20]}), rs1_addr);
endfunction
function automatic void decode_store_insn();
string mnemonic;
if (inst_i[13:12] == 2'b00) begin
mnemonic = "sb";
end else if (inst_i[13:12] == 2'b01) begin
mnemonic = "sh";
end else if (inst_i[13:12] == 2'b10) begin
mnemonic = "sw";
end else begin
decode_mnemonic("INVALID");
return;
end
if (!inst_i[14]) begin
decoded_str = $sformatf("%s x%0d,%0d(x%0d)", mnemonic, rs2_addr,
$signed({ {20 {inst_i[31]}}, inst_i[31:25], inst_i[11:7] }), rs1_addr);
end else begin
decode_mnemonic("INVALID");
end
endfunction
function automatic string get_fence_description(logic [3:0] bits);
string desc = "";
if (bits[3]) begin
desc = {desc, "i"};
end
if (bits[2]) begin
desc = {desc, "o"};
end
if (bits[1]) begin
desc = {desc, "r"};
end
if (bits[0]) begin
desc = {desc, "w"};
end
return desc;
endfunction
function automatic void decode_fence();
string predecessor;
string successor;
predecessor = get_fence_description(inst_i[27:24]);
successor = get_fence_description(inst_i[23:20]);
decoded_str = $sformatf("fence %s,%s", predecessor, successor);
endfunction
always_comb begin
decoded_str = "";
unique casez (inst_i)
INSN_LUI: decode_u_insn("lui");
INSN_AUIPC: decode_u_insn("auipc");
INSN_JAL: decode_j_insn("jal");
INSN_JALR: decode_i_jalr_insn("jalr");
// BRANCH
INSN_BEQ: decode_b_insn("beq");
INSN_BNE: decode_b_insn("bne");
INSN_BLT: decode_b_insn("blt");
INSN_BGE: decode_b_insn("bge");
INSN_BLTU: decode_b_insn("bltu");
INSN_BGEU: decode_b_insn("bgeu");
// OPIMM
INSN_ADDI: begin
if (inst_i == 32'h00_00_00_13) begin
decode_mnemonic("nop");
end else begin
decode_i_insn("addi");
end
end
INSN_SLTI: decode_i_insn("slti");
INSN_SLTIU: decode_i_insn("sltiu");
INSN_XORI: decode_i_insn("xori");
INSN_ORI: decode_i_insn("ori");
INSN_ANDI: decode_i_insn("andi");
INSN_SLLI: decode_i_shift_insn("slli");
INSN_SRLI: decode_i_shift_insn("srli");
INSN_SRAI: decode_i_shift_insn("srai");
// OP
INSN_ADD: decode_r_insn("add");
INSN_SUB: decode_r_insn("sub");
INSN_SLL: decode_r_insn("sll");
INSN_SLT: decode_r_insn("slt");
INSN_SLTU: decode_r_insn("sltu");
INSN_XOR: decode_r_insn("xor");
INSN_SRL: decode_r_insn("srl");
INSN_SRA: decode_r_insn("sra");
INSN_OR: decode_r_insn("or");
INSN_AND: decode_r_insn("and");
// SYSTEM (CSR manipulation)
INSN_CSRRW: decode_csr_insn("csrrw");
INSN_CSRRS: decode_csr_insn("csrrs");
INSN_CSRRC: decode_csr_insn("csrrc");
INSN_CSRRWI: decode_csr_insn("csrrwi");
INSN_CSRRSI: decode_csr_insn("csrrsi");
INSN_CSRRCI: decode_csr_insn("csrrci");
// SYSTEM (others)
INSN_ECALL: decode_mnemonic("ecall");
INSN_EBREAK: decode_mnemonic("ebreak");
INSN_MRET: decode_mnemonic("mret");
INSN_DRET: decode_mnemonic("dret");
INSN_WFI: decode_mnemonic("wfi");
// RV32M
INSN_MUL: decode_r_insn("mul");
INSN_MULH: decode_r_insn("mulh");
INSN_MULHSU: decode_r_insn("mulhsu");
INSN_MULHU: decode_r_insn("mulhu");
INSN_DIV: decode_r_insn("div");
INSN_DIVU: decode_r_insn("divu");
INSN_REM: decode_r_insn("rem");
INSN_REMU: decode_r_insn("remu");
// LOAD & STORE
INSN_LOAD: decode_load_insn();
INSN_STORE: decode_store_insn();
// MISC-MEM
INSN_FENCE: decode_fence();
INSN_FENCEI: decode_mnemonic("fence.i");
default: decode_mnemonic("INVALID");
endcase
end
initial begin
string file_name_base = "trace_core";
$sformat(file_name, "%s.log", file_name_base);
$display("Writing execution trace to %s", file_name);
file_handle = $fopen(file_name, "w");
$fwrite(file_handle, "\t\t\tTime\t\tCycle\tPC\t\t\tInsn\t\tDecoded instruction\n");
$fflush(file_handle);
end
function automatic void printbuffer_dumpline();
string insn_str = $sformatf("%h", inst_i);
$fwrite(file_handle, "%15t\t%d\t\t%h\t%s\t%s", $time, cycle, pc_i, insn_str, decoded_str);
$fwrite(file_handle, "\n");
$fflush(file_handle);
endfunction
// log execution
always @(posedge clk) begin
if (inst_valid_i) begin
printbuffer_dumpline();
end
end
// cycle counter
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cycle <= 0;
end else begin
cycle <= cycle + 1;
end
end
endmodule

88
rtl/debug/debug_rom.sv Normal file
View File

@ -0,0 +1,88 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module debug_rom (
input wire clk_i,
input wire req_i,
input wire [31:0] addr_i,
output wire [31:0] rdata_o
);
localparam RomSize = 38;
wire [RomSize-1:0][31:0] mem;
assign mem = {
32'h00000000,
32'h7b200073,
32'h7b202473,
32'h7b302573,
32'h10852423,
32'hf1402473,
32'ha85ff06f,
32'h7b202473,
32'h7b302573,
32'h10052223,
32'h00100073,
32'h7b202473,
32'h7b302573,
32'h10052623,
32'h00c51513,
32'h00c55513,
32'h00000517,
32'hfd5ff06f,
32'hfa041ce3,
32'h00247413,
32'h40044403,
32'h00a40433,
32'hf1402473,
32'h02041c63,
32'h00147413,
32'h40044403,
32'h00a40433,
32'h10852023,
32'hf1402473,
32'h00c51513,
32'h00c55513,
32'h00000517,
32'h7b351073,
32'h7b241073,
32'h0ff0000f,
32'h04c0006f,
32'h07c0006f,
32'h00c0006f
};
reg [5:0] addr_q;
always @ (posedge clk_i) begin
if (req_i) begin
addr_q <= addr_i[7:2];
end
end
reg[31:0] rdata;
always @ (*) begin
rdata = 32'h0;
if (addr_q < 6'd38) begin
rdata = mem[addr_q];
end
end
assign rdata_o = rdata;
endmodule

155
rtl/debug/jtag_def.sv Normal file
View File

@ -0,0 +1,155 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`define DbgVersion013 4'h2
`define ProgBufSize 5'h8
`define DataCount 4'h1
`define HaltAddress 64'h800
`define ResumeAddress `HaltAddress + 4
`define ExceptionAddress `HaltAddress + 8
`define DataBaseAddr 12'h380
`define AbstCmdBaseAddr 12'h338
`define AbstCmdCount 12'd10
`define ProgbufBaseAddr `AbstCmdBaseAddr + (4 * `AbstCmdCount)
// dmi op
`define DMI_OP_NOP 2'b00
`define DMI_OP_READ 2'b01
`define DMI_OP_WRITE 2'b10
// DM regs addr
`define Data0 7'h04
`define Data1 7'h05
`define Data2 7'h06
`define Data3 7'h07
`define Data4 7'h08
`define DMControl 7'h10
`define DMStatus 7'h11
`define Hartinfo 7'h12
`define AbstractCS 7'h16
`define Command 7'h17
`define AbstractAuto 7'h18
`define ProgBuf0 7'h20
`define ProgBuf1 7'h21
`define ProgBuf2 7'h22
`define ProgBuf3 7'h23
`define ProgBuf4 7'h24
`define ProgBuf5 7'h25
`define ProgBuf6 7'h26
`define ProgBuf7 7'h27
`define ProgBuf8 7'h28
`define ProgBuf9 7'h29
`define ProgBuf10 7'h2A
`define ProgBuf11 7'h2B
`define ProgBuf12 7'h2C
`define ProgBuf13 7'h2D
`define ProgBuf14 7'h2E
`define ProgBuf15 7'h2F
`define SBAddress3 7'h37
`define SBCS 7'h38
`define SBAddress0 7'h39
`define SBAddress1 7'h3A
`define SBAddress2 7'h3B
`define SBData0 7'h3C
`define SBData1 7'h3D
`define SBData2 7'h3E
`define SBData3 7'h3F
`define HaltSum0 7'h40
`define HaltSum1 7'h13
// dmstatus bit index
`define Impebreak 22
`define Allhavereset 19
`define Anyhavereset 18
`define Allresumeack 17
`define Anyresumeack 16
`define Allnonexistent 15
`define Anynonexistent 14
`define Allunavail 13
`define Anyunavail 12
`define Allrunning 11
`define Anyrunning 10
`define Allhalted 9
`define Anyhalted 8
`define Authenticated 7
`define Authbusy 6
`define Hasresethaltreq 5
`define Confstrptrvalid 4
`define Version 3:0
// dmcontrol bit index
`define Haltreq 31
`define Resumereq 30
`define Hartreset 29
`define Ackhavereset 28
`define Hasel 26
`define Hartsello 25:16
`define Hartselhi 15:6
`define Setresethaltreq 3
`define Clrresethaltreq 2
`define Ndmreset 1
`define Dmactive 0
// abstractcs bit index
`define Progbufsize 28:24
`define Busy 12
`define Cmderr 10:8
`define Datacount 3:0
// abstract command access register bit index
`define Cmdtype 31:24
`define Aarsize 22:20
`define Aarpostincrement 19
`define Postexec 18
`define Transfer 17
`define Write 16
`define Regno 15:0
// sbcs bit index
`define Sbversion 31:29
`define Sbbusyerror 22
`define Sbbusy 21
`define Sbreadonaddr 20
`define Sbaccess 19:17
`define Sbautoincrement 16
`define Sbreadondata 15
`define Sberror 14:12
`define Sbasize 11:5
`define Sbaccess128 4
`define Sbaccess64 3
`define Sbaccess32 2
`define Sbaccess16 1
`define Sbaccess8 0
// abstractauto
`define AutoexecData 11:0
`define AutoexecProgbuf 31:16
`define CSR_CYCLE 12'hc00
`define CSR_CYCLEH 12'hc80
`define CSR_MTVEC 12'h305
`define CSR_MCAUSE 12'h342
`define CSR_MEPC 12'h341
`define CSR_MIE 12'h304
`define CSR_MSTATUS 12'h300
`define CSR_MSCRATCH 12'h340
`define CSR_MHARTID 12'hF14
`define CSR_DCSR 12'h7b0
`define CSR_DPC 12'h7b1
`define CSR_DSCRATCH0 12'h7b2
`define CSR_DSCRATCH1 12'h7b3

533
rtl/debug/jtag_dm.sv Normal file
View File

@ -0,0 +1,533 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "jtag_def.sv"
module jtag_dm #(
parameter DMI_ADDR_BITS = 7,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2,
parameter DMI_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
parameter DMI_RESP_BITS = DMI_REQ_BITS
)(
input wire clk,
input wire rst_n,
// from DMI
input wire [DMI_REQ_BITS-1:0] dmi_data_i,
input wire dmi_valid_i,
output wire dm_ready_o,
// to DMI
output wire [DMI_RESP_BITS-1:0] dm_data_o,
output wire dm_valid_o,
input wire dmi_ready_i,
output wire debug_req_o,
output wire ndmreset_o,
output wire halted_o,
// jtag access mem devices(DM as master)
output wire master_req_o,
input wire master_gnt_i,
input wire master_rvalid_i,
output wire master_we_o,
output wire [3:0] master_be_o,
output wire [31:0] master_addr_o,
output wire [31:0] master_wdata_o,
input wire [31:0] master_rdata_i,
input wire master_err_i,
// core fetch instr or mem(DM as slave)
input wire slave_req_i,
input wire slave_we_i,
input wire [31:0] slave_addr_i,
input wire [3:0] slave_be_i,
input wire [31:0] slave_wdata_i,
output wire slave_gnt_o,
output wire slave_rvalid_o,
output wire [31:0] slave_rdata_o
);
localparam HARTINFO = {8'h0, 4'h2, 3'b0, 1'b1, `DataCount, `DataBaseAddr};
localparam CmdErrorNone = 3'h0;
localparam CmdErrorBusy = 3'h1;
wire halted;
wire resumeack;
wire sbbusy;
wire[2:0] sberror;
wire[DMI_OP_BITS-1:0] dm_op;
wire[DMI_ADDR_BITS-1:0] dm_op_addr;
wire[DMI_DATA_BITS-1:0] dm_op_data;
reg havereset_d, havereset_q;
reg clear_resumeack;
reg sbaddress_write_valid;
reg sbdata_write_valid;
reg sbdata_read_valid;
reg[31:0] sbcs;
reg[31:0] a_abstractcs;
reg[31:0] dm_resp_data_d, dm_resp_data_q;
reg cmd_valid_d, cmd_valid_q;
reg[15:0] abstractautoprogbuf;
reg[3:0] progbuf_index;
wire[31:0] sba_sbaddress;
wire[31:0] dm_sbaddress;
wire resumereq;
wire cmdbusy;
wire sbdata_valid;
wire[31:0] sbdata;
wire[19:0] hartsel;
wire data_valid;
wire[31:0] data0;
wire cmderror_valid;
wire[2:0] cmderror;
// DM regs
reg[31:0] dmstatus;
reg[31:0] dmcontrol_d, dmcontrol_q;
reg[31:0] abstractcs;
reg[31:0] abstractauto_d, abstractauto_q;
reg[31:0] sbcs_d, sbcs_q;
reg[31:0] sbdata0_d, sbdata0_q;
reg[31:0] sbaddress0_d, sbaddress0_q;
reg[31:0] command_d, command_q;
reg[31:0] data0_d, data0_q;
reg[2:0] cmderr_d, cmderr_q;
reg[`ProgBufSize-1:0][31:0] progbuf_d, progbuf_q;
assign dm_sbaddress = sbaddress0_q;
assign hartsel = {dmcontrol_q[`Hartselhi], dmcontrol_q[`Hartsello]};
assign dm_op = dmi_data_i[DMI_OP_BITS-1:0];
assign dm_op_addr = dmi_data_i[DMI_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
assign dm_op_data = dmi_data_i[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
localparam S_REQ = 2'b01;
localparam S_RESP = 2'b10;
reg[2:0] req_state_d, req_state_q;
reg dm_valid_d;
// response FSM
always @ (*) begin
req_state_d = req_state_q;
dm_valid_d = 1'b0;
case (req_state_q)
S_REQ: begin
if (dmi_valid_i & dm_ready_o) begin
req_state_d = S_RESP;
end
end
S_RESP: begin
if (dmi_ready_i) begin
dm_valid_d = 1'b1;
req_state_d = S_REQ;
end
end
default:;
endcase
end
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
req_state_q <= S_REQ;
end else begin
req_state_q <= req_state_d;
end
end
// we always ready to receive dmi request
assign dm_ready_o = ~sbbusy;
assign dm_valid_o = dm_valid_d;
assign dm_data_o = {{DMI_ADDR_BITS{1'b0}}, dm_resp_data_q, 2'b00}; // response successfully
// DMI read or write operation
always @ (*) begin
// dmstatus
dmstatus = 32'h0;
dmstatus[`Version] = `DbgVersion013;
dmstatus[`Authenticated] = 1'b1;
dmstatus[`Allresumeack] = resumeack;
dmstatus[`Anyresumeack] = resumeack;
dmstatus[`Allhavereset] = havereset_q;
dmstatus[`Anyhavereset] = havereset_q;
dmstatus[`Allhalted] = halted;
dmstatus[`Anyhalted] = halted;
dmstatus[`Allrunning] = ~halted;
dmstatus[`Anyrunning] = ~halted;
dmstatus[`Allnonexistent] = hartsel > 20'h0;
dmstatus[`Anynonexistent] = hartsel > 20'h0;
// abstractcs
cmderr_d = cmderr_q;
abstractcs = 32'h0;
abstractcs[`Datacount] = `DataCount;
abstractcs[`Progbufsize] = `ProgBufSize;
abstractcs[`Busy] = cmdbusy;
abstractcs[`Cmderr] = cmderr_q;
a_abstractcs = 32'h0;
abstractauto_d = abstractauto_q;
havereset_d = havereset_q;
sbaddress0_d = sba_sbaddress;
dmcontrol_d = dmcontrol_q;
clear_resumeack = 1'b0;
sbaddress_write_valid = 1'b0;
sbdata_write_valid = 1'b0;
sbdata_read_valid = 1'b0;
sbcs = 32'h0;
command_d = command_q;
cmd_valid_d = 1'b0;
progbuf_index = 4'h0;
progbuf_d = progbuf_q;
abstractautoprogbuf = abstractauto_q[`AutoexecProgbuf];
data0_d = data0_q;
sbcs_d = sbcs_q;
sbdata0_d = sbdata0_q;
dm_resp_data_d = dm_resp_data_q;
if (dmi_valid_i & dm_ready_o) begin
// read
if (dm_op == `DMI_OP_READ) begin
case (dm_op_addr)
`DMStatus :dm_resp_data_d = dmstatus;
`DMControl :dm_resp_data_d = dmcontrol_q;
`Hartinfo :dm_resp_data_d = HARTINFO;
`SBCS :dm_resp_data_d = sbcs_q;
`AbstractCS:dm_resp_data_d = abstractcs;
`AbstractAuto: dm_resp_data_d = abstractauto_q;
`Command :dm_resp_data_d = 32'h0;
`SBAddress0:dm_resp_data_d = sbaddress0_q;
`SBData0 : begin
if (sbbusy || sbcs_q[`Sbbusyerror]) begin
sbcs_d[`Sbbusyerror] = 1'b1;
end else begin
sbdata_read_valid = (sbcs_q[`Sberror] == 3'b0);
dm_resp_data_d = sbdata0_q;
end
end
`Data0: begin
dm_resp_data_d = data0_q;
if (!cmdbusy) begin
cmd_valid_d = abstractauto_q[0];
end else if (cmderr_q == CmdErrorNone) begin
cmderr_d = CmdErrorBusy;
end
end
`ProgBuf0, `ProgBuf1, `ProgBuf2, `ProgBuf3,
`ProgBuf4, `ProgBuf5, `ProgBuf6, `ProgBuf7,
`ProgBuf8, `ProgBuf9: begin
progbuf_index = dm_op_addr[3:0];
dm_resp_data_d = progbuf_q[progbuf_index];
if (!cmdbusy) begin
cmd_valid_d = abstractautoprogbuf[progbuf_index];
end else if (cmderr_q == CmdErrorNone) begin
cmderr_d = CmdErrorBusy;
end
end
`HaltSum0: dm_resp_data_d = {31'h0, halted};
`HaltSum1: dm_resp_data_d = {31'h0, halted};
default: dm_resp_data_d = 32'h0;
endcase
// write
end else if (dm_op == `DMI_OP_WRITE) begin
case (dm_op_addr)
`DMControl: begin
dmcontrol_d = dm_op_data;
if (dmcontrol_d[`Ackhavereset]) begin
havereset_d = 1'b0;
end
end
`Data0: begin
if (!cmdbusy) begin
data0_d = dm_op_data;
cmd_valid_d = abstractauto_q[0];
end else if (cmderr_q == CmdErrorNone) begin
cmderr_d = CmdErrorBusy;
end
end
`SBCS: begin
if (sbbusy) begin
sbcs_d[`Sbbusyerror] = 1'b1;
end else begin
sbcs = dm_op_data;
sbcs_d = dm_op_data;
// write 1 to clear
sbcs_d[`Sbbusyerror] = sbcs_q[`Sbbusyerror] & (~sbcs[`Sbbusyerror]);
sbcs_d[`Sberror] = sbcs_q[`Sberror] & (~sbcs[`Sberror]);
end
end
`SBAddress0: begin
if (sbbusy | sbcs_q[`Sbbusyerror]) begin
sbcs_d[`Sbbusyerror] = 1'b1;
end else begin
sbaddress0_d = dm_op_data;
sbaddress_write_valid = (sbcs_q[`Sberror] == 3'b0);
end
end
`SBData0: begin
if (sbbusy | sbcs_q[`Sbbusyerror]) begin
sbcs_d[`Sbbusyerror] = 1'b1;
end else begin
sbdata0_d = dm_op_data;
sbdata_write_valid = (sbcs_q[`Sberror] == 3'b0);
end
end
`Command: begin
if (!cmdbusy) begin
cmd_valid_d = 1'b1;
command_d = dm_op_data;
end else if (cmderr_q == CmdErrorNone) begin
cmderr_d = CmdErrorBusy;
end
end
`AbstractCS: begin
a_abstractcs = dm_op_data;
if (!cmdbusy) begin
cmderr_d = (~a_abstractcs[`Cmderr]) & cmderr_q;
end else if (cmderr_q == CmdErrorNone) begin
cmderr_d = CmdErrorBusy;
end
end
`AbstractAuto: begin
if (!cmdbusy) begin
abstractauto_d = 32'h0;
abstractauto_d[`AutoexecData] = {11'h0, dm_op_data[0]};
abstractauto_d[`AutoexecProgbuf] = dm_op_data[`ProgBufSize-1+16:16];
end else if (cmderr_q == CmdErrorNone) begin
cmderr_d = CmdErrorBusy;
end
end
`ProgBuf0, `ProgBuf1, `ProgBuf2, `ProgBuf3,
`ProgBuf4, `ProgBuf5, `ProgBuf6, `ProgBuf7,
`ProgBuf8, `ProgBuf9: begin
if (!cmdbusy) begin
progbuf_index = dm_op_addr[3:0];
progbuf_d[progbuf_index] = dm_op_data;
cmd_valid_d = abstractautoprogbuf[progbuf_index];
end else if (cmderr_q == CmdErrorNone) begin
cmderr_d = CmdErrorBusy;
end
end
default:;
endcase
// nop
end
end
// dmcontrol
dmcontrol_d[`Hasel] = 1'b0;
dmcontrol_d[`Hartreset] = 1'b0;
dmcontrol_d[`Setresethaltreq] = 1'b0;
dmcontrol_d[`Clrresethaltreq] = 1'b0;
dmcontrol_d[`Ackhavereset] = 1'b0;
// 收到resume请求后清resume应答
if (!dmcontrol_q[`Resumereq] && dmcontrol_d[`Resumereq]) begin
clear_resumeack = 1'b1;
end
// 发出resume后并且收到应答
if (dmcontrol_q[`Resumereq] && resumeack) begin
// 清resume请求位
dmcontrol_d[`Resumereq] = 1'b0;
end
// sbcs
sbcs_d[`Sbversion] = 3'd1;
sbcs_d[`Sbbusy] = sbbusy;
sbcs_d[`Sberror] = sberror;
sbcs_d[`Sbasize] = 7'd32;
sbcs_d[`Sbaccess128] = 1'b0;
sbcs_d[`Sbaccess64] = 1'b0;
sbcs_d[`Sbaccess32] = 1'b1;
sbcs_d[`Sbaccess16] = 1'b0;
sbcs_d[`Sbaccess8] = 1'b0;
sbcs_d[`Sbaccess] = 3'd2;
if (sbdata_valid) begin
sbdata0_d = sbdata;
end
if (cmderror_valid) begin
cmderr_d = cmderror;
end
if (data_valid) begin
data0_d = data0;
end
// set the havereset flag when we did a ndmreset
if (ndmreset_o) begin
havereset_d = 1'b1;
end
end
assign debug_req_o = dmcontrol_q[`Haltreq];
assign ndmreset_o = dmcontrol_q[`Ndmreset];
assign resumereq = dmcontrol_q[`Resumereq];
assign halted_o = halted;
genvar i;
generate
for (i = 0; i < `ProgBufSize; i = i + 1) begin: gen_progbuf
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
progbuf_q[i] <= 32'h0;
end else begin
if (!dmcontrol_q[`Dmactive]) begin
progbuf_q[i] <= 32'h0;
end else begin
progbuf_q[i] <= progbuf_d[i];
end
end
end
end
endgenerate
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
dmcontrol_q <= 32'h0;
havereset_q <= 1'b1;
data0_q <= 32'h0;
sbcs_q <= 32'h0;
sbaddress0_q <= 32'h0;
sbdata0_q <= 32'h0;
dm_resp_data_q <= 32'h0;
cmderr_q <= 3'h0;
command_q <= 32'h0;
abstractauto_q <= 32'h0;
cmd_valid_q <= 1'b0;
end else begin
if (!dmcontrol_q[`Dmactive]) begin
dmcontrol_q[`Haltreq] <= 1'b0;
dmcontrol_q[`Resumereq] <= 1'b0;
dmcontrol_q[`Hartreset] <= 1'b0;
dmcontrol_q[`Ackhavereset] <= 1'b0;
dmcontrol_q[`Hasel] <= 1'b0;
dmcontrol_q[`Hartsello] <= 10'b0;
dmcontrol_q[`Hartselhi] <= 10'b0;
dmcontrol_q[`Setresethaltreq] <= 1'b0;
dmcontrol_q[`Clrresethaltreq] <= 1'b0;
dmcontrol_q[`Ndmreset] <= 1'b0;
dmcontrol_q[`Dmactive] <= dmcontrol_d[`Dmactive];
data0_q <= 32'h0;
sbcs_q <= 32'h0;
sbaddress0_q <= 32'h0;
sbdata0_q <= 32'h0;
dm_resp_data_q <= 32'h0;
cmderr_q <= 3'h0;
command_q <= 32'h0;
abstractauto_q <= 32'h0;
cmd_valid_q <= 1'b0;
end else begin
dmcontrol_q <= dmcontrol_d;
data0_q <= data0_d;
sbcs_q <= sbcs_d;
sbaddress0_q <= sbaddress0_d;
sbdata0_q <= sbdata0_d;
dm_resp_data_q <= dm_resp_data_d;
cmderr_q <= cmderr_d;
command_q <= command_d;
abstractauto_q <= abstractauto_d;
cmd_valid_q <= cmd_valid_d;
end
havereset_q <= havereset_d;
end
end
jtag_mem u_jtag_mem (
.clk(clk),
.rst_n(rst_n),
.halted_o(halted),
.resumeack_o(resumeack),
.clear_resumeack_i(clear_resumeack),
.resumereq_i(resumereq),
.haltreq_i(debug_req_o),
.ndmreset_i(ndmreset_o),
.progbuf_i(progbuf_q),
.data_i(data0_q),
.data_o(data0),
.data_valid_o(data_valid),
.cmd_valid_i(cmd_valid_q),
.cmd_i(command_q),
.cmderror_valid_o(cmderror_valid),
.cmderror_o(cmderror),
.cmdbusy_o(cmdbusy),
.req_i(slave_req_i),
.we_i(slave_we_i),
.addr_i(slave_addr_i),
.be_i(slave_be_i),
.wdata_i(slave_wdata_i),
.gnt_o(slave_gnt_o),
.rvalid_o(slave_rvalid_o),
.rdata_o(slave_rdata_o)
);
jtag_sba u_jtag_sba (
.clk(clk),
.rst_n(rst_n),
.sbaddress_i(sbaddress0_q),
.sbaddress_write_valid_i(sbaddress_write_valid),
.sbreadonaddr_i(sbcs_q[`Sbreadonaddr]),
.sbaddress_o(sba_sbaddress),
.sbautoincrement_i(sbcs_q[`Sbautoincrement]),
.sbaccess_i(sbcs_q[`Sbaccess]),
.sbreadondata_i(sbcs_q[`Sbreadondata]),
.sbdata_i(sbdata0_q),
.sbdata_read_valid_i(sbdata_read_valid),
.sbdata_write_valid_i(sbdata_write_valid),
.sbdata_o(sbdata),
.sbdata_valid_o(sbdata_valid),
.sbbusy_o(sbbusy),
.sberror_o(sberror),
.master_req_o(master_req_o),
.master_gnt_i(master_gnt_i),
.master_rvalid_i(master_rvalid_i),
.master_we_o(master_we_o),
.master_be_o(master_be_o),
.master_addr_o(master_addr_o),
.master_wdata_o(master_wdata_o),
.master_rdata_i(master_rdata_i),
.master_err_i(master_err_i)
);
endmodule

View File

@ -1,342 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`define DM_RESP_VALID 1'b1
`define DM_RESP_INVALID 1'b0
`define DTM_REQ_VALID 1'b1
`define DTM_REQ_INVALID 1'b0
`define DTM_OP_NOP 2'b00
`define DTM_OP_READ 2'b01
`define DTM_OP_WRITE 2'b10
module jtag_dm #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2)(
clk,
rst_n,
// rx
dm_ack_o,
dtm_req_valid_i,
dtm_req_data_i,
// tx
dtm_ack_i,
dm_resp_data_o,
dm_resp_valid_o,
dm_reg_we_o,
dm_reg_addr_o,
dm_reg_wdata_o,
dm_reg_rdata_i,
dm_mem_we_o,
dm_mem_addr_o,
dm_mem_wdata_o,
dm_mem_rdata_i,
dm_op_req_o,
dm_halt_req_o,
dm_reset_req_o
);
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
parameter SHIFT_REG_BITS = DTM_REQ_BITS;
//
input wire clk;
input wire rst_n;
output wire dm_ack_o;
input wire dtm_req_valid_i;
input wire[DTM_REQ_BITS-1:0] dtm_req_data_i;
input wire dtm_ack_i;
output wire[DM_RESP_BITS-1:0] dm_resp_data_o;
output wire dm_resp_valid_o;
output wire dm_reg_we_o;
output wire[4:0] dm_reg_addr_o;
output wire[31:0] dm_reg_wdata_o;
input wire[31:0] dm_reg_rdata_i;
output wire dm_mem_we_o;
output wire[31:0] dm_mem_addr_o;
output wire[31:0] dm_mem_wdata_o;
input wire[31:0] dm_mem_rdata_i;
output wire dm_op_req_o;
output wire dm_halt_req_o;
output wire dm_reset_req_o;
// DM
reg[31:0] dcsr;
reg[31:0] dmstatus;
reg[31:0] dmcontrol;
reg[31:0] hartinfo;
reg[31:0] abstractcs;
reg[31:0] data0;
reg[31:0] sbcs;
reg[31:0] sbaddress0;
reg[31:0] sbdata0;
reg[31:0] command;
// DM
localparam DCSR = 16'h7b0;
localparam DMSTATUS = 6'h11;
localparam DMCONTROL = 6'h10;
localparam HARTINFO = 6'h12;
localparam ABSTRACTCS = 6'h16;
localparam DATA0 = 6'h04;
localparam SBCS = 6'h38;
localparam SBADDRESS0 = 6'h39;
localparam SBDATA0 = 6'h3C;
localparam COMMAND = 6'h17;
localparam DPC = 16'h7b1;
localparam OP_SUCC = 2'b00;
reg[31:0] read_data;
reg dm_reg_we;
reg[4:0] dm_reg_addr;
reg[31:0] dm_reg_wdata;
reg dm_mem_we;
reg[31:0] dm_mem_addr;
reg[31:0] dm_mem_wdata;
reg dm_halt_req;
reg dm_reset_req;
reg need_resp;
reg is_read_reg;
wire rx_valid;
wire[DTM_REQ_BITS-1:0] rx_data;
wire[31:0] sbaddress0_next = sbaddress0 + 4;
wire[DM_RESP_BITS-1:0] dm_resp_data;
wire[DMI_OP_BITS-1:0] op = rx_data[DMI_OP_BITS-1:0];
wire[DMI_DATA_BITS-1:0] data = rx_data[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
wire[DMI_ADDR_BITS-1:0] address = rx_data[DTM_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
wire read_dmstatus = (op == `DTM_OP_READ) & (address == DMSTATUS);
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
dm_mem_we <= 1'b0;
dm_reg_we <= 1'b0;
dm_halt_req <= 1'b0;
dm_reset_req <= 1'b0;
dm_mem_addr <= 32'h0;
dm_reg_addr <= 5'h0;
sbaddress0 <= 32'h0;
dcsr <= 32'h0;
hartinfo <= 32'h0;
sbcs <= 32'h20040404;
dmcontrol <= 32'h0;
abstractcs <= 32'h1000003;
data0 <= 32'h0;
sbdata0 <= 32'h0;
command <= 32'h0;
dm_reg_wdata <= 32'h0;
dm_mem_wdata <= 32'h0;
dmstatus <= 32'h430c82;
is_read_reg <= 1'b0;
read_data <= 32'h0;
need_resp <= 1'b0;
end else begin
if (rx_valid) begin
need_resp <= 1'b1;
case (op)
`DTM_OP_READ: begin
case (address)
DMSTATUS: begin
read_data <= dmstatus;
end
DMCONTROL: begin
read_data <= dmcontrol;
end
HARTINFO: begin
read_data <= hartinfo;
end
SBCS: begin
read_data <= sbcs;
end
ABSTRACTCS: begin
read_data <= abstractcs;
end
DATA0: begin
if (is_read_reg == 1'b1) begin
read_data <= dm_reg_rdata_i;
end else begin
read_data <= data0;
end
is_read_reg <= 1'b0;
end
SBDATA0: begin
read_data <= dm_mem_rdata_i;
if (sbcs[16] == 1'b1) begin
sbaddress0 <= sbaddress0_next;
end
if (sbcs[15] == 1'b1) begin
dm_mem_addr <= sbaddress0_next;
end
end
default: begin
read_data <= {(DMI_DATA_BITS){1'b0}};
end
endcase
end
`DTM_OP_WRITE: begin
read_data <= {(DMI_DATA_BITS){1'b0}};
case (address)
DMCONTROL: begin
// reset DM module
if (data[0] == 1'b0) begin
dcsr <= 32'hc0;
dmstatus <= 32'h430c82; // not halted, all running
hartinfo <= 32'h0;
sbcs <= 32'h20040404;
abstractcs <= 32'h1000003;
dmcontrol <= data;
dm_halt_req <= 1'b0;
dm_reset_req <= 1'b0;
// DM is active
end else begin
// we have only one hart
dmcontrol <= (data & ~(32'h3fffc0)) | 32'h10000;
// halt
if (data[31] == 1'b1) begin
dm_halt_req <= 1'b1;
// clear ALLRUNNING ANYRUNNING and set ALLHALTED
dmstatus <= {dmstatus[31:12], 4'h3, dmstatus[7:0]};
// resume
end else if (dm_halt_req == 1'b1 && data[30] == 1'b1) begin
dm_halt_req <= 1'b0;
// set ALLRUNNING ANYRUNNING and clear ALLHALTED
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
end
end
end
COMMAND: begin
// access reg
if (data[31:24] == 8'h0) begin
if (data[22:20] > 3'h2) begin
abstractcs <= abstractcs | (1'b1 << 9);
end else begin
abstractcs <= abstractcs & (~(3'h7 << 8));
// read or write
if (data[18] == 1'b0) begin
dm_reg_addr <= data[15:0] - 16'h1000;
// read
if (data[16] == 1'b0) begin
if (data[15:0] == DCSR) begin
data0 <= dcsr;
end else if (data[15:0] < 16'h1020) begin
is_read_reg <= 1'b1;
end
// write
end else begin
// when write dpc, we reset cpu here
if (data[15:0] == DPC) begin
dm_reset_req <= 1'b1;
dm_halt_req <= 1'b0;
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
end else if (data[15:0] < 16'h1020) begin
dm_reg_we <= 1'b1;
dm_reg_wdata <= data0;
end
end
end
end
end
end
DATA0: begin
data0 <= data;
end
SBCS: begin
sbcs <= data;
end
SBADDRESS0: begin
sbaddress0 <= data;
if (sbcs[20] == 1'b1) begin
dm_mem_addr <= data;
end
end
SBDATA0: begin
sbdata0 <= data;
dm_mem_addr <= sbaddress0;
dm_mem_wdata <= data;
dm_mem_we <= 1'b1;
if (sbcs[16] == 1'b1) begin
sbaddress0 <= sbaddress0_next;
end
end
endcase
end
`DTM_OP_NOP: begin
read_data <= {(DMI_DATA_BITS){1'b0}};
end
endcase
end else begin
need_resp <= 1'b0;
dm_mem_we <= 1'b0;
dm_reg_we <= 1'b0;
dm_reset_req <= 1'b0;
end
end
end
assign dm_reg_we_o = dm_reg_we;
assign dm_reg_addr_o = dm_reg_addr;
assign dm_reg_wdata_o = dm_reg_wdata;
assign dm_mem_we_o = dm_mem_we;
assign dm_mem_addr_o = dm_mem_addr;
assign dm_mem_wdata_o = dm_mem_wdata;
assign dm_op_req_o = (rx_valid & (~read_dmstatus)) | need_resp;
assign dm_halt_req_o = dm_halt_req;
assign dm_reset_req_o = dm_reset_req;
assign dm_resp_data = {address, read_data, OP_SUCC};
full_handshake_tx #(
.DW(DM_RESP_BITS)
) tx(
.clk(clk),
.rst_n(rst_n),
.ack_i(dtm_ack_i),
.req_i(need_resp),
.req_data_i(dm_resp_data),
.idle_o(tx_idle),
.req_o(dm_resp_valid_o),
.req_data_o(dm_resp_data_o)
);
full_handshake_rx #(
.DW(DTM_REQ_BITS)
) rx(
.clk(clk),
.rst_n(rst_n),
.req_i(dtm_req_valid_i),
.req_data_i(dtm_req_data_i),
.ack_o(dm_ack_o),
.recv_data_o(rx_data),
.recv_rdy_o(rx_valid)
);
endmodule

76
rtl/debug/jtag_dmi.sv Normal file
View File

@ -0,0 +1,76 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_dmi #(
parameter DATA_WIDTH = 41
)(
// JTAG side(master side)
input wire jtag_tck_i,
input wire jtag_trst_ni,
input wire [DATA_WIDTH-1:0] jtag_data_i,
input wire jtag_valid_i,
output wire jtag_ready_o,
output wire [DATA_WIDTH-1:0] jtag_data_o,
output wire jtag_valid_o,
input wire jtag_ready_i,
// Core side(slave side)
input wire clk_i,
input wire rst_ni,
input wire [DATA_WIDTH-1:0] core_data_i,
input wire core_valid_i,
output wire core_ready_o,
output wire [DATA_WIDTH-1:0] core_data_o,
output wire core_valid_o,
input wire core_ready_i
);
cdc_2phase #(.DATA_WIDTH(DATA_WIDTH)) u_cdc_req (
.src_rst_ni ( jtag_trst_ni ),
.src_clk_i ( jtag_tck_i ),
.src_data_i ( jtag_data_i ),
.src_valid_i ( jtag_valid_i ),
.src_ready_o ( jtag_ready_o ),
.dst_rst_ni ( rst_ni ),
.dst_clk_i ( clk_i ),
.dst_data_o ( core_data_o ),
.dst_valid_o ( core_valid_o ),
.dst_ready_i ( core_ready_i )
);
cdc_2phase #(.DATA_WIDTH(DATA_WIDTH)) u_cdc_resp (
.src_rst_ni ( rst_ni ),
.src_clk_i ( clk_i ),
.src_data_i ( core_data_i ),
.src_valid_i ( core_valid_i ),
.src_ready_o ( core_ready_o ),
.dst_rst_ni ( jtag_trst_ni ),
.dst_clk_i ( jtag_tck_i ),
.dst_data_o ( jtag_data_o ),
.dst_valid_o ( jtag_valid_o ),
.dst_ready_i ( jtag_ready_i )
);
endmodule

View File

@ -1,295 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`define DM_RESP_VALID 1'b1
`define DM_RESP_INVALID 1'b0
`define DTM_REQ_VALID 1'b1
`define DTM_REQ_INVALID 1'b0
module jtag_driver #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2)(
rst_n,
jtag_TCK,
jtag_TDI,
jtag_TMS,
jtag_TDO,
// rx
dm_resp_i,
dm_resp_data_i,
dtm_ack_o,
// tx
dm_ack_i,
dtm_req_valid_o,
dtm_req_data_o
);
parameter IDCODE_VERSION = 4'h1;
parameter IDCODE_PART_NUMBER = 16'he200;
parameter IDCODE_MANUFLD = 11'h537;
parameter DTM_VERSION = 4'h1;
parameter IR_BITS = 5;
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
parameter SHIFT_REG_BITS = DTM_REQ_BITS;
// input and output
input wire rst_n;
input wire jtag_TCK;
input wire jtag_TDI;
input wire jtag_TMS;
output reg jtag_TDO;
input wire dm_resp_i;
input wire[DM_RESP_BITS - 1:0] dm_resp_data_i;
output wire dtm_ack_o;
input wire dm_ack_i;
output wire dtm_req_valid_o;
output wire[DTM_REQ_BITS - 1:0] dtm_req_data_o;
// JTAG StateMachine
parameter TEST_LOGIC_RESET = 4'h0;
parameter RUN_TEST_IDLE = 4'h1;
parameter SELECT_DR = 4'h2;
parameter CAPTURE_DR = 4'h3;
parameter SHIFT_DR = 4'h4;
parameter EXIT1_DR = 4'h5;
parameter PAUSE_DR = 4'h6;
parameter EXIT2_DR = 4'h7;
parameter UPDATE_DR = 4'h8;
parameter SELECT_IR = 4'h9;
parameter CAPTURE_IR = 4'hA;
parameter SHIFT_IR = 4'hB;
parameter EXIT1_IR = 4'hC;
parameter PAUSE_IR = 4'hD;
parameter EXIT2_IR = 4'hE;
parameter UPDATE_IR = 4'hF;
// DTM regs
parameter REG_BYPASS = 5'b11111;
parameter REG_IDCODE = 5'b00001;
parameter REG_DMI = 5'b10001;
parameter REG_DTMCS = 5'b10000;
reg[IR_BITS - 1:0] ir_reg;
reg[SHIFT_REG_BITS - 1:0] shift_reg;
reg[3:0] jtag_state;
wire is_busy;
reg sticky_busy;
reg dtm_req_valid;
reg[DTM_REQ_BITS - 1:0] dtm_req_data;
reg[DM_RESP_BITS - 1:0] dm_resp_data;
reg dm_is_busy;
wire[5:0] addr_bits = DMI_ADDR_BITS[5:0];
wire [SHIFT_REG_BITS - 1:0] busy_response;
wire [SHIFT_REG_BITS - 1:0] none_busy_response;
wire[31:0] idcode;
wire[31:0] dtmcs;
wire[1:0] dmi_stat;
wire dtm_reset;
wire tx_idle;
wire rx_valid;
wire[DM_RESP_BITS - 1:0] rx_data;
wire tx_valid;
wire[DTM_REQ_BITS - 1:0] tx_data;
assign dtm_reset = shift_reg[16];
assign idcode = {IDCODE_VERSION, IDCODE_PART_NUMBER, IDCODE_MANUFLD, 1'h1};
assign dtmcs = {14'b0,
1'b0, // dmihardreset
1'b0, // dmireset
1'b0,
3'h5, // idle
dmi_stat, // dmistat
addr_bits, // abits
DTM_VERSION}; // version
assign busy_response = {{(DMI_ADDR_BITS + DMI_DATA_BITS){1'b0}}, {(DMI_OP_BITS){1'b1}}}; // op = 2'b11
assign none_busy_response = dm_resp_data;
assign is_busy = sticky_busy | dm_is_busy;
assign dmi_stat = is_busy ? 2'b01 : 2'b00;
// state switch
always @(posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
jtag_state <= TEST_LOGIC_RESET;
end else begin
case (jtag_state)
TEST_LOGIC_RESET : jtag_state <= jtag_TMS ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
RUN_TEST_IDLE : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
SELECT_DR : jtag_state <= jtag_TMS ? SELECT_IR : CAPTURE_DR;
CAPTURE_DR : jtag_state <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
SHIFT_DR : jtag_state <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
EXIT1_DR : jtag_state <= jtag_TMS ? UPDATE_DR : PAUSE_DR;
PAUSE_DR : jtag_state <= jtag_TMS ? EXIT2_DR : PAUSE_DR;
EXIT2_DR : jtag_state <= jtag_TMS ? UPDATE_DR : SHIFT_DR;
UPDATE_DR : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
SELECT_IR : jtag_state <= jtag_TMS ? TEST_LOGIC_RESET : CAPTURE_IR;
CAPTURE_IR : jtag_state <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
SHIFT_IR : jtag_state <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
EXIT1_IR : jtag_state <= jtag_TMS ? UPDATE_IR : PAUSE_IR;
PAUSE_IR : jtag_state <= jtag_TMS ? EXIT2_IR : PAUSE_IR;
EXIT2_IR : jtag_state <= jtag_TMS ? UPDATE_IR : SHIFT_IR;
UPDATE_IR : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
endcase
end
end
// IR or DR shift
always @(posedge jtag_TCK) begin
case (jtag_state)
// IR
CAPTURE_IR: shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, 1'b1}; //JTAG spec says it must be b01
SHIFT_IR : shift_reg <= {{(SHIFT_REG_BITS - IR_BITS){1'b0}}, jtag_TDI, shift_reg[IR_BITS - 1:1]}; // right shift 1 bit
// DR
CAPTURE_DR: case (ir_reg)
REG_BYPASS : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, idcode};
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, dtmcs};
REG_DMI : shift_reg <= is_busy ? busy_response : none_busy_response;
default:
shift_reg <= {(SHIFT_REG_BITS){1'b0}};
endcase
SHIFT_DR : case (ir_reg)
REG_BYPASS : shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, jtag_TDI}; // in = out
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bit
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bit
REG_DMI : shift_reg <= {jtag_TDI, shift_reg[SHIFT_REG_BITS - 1:1]}; // right shift 1 bit
default:
shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}} , jtag_TDI};
endcase
endcase
end
// start access DM module
always @(posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dtm_req_valid <= `DTM_REQ_INVALID;
dtm_req_data <= {DTM_REQ_BITS{1'b0}};
end else begin
if (jtag_state == UPDATE_DR) begin
if (ir_reg == REG_DMI) begin
// if DM can be access
if (!is_busy & tx_idle) begin
dtm_req_valid <= `DTM_REQ_VALID;
dtm_req_data <= shift_reg;
end
end
end else begin
dtm_req_valid <= `DTM_REQ_INVALID;
end
end
end
assign tx_valid = dtm_req_valid;
assign tx_data = dtm_req_data;
// DTM reset
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
sticky_busy <= 1'b0;
end else begin
if (jtag_state == UPDATE_DR) begin
if (ir_reg == REG_DTMCS & dtm_reset) begin
sticky_busy <= 1'b0;
end
end else if (jtag_state == CAPTURE_DR) begin
if (ir_reg == REG_DMI) begin
sticky_busy <= is_busy;
end
end
end
end
// receive DM response data
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dm_resp_data <= {DM_RESP_BITS{1'b0}};
end else begin
if (rx_valid) begin
dm_resp_data <= rx_data;
end
end
end
// tx busy
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dm_is_busy <= 1'b0;
end else begin
if (dtm_req_valid) begin
dm_is_busy <= 1'b1;
end else if (rx_valid) begin
dm_is_busy <= 1'b0;
end
end
end
// TAP reset
always @(negedge jtag_TCK) begin
if (jtag_state == TEST_LOGIC_RESET) begin
ir_reg <= REG_IDCODE;
end else if (jtag_state == UPDATE_IR) begin
ir_reg <= shift_reg[IR_BITS - 1:0];
end
end
// TDO output
always @(negedge jtag_TCK) begin
if (jtag_state == SHIFT_IR) begin
jtag_TDO <= shift_reg[0];
end else if (jtag_state == SHIFT_DR) begin
jtag_TDO <= shift_reg[0];
end else begin
jtag_TDO <= 1'b0;
end
end
full_handshake_tx #(
.DW(DTM_REQ_BITS)
) tx(
.clk(jtag_TCK),
.rst_n(rst_n),
.ack_i(dm_ack_i),
.req_i(tx_valid),
.req_data_i(tx_data),
.idle_o(tx_idle),
.req_o(dtm_req_valid_o),
.req_data_o(dtm_req_data_o)
);
full_handshake_rx #(
.DW(DM_RESP_BITS)
) rx(
.clk(jtag_TCK),
.rst_n(rst_n),
.req_i(dm_resp_i),
.req_data_i(dm_resp_data_i),
.ack_o(dtm_ack_o),
.recv_data_o(rx_data),
.recv_rdy_o(rx_valid)
);
endmodule

194
rtl/debug/jtag_dtm.sv Normal file
View File

@ -0,0 +1,194 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "jtag_def.sv"
module jtag_dtm #(
parameter DMI_ADDR_BITS = 7,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2,
parameter TAP_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
parameter DTM_RESP_BITS = TAP_REQ_BITS,
parameter DTM_REQ_BITS = DTM_RESP_BITS,
parameter DMI_RESP_BITS = DTM_REQ_BITS
)(
input wire jtag_tck_i, // JTAG test clock pad
input wire jtag_trst_ni, // JTAG test reset pad
// to jtag_dmi
output wire [DTM_REQ_BITS-1:0] dtm_data_o,
output wire dtm_valid_o,
// from jtag_dmi
input wire dmi_ready_i,
// from jtag_dmi
input wire [DMI_RESP_BITS-1:0] dmi_data_i,
input wire dmi_valid_i,
// to jtag_dmi
output wire dtm_ready_o,
// from jtag_tap
input wire tap_req_i,
input wire [TAP_REQ_BITS-1:0] tap_data_i,
input wire dmireset_i,
// to jtag_tap
output wire [DTM_RESP_BITS-1:0] data_o,
output wire [31:0] idcode_o,
output wire [31:0] dtmcs_o
);
localparam IDCODE_VERSION = 4'h1;
localparam IDCODE_PART_NUMBER = 16'he200;
localparam IDCODE_MANUFLD = 11'h537;
localparam DTM_VERSION = 4'h1;
localparam S_IDLE = 5'b00001;
localparam S_READ = 5'b00010;
localparam S_WAIT_READ = 5'b00100;
localparam S_WRITE = 5'b01000;
localparam S_WAIT_WRITE = 5'b10000;
reg[4:0] state_d;
reg[4:0] state_q;
reg dtm_valid;
reg dtm_ready;
reg[DTM_REQ_BITS-1:0] dtm_data_q;
reg[DTM_REQ_BITS-1:0] dtm_data_d;
reg[DTM_RESP_BITS-1:0] resp_tap_data_q;
reg is_busy;
reg stick_busy;
wire[DTM_RESP_BITS-1:0] busy_response;
wire dtm_busy;
wire[DMI_OP_BITS-1:0] op;
wire[1:0] dmistat;
wire[DMI_ADDR_BITS-1:0] abits = DMI_ADDR_BITS[6:0];
assign idcode_o = {IDCODE_VERSION, IDCODE_PART_NUMBER, IDCODE_MANUFLD, 1'h1};
assign dtmcs_o = {14'b0,
1'b0, // dmihardreset
1'b0, // dmireset
1'b0,
3'h1, // idle
dmistat, // dmistat
abits, // abits
DTM_VERSION}; // version
assign busy_response = {{(DMI_ADDR_BITS + DMI_DATA_BITS){1'b0}}, {(DMI_OP_BITS){1'b1}}}; // op = 2'b11
assign dmistat = (stick_busy | is_busy) ? 2'b11 : 2'b00;
assign op = tap_data_i[DMI_OP_BITS-1:0];
always @ (*) begin
state_d = state_q;
dtm_valid = 1'b0;
dtm_ready = 1'b0;
dtm_data_d = dtm_data_q;
case (state_q)
S_IDLE: begin
if (tap_req_i) begin
if (op == `DMI_OP_READ) begin
state_d = S_READ;
dtm_data_d = tap_data_i;
end else if (op == `DMI_OP_WRITE) begin
state_d = S_WRITE;
dtm_data_d = tap_data_i;
end else begin
state_d = S_IDLE;
end
end else begin
state_d = S_IDLE;
end
end
S_READ: begin
if (dmi_ready_i) begin
dtm_valid = 1'b1;
state_d = S_WAIT_READ;
end
end
S_WAIT_READ: begin
dtm_ready = 1'b1;
if (dmi_valid_i) begin
dtm_data_d = dmi_data_i;
state_d = S_IDLE;
end
end
S_WRITE: begin
if (dmi_ready_i) begin
dtm_valid = 1'b1;
state_d = S_WAIT_WRITE;
end
end
S_WAIT_WRITE: begin
dtm_ready = 1'b1;
if (dmi_valid_i) begin
dtm_data_d = dmi_data_i;
state_d = S_IDLE;
end
end
default: begin
dtm_data_d = {DTM_REQ_BITS{1'b0}};
state_d = S_IDLE;
end
endcase
end
assign dtm_valid_o = dtm_valid;
assign dtm_data_o = dtm_data_q;
assign dtm_ready_o = dtm_ready;
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
state_q <= S_IDLE;
dtm_data_q <= {DTM_REQ_BITS{1'b0}};
end else begin
state_q <= state_d;
dtm_data_q <= dtm_data_d;
end
end
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
is_busy <= 1'b0;
stick_busy <= 1'b0;
end else begin
if (dmireset_i) begin
stick_busy <= 1'b0;
end else if ((state_q != S_IDLE) && tap_req_i) begin
stick_busy <= 1'b1;
end
if ((state_q != S_IDLE) | tap_req_i) begin
is_busy <= 1'b1;
end else begin
is_busy <= 1'b0;
end
end
end
assign data_o = (stick_busy | is_busy | tap_req_i) ? busy_response : dtm_data_q;
endmodule

512
rtl/debug/jtag_mem.sv Normal file
View File

@ -0,0 +1,512 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "jtag_def.sv"
module jtag_mem(
input wire clk,
input wire rst_n,
output wire halted_o,
output wire resumeack_o,
input wire clear_resumeack_i,
input wire resumereq_i,
input wire haltreq_i,
input wire ndmreset_i,
input wire [`ProgBufSize-1:0][31:0] progbuf_i,
input wire [31:0] data_i,
output wire [31:0] data_o,
output wire data_valid_o,
input wire cmd_valid_i,
input wire [31:0] cmd_i,
output wire cmderror_valid_o,
output wire [2:0] cmderror_o,
output wire cmdbusy_o,
input wire req_i,
input wire we_i,
input wire [31:0] addr_i,
input wire [3:0] be_i,
input wire [31:0] wdata_i,
output wire gnt_o,
output wire rvalid_o,
output wire [31:0] rdata_o
);
// 16KB
localparam DbgAddressBits = 12;
// x10/a0
localparam LoadBaseAddr = 5'd10;
localparam Data0Addr = `DataBaseAddr;
localparam Data1Addr = `DataBaseAddr + 4;
localparam Data2Addr = `DataBaseAddr + 8;
localparam Data3Addr = `DataBaseAddr + 12;
localparam Data4Addr = `DataBaseAddr + 16;
localparam Progbuf0Addr = `ProgbufBaseAddr;
localparam Progbuf1Addr = `ProgbufBaseAddr + 4;
localparam Progbuf2Addr = `ProgbufBaseAddr + 8;
localparam Progbuf3Addr = `ProgbufBaseAddr + 12;
localparam Progbuf4Addr = `ProgbufBaseAddr + 16;
localparam Progbuf5Addr = `ProgbufBaseAddr + 20;
localparam Progbuf6Addr = `ProgbufBaseAddr + 24;
localparam Progbuf7Addr = `ProgbufBaseAddr + 28;
localparam Progbuf8Addr = `ProgbufBaseAddr + 32;
localparam Progbuf9Addr = `ProgbufBaseAddr + 36;
localparam AbstractCmd0Addr = `AbstCmdBaseAddr;
localparam AbstractCmd1Addr = `AbstCmdBaseAddr + 4;
localparam AbstractCmd2Addr = `AbstCmdBaseAddr + 8;
localparam AbstractCmd3Addr = `AbstCmdBaseAddr + 12;
localparam AbstractCmd4Addr = `AbstCmdBaseAddr + 16;
localparam AbstractCmd5Addr = `AbstCmdBaseAddr + 20;
localparam AbstractCmd6Addr = `AbstCmdBaseAddr + 24;
localparam AbstractCmd7Addr = `AbstCmdBaseAddr + 28;
localparam AbstractCmd8Addr = `AbstCmdBaseAddr + 32;
localparam AbstractCmd9Addr = `AbstCmdBaseAddr + 36;
localparam WhereToAddr = 12'h300;
localparam FlagsBaseAddr = 12'h400;
localparam FlagsEndAddr = 12'h7FF;
localparam HaltedAddr = 12'h100;
localparam GoingAddr = 12'h104;
localparam ResumingAddr = 12'h108;
localparam ExceptionAddr = 12'h10C;
localparam CmdAccessRegister = 8'h0;
localparam CmdQuickAccess = 8'h1;
localparam CmdAccessMemory = 8'h2;
localparam CmdErrorNone = 3'h0;
localparam CmdErrorHaltResume = 3'h4;
localparam CmdErrorNotSupport = 3'h2;
localparam CmdErrorException = 3'h3;
localparam illegal = 32'h00000000;
localparam nop = 32'h00000013;
localparam ebreak = 32'h00100073;
localparam S_IDLE = 4'b0001;
localparam S_RESUME = 4'b0010;
localparam S_GO = 4'b0100;
localparam S_CMD_EXECUTING = 4'b1000;
function automatic [31:0] jal;
input [4:0] rd;
input [20:0] imm;
jal = {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h6f};
endfunction
function automatic [31:0] slli;
input [4:0] rd;
input [4:0] rs1;
input [5:0] shamt;
slli = {6'b0, shamt[5:0], rs1, 3'h1, rd, 7'h13};
endfunction
function automatic [31:0] srli;
input [4:0] rd;
input [4:0] rs1;
input [5:0] shamt;
srli = {6'b0, shamt[5:0], rs1, 3'h5, rd, 7'h13};
endfunction
function automatic [31:0] load;
input [2:0] size;
input [4:0] dest;
input [4:0] base;
input [11:0] offset;
load = {offset[11:0], base, size, dest, 7'h03};
endfunction
function automatic [31:0] auipc;
input [4:0] rd;
input [20:0] imm;
auipc = {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h17};
endfunction
function automatic [31:0] store;
input [2:0] size;
input [4:0] src;
input [4:0] base;
input [11:0] offset;
store = {offset[11:5], src, base, size, offset[4:0], 7'h23};
endfunction
function automatic [31:0] csrw;
input [11:0] csr;
input [4:0] rs1;
csrw = {csr, rs1, 3'h1, 5'h0, 7'h73};
endfunction
function automatic [31:0] csrr;
input [11:0] csr;
input [4:0] dest;
csrr = {csr, 5'h0, 3'h2, dest, 7'h73};
endfunction
reg[3:0] state_d, state_q;
reg[31:0] rdata_d, rdata_q;
reg halted_d, halted_q;
reg resuming_d, resuming_q;
reg resume, go, going;
reg fwd_rom_q;
reg data_valid;
reg cmdbusy;
reg halted_aligned;
reg rvalid_q;
wire fwd_rom_d;
wire[31:0] rom_rdata;
reg[31:0] data_bits;
reg[9:0][31:0] abstract_cmd;
reg unsupported_command;
reg cmderror_valid;
reg[2:0] cmderror;
reg exception;
wire[11:0] progbuf_baseaddr = Progbuf0Addr;
wire[11:0] abstractcmd_baseaddr = AbstractCmd0Addr;
wire[7:0] cmd_type = cmd_i[31:24];
wire cmd_postexec = cmd_i[18];
wire cmd_transfer = cmd_i[17];
wire cmd_write = cmd_i[16];
wire[15:0] cmd_regno = cmd_i[15:0];
wire[2:0] cmd_aarsize = cmd_i[22:20];
wire cmd_aarpostincrement = cmd_i[19];
wire[31:0] word_mux;
assign word_mux = fwd_rom_q ? rom_rdata : rdata_q;
assign rdata_o = word_mux;
assign halted_o = halted_q;
assign resumeack_o = resuming_q;
assign gnt_o = req_i;
assign rvalid_o = rvalid_q;
always @ (*) begin
state_d = state_q;
resume = 1'b0;
go = 1'b0;
cmdbusy = 1'b1;
cmderror_valid = 1'b0;
cmderror = CmdErrorNone;
case (state_q)
S_IDLE: begin
cmdbusy = 1'b0;
if (resumereq_i && (!resuming_q) &&
halted_q && (!haltreq_i)) begin
state_d = S_RESUME;
end
if (cmd_valid_i) begin
if (!halted_q) begin
cmderror_valid = 1'b1;
cmderror = CmdErrorHaltResume;
end else if (unsupported_command) begin
cmderror_valid = 1'b1;
cmderror = CmdErrorNotSupport;
end else begin
state_d = S_GO;
end
end
end
S_GO: begin
cmdbusy = 1'b1;
go = 1'b1;
if (going) begin
state_d = S_CMD_EXECUTING;
end
end
S_RESUME: begin
resume = 1'b1;
cmdbusy = 1'b1;
if (resuming_q) begin
state_d = S_IDLE;
end
end
S_CMD_EXECUTING: begin
cmdbusy = 1'b1;
go = 1'b0;
if (halted_aligned) begin
state_d = S_IDLE;
end
end
default:;
endcase
if (exception) begin
cmderror_valid = 1'b1;
cmderror = CmdErrorException;
end
end
assign cmderror_valid_o = cmderror_valid;
assign cmderror_o = cmderror;
assign cmdbusy_o = cmdbusy;
always @ (*) begin
rdata_d = rdata_q;
halted_d = halted_q;
resuming_d = resuming_q;
going = 1'b0;
exception = 1'b0;
halted_aligned = 1'b0;
data_valid = 1'b0;
data_bits = data_i;
if (clear_resumeack_i) begin
resuming_d = 1'b0;
end
if (ndmreset_i & (!haltreq_i)) begin
halted_d = 1'b0;
end
// write
if (req_i & we_i) begin
case (addr_i[DbgAddressBits-1:0])
HaltedAddr: begin
halted_d = 1'b1;
halted_aligned = 1'b1;
end
GoingAddr: begin
going = 1'b1;
end
ResumingAddr: begin
halted_d = 1'b0;
resuming_d = 1'b1;
end
ExceptionAddr: begin
exception = 1'b1;
end
Data0Addr, Data1Addr, Data2Addr,
Data3Addr, Data4Addr: begin
data_valid = 1'b1;
if (be_i[0])
data_bits[7:0] = wdata_i[7:0];
if (be_i[1])
data_bits[15:8] = wdata_i[15:8];
if (be_i[2])
data_bits[23:16] = wdata_i[23:16];
if (be_i[3])
data_bits[31:24] = wdata_i[31:24];
end
default:;
endcase
// read
end else if (req_i & (!we_i)) begin
case (addr_i[DbgAddressBits-1:0])
WhereToAddr: begin
if (cmdbusy & (cmd_type == CmdAccessRegister)) begin
// execute program buf
if (cmd_postexec) begin
rdata_d = jal(5'h0, {9'h0, progbuf_baseaddr-WhereToAddr});
// execute command
end else begin
rdata_d = jal(5'h0, {9'h0, abstractcmd_baseaddr-WhereToAddr});
end
end
end
// harts are polling for flags here
FlagsBaseAddr: begin
rdata_d = {30'b0, resume, go};
end
Data0Addr, Data1Addr, Data2Addr, Data3Addr,
Data4Addr: begin
rdata_d = data_i;
end
Progbuf0Addr, Progbuf1Addr, Progbuf2Addr, Progbuf3Addr,
Progbuf4Addr, Progbuf5Addr, Progbuf6Addr, Progbuf7Addr,
Progbuf8Addr, Progbuf9Addr: begin
rdata_d = progbuf_i[addr_i[DbgAddressBits-1:2] -
progbuf_baseaddr[DbgAddressBits-1:2]];
end
AbstractCmd0Addr, AbstractCmd1Addr, AbstractCmd2Addr, AbstractCmd3Addr,
AbstractCmd4Addr, AbstractCmd5Addr, AbstractCmd6Addr, AbstractCmd7Addr,
AbstractCmd8Addr, AbstractCmd9Addr: begin
rdata_d = abstract_cmd[addr_i[DbgAddressBits-1:2] -
abstractcmd_baseaddr[DbgAddressBits-1:2]];
end
default:;
endcase
end
end
assign data_valid_o = data_valid;
assign data_o = data_bits;
always @ (*) begin
unsupported_command = 1'b0;
abstract_cmd[0] = illegal;
abstract_cmd[1] = auipc(5'd10, 21'd0); // auipc a0, 0
abstract_cmd[2] = srli(5'd10, 5'd10, 6'd12); // srli a0, a0, 12
abstract_cmd[3] = slli(5'd10, 5'd10, 6'd12); // slli a0, a0, 12
abstract_cmd[4] = nop;
abstract_cmd[5] = nop;
abstract_cmd[6] = nop;
abstract_cmd[7] = nop;
abstract_cmd[8] = csrr(`CSR_DSCRATCH1, 5'd10); // csrr dscratch1, a0 恢复a0寄存器的值
abstract_cmd[9] = ebreak;
case (cmd_type)
CmdAccessRegister: begin
// unsupported reg size
if (cmd_aarsize > 3'h2 || cmd_aarpostincrement || cmd_regno >= 16'h1020) begin
abstract_cmd[0] = ebreak;
unsupported_command = 1'b1;
end else begin
// store a0 in dscratch1
abstract_cmd[0] = csrw(`CSR_DSCRATCH1, 5'd10); // csrw dscratch1, a0 保存a0寄存器的值
// write regs
if (cmd_transfer && cmd_write) begin
// a0
if (cmd_regno[12] && (cmd_regno[4:0] == 5'd10)) begin
// store s0 in dscratch
abstract_cmd[4] = csrw(`CSR_DSCRATCH0, 5'd8);
// load from data register
abstract_cmd[5] = load(cmd_aarsize, 5'd8, LoadBaseAddr, `DataBaseAddr);
// and store it in the corresponding CSR
abstract_cmd[6] = csrw(`CSR_DSCRATCH1, 5'd8);
// restore s0 again from dscratch
abstract_cmd[7] = csrr(`CSR_DSCRATCH0, 5'd8);
// GPR access
end else if (cmd_regno[12]) begin
abstract_cmd[4] = load(cmd_aarsize, cmd_regno[4:0], LoadBaseAddr, `DataBaseAddr);
// CSR access
end else begin
// data register to CSR
// store s0 in dscratch
abstract_cmd[4] = csrw(`CSR_DSCRATCH0, 5'd8);
// load from data register
abstract_cmd[5] = load(cmd_aarsize, 5'd8, LoadBaseAddr, `DataBaseAddr);
// and store it in the corresponding CSR
abstract_cmd[6] = csrw(cmd_regno[11:0], 5'd8);
// restore s0 again from dscratch
abstract_cmd[7] = csrr(`CSR_DSCRATCH0, 5'd8);
end
// read regs
end else if (cmd_transfer && (!cmd_write)) begin
// a0
if (cmd_regno[12] && (cmd_regno[4:0] == 5'd10)) begin
// store s0 in dscratch
abstract_cmd[4] = csrw(`CSR_DSCRATCH0, 5'd8);
// read value from CSR into s0
abstract_cmd[5] = csrr(`CSR_DSCRATCH1, 5'd8);
// and store s0 into data section
abstract_cmd[6] = store(cmd_aarsize, 5'd8, LoadBaseAddr, `DataBaseAddr);
// restore s0 again from dscratch
abstract_cmd[7] = csrr(`CSR_DSCRATCH0, 5'd8);
// GPR access
end else if (cmd_regno[12]) begin
abstract_cmd[4] = store(cmd_aarsize, cmd_regno[4:0], LoadBaseAddr, `DataBaseAddr);
// CSR access
end else begin
// CSR register to data
// store s0 in dscratch
abstract_cmd[4] = csrw(`CSR_DSCRATCH0, 5'd8);
// read value from CSR into s0
abstract_cmd[5] = csrr(cmd_regno[11:0], 5'd8);
// and store s0 into data section
abstract_cmd[6] = store(cmd_aarsize, 5'd8, LoadBaseAddr, `DataBaseAddr);
// restore s0 again from dscratch
abstract_cmd[7] = csrr(`CSR_DSCRATCH0, 5'd8);
end
end
end
if (cmd_postexec && (!unsupported_command)) begin
// issue a nop, we will automatically run into the program buffer
abstract_cmd[9] = nop;
end
end
// not supported at the moment:
// CmdQuickAccess:;
// CmdAccessMemory:;
default: begin
unsupported_command = 1'b1;
abstract_cmd[0] = ebreak;
end
endcase
end
wire[31:0] rom_addr;
assign rom_addr = addr_i;
assign fwd_rom_d = addr_i[DbgAddressBits-1:0] >= `HaltAddress;
debug_rom u_debug_rom (
.clk_i ( clk ),
.req_i ( req_i ),
.addr_i ( rom_addr ),
.rdata_o ( rom_rdata )
);
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
rdata_q <= 32'h0;
fwd_rom_q <= 1'b0;
halted_q <= 1'b0;
resuming_q <= 1'b0;
rvalid_q <= 1'b0;
end else begin
rdata_q <= rdata_d;
fwd_rom_q <= fwd_rom_d;
halted_q <= halted_d;
resuming_q <= resuming_d;
rvalid_q <= req_i;
end
end
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= S_IDLE;
end else begin
state_q <= state_d;
end
end
endmodule

191
rtl/debug/jtag_sba.sv Normal file
View File

@ -0,0 +1,191 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_sba(
input wire clk,
input wire rst_n,
input wire [31:0] sbaddress_i,
input wire sbaddress_write_valid_i,
input wire sbreadonaddr_i,
output wire [31:0] sbaddress_o,
input wire sbautoincrement_i,
input wire [2:0] sbaccess_i,
input wire sbreadondata_i,
input wire [31:0] sbdata_i,
input wire sbdata_read_valid_i,
input wire sbdata_write_valid_i,
output wire [31:0] sbdata_o,
output wire sbdata_valid_o,
output wire sbbusy_o,
output wire [2:0] sberror_o,
output wire master_req_o,
input wire master_gnt_i,
input wire master_rvalid_i,
output wire master_we_o,
output wire [3:0] master_be_o,
output wire [31:0] master_addr_o,
output wire [31:0] master_wdata_o,
input wire [31:0] master_rdata_i,
input wire master_err_i
);
localparam S_IDLE = 4'b0001;
localparam S_READ = 4'b0010;
localparam S_WAIT = 4'b0100;
localparam S_WRITE = 4'b1000;
reg[3:0] state_d, state_q;
reg[2:0] sberror;
reg[3:0] be_mask;
reg[1:0] be_index;
reg master_req;
reg master_we;
reg[3:0] master_be;
reg[31:0] master_addr;
reg[31:0] master_wdata;
reg[31:0] sbaddress;
wire[31:0] sbaddress_new;
assign sbaddress_new = sbaddress_i + (32'h1 << sbaccess_i);
assign sbbusy_o = (state_q != S_IDLE);
always @ (*) begin
be_mask = 4'b0;
be_index = sbaddress_i[1:0];
// generate byte enable mask
case (sbaccess_i)
3'b000: begin
be_mask[be_index] = 1'b1;
end
3'b001: begin
if (be_index == 2'h0) begin
be_mask[1:0] = 2'b11;
end else if (be_index == 2'h2) begin
be_mask[3:2] = 2'b11;
end
end
3'b010: begin
be_mask = 4'b1111;
end
default:;
endcase
end
// 访存状态机
always @ (*) begin
state_d = state_q;
sbaddress = sbaddress_i;
master_addr = sbaddress_i;
master_wdata = sbdata_i;
master_req = 1'b0;
master_be = 4'b0;
master_we = 1'b0;
sberror = 3'b0;
case (state_q)
S_IDLE: begin
// debugger requested a read
if (sbaddress_write_valid_i && sbreadonaddr_i) begin
state_d = S_READ;
end
// debugger requested a write
if (sbdata_write_valid_i) begin
state_d = S_WRITE;
end
// perform another read
if (sbdata_read_valid_i && sbreadondata_i) begin
state_d = S_READ;
end
end
// 读内存
S_READ: begin
master_req = 1'b1;
master_be = 4'b1111;
if (master_gnt_i) begin
state_d = S_WAIT;
end
end
// 写内存
S_WRITE: begin
master_req = 1'b1;
master_be = be_mask;
master_we = 1'b1;
if (master_gnt_i) begin
state_d = S_WAIT;
end
end
// 等待读写完成
S_WAIT: begin
if (master_rvalid_i) begin
state_d = S_IDLE;
if (sbautoincrement_i) begin
sbaddress = sbaddress_new;
end
end
end
default: state_d = S_IDLE;
endcase
if ((sbaccess_i > 3'h2) & (state_q != S_IDLE)) begin
master_req = 1'b0;
state_d = S_IDLE;
sberror = 3'h3;
end
end
assign master_req_o = master_req;
assign master_we_o = master_we;
assign master_be_o = master_be;
assign master_addr_o = master_addr;
assign master_wdata_o = master_wdata;
assign sbdata_valid_o = master_rvalid_i & (state_q == S_WAIT);
assign sbdata_o = master_rdata_i;
assign sberror_o = sberror;
assign sbaddress_o = sbaddress;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= S_IDLE;
end else begin
state_q <= state_d;
end
end
endmodule

192
rtl/debug/jtag_tap.sv Normal file
View File

@ -0,0 +1,192 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_tap #(
parameter DMI_ADDR_BITS = 7,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2,
parameter IR_BITS = 5,
parameter TAP_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
parameter DTM_RESP_BITS = TAP_REQ_BITS
)(
input wire jtag_tck_i, // JTAG test clock pad
input wire jtag_tdi_i, // JTAG test data input pad
input wire jtag_tms_i, // JTAG test mode select pad
input wire jtag_trst_ni, // JTAG test reset pad
output wire jtag_tdo_o, // JTAG test data output pad
output wire tap_req_o,
output wire[TAP_REQ_BITS-1:0] tap_data_o,
output wire dmireset_o,
input wire[DTM_RESP_BITS-1:0] dtm_data_i,
input wire[31:0] idcode_i,
input wire[31:0] dtmcs_i
);
localparam SHIFT_REG_BITS = TAP_REQ_BITS;
localparam TEST_LOGIC_RESET = 16'h0001;
localparam RUN_TEST_IDLE = 16'h0002;
localparam SELECT_DR = 16'h0004;
localparam CAPTURE_DR = 16'h0008;
localparam SHIFT_DR = 16'h0010;
localparam EXIT1_DR = 16'h0020;
localparam PAUSE_DR = 16'h0040;
localparam EXIT2_DR = 16'h0080;
localparam UPDATE_DR = 16'h0100;
localparam SELECT_IR = 16'h0200;
localparam CAPTURE_IR = 16'h0400;
localparam SHIFT_IR = 16'h0800;
localparam EXIT1_IR = 16'h1000;
localparam PAUSE_IR = 16'h2000;
localparam EXIT2_IR = 16'h4000;
localparam UPDATE_IR = 16'h8000;
// DTM regs
localparam REG_BYPASS = 5'b11111;
localparam REG_IDCODE = 5'b00001;
localparam REG_DMI = 5'b10001;
localparam REG_DTMCS = 5'b10000;
reg[IR_BITS-1:0] ir_reg;
reg[SHIFT_REG_BITS-1:0] shift_reg;
reg[15:0] tap_state;
reg[15:0] next_state;
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
tap_state <= TEST_LOGIC_RESET;
end else begin
tap_state <= next_state;
end
end
// state switch
always @ (*) begin
case (tap_state)
TEST_LOGIC_RESET : next_state = jtag_tms_i ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
RUN_TEST_IDLE : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
SELECT_DR : next_state = jtag_tms_i ? SELECT_IR : CAPTURE_DR;
CAPTURE_DR : next_state = jtag_tms_i ? EXIT1_DR : SHIFT_DR;
SHIFT_DR : next_state = jtag_tms_i ? EXIT1_DR : SHIFT_DR;
EXIT1_DR : next_state = jtag_tms_i ? UPDATE_DR : PAUSE_DR;
PAUSE_DR : next_state = jtag_tms_i ? EXIT2_DR : PAUSE_DR;
EXIT2_DR : next_state = jtag_tms_i ? UPDATE_DR : SHIFT_DR;
UPDATE_DR : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
SELECT_IR : next_state = jtag_tms_i ? TEST_LOGIC_RESET : CAPTURE_IR;
CAPTURE_IR : next_state = jtag_tms_i ? EXIT1_IR : SHIFT_IR;
SHIFT_IR : next_state = jtag_tms_i ? EXIT1_IR : SHIFT_IR;
EXIT1_IR : next_state = jtag_tms_i ? UPDATE_IR : PAUSE_IR;
PAUSE_IR : next_state = jtag_tms_i ? EXIT2_IR : PAUSE_IR;
EXIT2_IR : next_state = jtag_tms_i ? UPDATE_IR : SHIFT_IR;
UPDATE_IR : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
default : next_state = TEST_LOGIC_RESET;
endcase
end
// IR or DR shift
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
shift_reg <= {SHIFT_REG_BITS{1'b0}};
end else begin
case (tap_state)
// IR
CAPTURE_IR: shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}}, 1'b1}; //JTAG spec says it must be 2'b01
SHIFT_IR : shift_reg <= {{(SHIFT_REG_BITS-IR_BITS){1'b0}}, jtag_tdi_i, shift_reg[IR_BITS-1:1]}; // right shift 1 bit
// DR
CAPTURE_DR: case (ir_reg)
REG_BYPASS : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, idcode_i};
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, dtmcs_i};
REG_DMI : shift_reg <= dtm_data_i;
default : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
endcase
SHIFT_DR : case (ir_reg)
REG_BYPASS : shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}}, jtag_tdi_i}; // in = out
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, jtag_tdi_i, shift_reg[31:1]}; // right shift 1 bit
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, jtag_tdi_i, shift_reg[31:1]}; // right shift 1 bit
REG_DMI : shift_reg <= {jtag_tdi_i, shift_reg[SHIFT_REG_BITS-1:1]}; // right shift 1 bit
default : shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}} , jtag_tdi_i};
endcase
endcase
end
end
reg tap_req_q;
reg[TAP_REQ_BITS-1:0] tap_data_q;
// send request to DTM module
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
tap_req_q <= 1'b0;
tap_data_q <= {TAP_REQ_BITS{1'b0}};
end else begin
if ((tap_state == UPDATE_DR) && (ir_reg == REG_DMI)) begin
tap_req_q <= 1'b1;
tap_data_q <= shift_reg;
end else begin
tap_req_q <= 1'b0;
end
end
end
assign tap_req_o = tap_req_q;
assign tap_data_o = tap_data_q;
// ir_reg
always @ (negedge jtag_tck_i) begin
if (tap_state == TEST_LOGIC_RESET) begin
ir_reg <= REG_IDCODE;
end else if (tap_state == UPDATE_IR) begin
ir_reg <= shift_reg[IR_BITS-1:0];
end
end
reg jtag_tdo_q;
// TDO output
always @ (negedge jtag_tck_i) begin
if ((tap_state == SHIFT_IR) || (tap_state == SHIFT_DR)) begin
jtag_tdo_q <= shift_reg[0];
end else begin
jtag_tdo_q <= 1'b0;
end
end
assign jtag_tdo_o = jtag_tdo_q;
reg dmireset_q;
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
dmireset_q <= 1'b0;
end else begin
if ((tap_state == UPDATE_DR) && (ir_reg == REG_DTMCS)) begin
dmireset_q <= shift_reg[16];
end else begin
dmireset_q <= 1'b0;
end
end
end
assign dmireset_o = dmireset_q;
endmodule

168
rtl/debug/jtag_top.sv Normal file
View File

@ -0,0 +1,168 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_top(
input wire clk_i,
input wire rst_ni,
output wire debug_req_o,
output wire ndmreset_o,
output wire halted_o,
input wire jtag_tck_i, // JTAG test clock pad
input wire jtag_tdi_i, // JTAG test data input pad
input wire jtag_tms_i, // JTAG test mode select pad
input wire jtag_trst_ni, // JTAG test reset pad
output wire jtag_tdo_o, // JTAG test data output pad
output wire master_req_o,
input wire master_gnt_i,
input wire master_rvalid_i,
output wire master_we_o,
output wire [3:0] master_be_o,
output wire [31:0] master_addr_o,
output wire [31:0] master_wdata_o,
input wire [31:0] master_rdata_i,
input wire master_err_i,
input wire slave_req_i,
input wire slave_we_i,
input wire [31:0] slave_addr_i,
input wire [3:0] slave_be_i,
input wire [31:0] slave_wdata_i,
output wire slave_gnt_o,
output wire slave_rvalid_o,
output wire [31:0] slave_rdata_o
);
// addr + data + op = 7 + 32 + 2 = 41
localparam DMI_DATA_WIDTH = 41;
wire [DMI_DATA_WIDTH-1:0] dm_to_dmi_data;
wire dm_to_dmi_valid;
wire dm_to_dmi_ready;
wire [DMI_DATA_WIDTH-1:0] dmi_to_dm_data;
wire dmi_to_dm_valid;
wire dmi_to_dm_ready;
jtag_dm #(
) u_jtag_dm (
.clk (clk_i),
.rst_n (rst_ni),
.dmi_data_i (dmi_to_dm_data),
.dmi_valid_i (dmi_to_dm_valid),
.dm_ready_o (dm_to_dmi_ready),
.dm_data_o (dm_to_dmi_data),
.dm_valid_o (dm_to_dmi_valid),
.dmi_ready_i (dmi_to_dm_ready),
.debug_req_o (debug_req_o),
.ndmreset_o (ndmreset_o),
.halted_o (halted_o),
.master_req_o (master_req_o),
.master_gnt_i (master_gnt_i),
.master_rvalid_i(master_rvalid_i),
.master_we_o (master_we_o),
.master_be_o (master_be_o),
.master_addr_o (master_addr_o),
.master_wdata_o (master_wdata_o),
.master_rdata_i (master_rdata_i),
.master_err_i (master_err_i),
.slave_req_i (slave_req_i),
.slave_we_i (slave_we_i),
.slave_addr_i (slave_addr_i),
.slave_be_i (slave_be_i),
.slave_wdata_i (slave_wdata_i),
.slave_gnt_o (slave_gnt_o),
.slave_rvalid_o (slave_rvalid_o),
.slave_rdata_o (slave_rdata_o)
);
wire [DMI_DATA_WIDTH-1:0] dtm_to_dmi_data;
wire dtm_to_dmi_valid;
wire dtm_to_dmi_ready;
wire [DMI_DATA_WIDTH-1:0] dmi_to_dtm_data;
wire dmi_to_dtm_valid;
wire dmi_to_dtm_ready;
jtag_dmi #(
) u_jtag_dmi (
.jtag_tck_i (jtag_tck_i),
.jtag_trst_ni (jtag_trst_ni),
.jtag_data_i (dtm_to_dmi_data),
.jtag_valid_i (dtm_to_dmi_valid),
.jtag_ready_o (dmi_to_dtm_ready),
.jtag_data_o (dmi_to_dtm_data),
.jtag_valid_o (dmi_to_dtm_valid),
.jtag_ready_i (dtm_to_dmi_ready),
.clk_i (clk_i),
.rst_ni (rst_ni),
.core_data_i (dm_to_dmi_data),
.core_valid_i (dm_to_dmi_valid),
.core_ready_o (dmi_to_dm_ready),
.core_data_o (dmi_to_dm_data),
.core_valid_o (dmi_to_dm_valid),
.core_ready_i (dm_to_dmi_ready)
);
wire tap_to_dtm_req;
wire [DMI_DATA_WIDTH-1:0] tap_to_dtm_data;
wire [DMI_DATA_WIDTH-1:0] dtm_to_tap_data;
wire [31:0] idcode;
wire [31:0] dtmcs;
wire dmireset;
jtag_dtm #(
) u_jtag_dtm (
.jtag_tck_i (jtag_tck_i),
.jtag_trst_ni (jtag_trst_ni),
.dtm_data_o (dtm_to_dmi_data),
.dtm_valid_o (dtm_to_dmi_valid),
.dmi_ready_i (dmi_to_dtm_ready),
.dmi_data_i (dmi_to_dtm_data),
.dmi_valid_i (dmi_to_dtm_valid),
.dtm_ready_o (dtm_to_dmi_ready),
.tap_req_i (tap_to_dtm_req),
.tap_data_i (tap_to_dtm_data),
.dmireset_i (dmireset),
.data_o (dtm_to_tap_data),
.idcode_o (idcode),
.dtmcs_o (dtmcs)
);
jtag_tap #(
) u_jtag_tap (
.jtag_tck_i (jtag_tck_i),
.jtag_tdi_i (jtag_tdi_i),
.jtag_tms_i (jtag_tms_i),
.jtag_trst_ni (jtag_trst_ni),
.jtag_tdo_o (jtag_tdo_o),
.tap_req_o (tap_to_dtm_req),
.tap_data_o (tap_to_dtm_data),
.dmireset_o (dmireset),
.dtm_data_i (dtm_to_tap_data),
.idcode_i (idcode),
.dtmcs_i (dtmcs)
);
endmodule

View File

@ -1,108 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "../core/defines.v"
// JTAG
module jtag_top #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2)(
input wire clk,
input wire jtag_rst_n,
input wire jtag_pin_TCK,
input wire jtag_pin_TMS,
input wire jtag_pin_TDI,
output wire jtag_pin_TDO,
output wire reg_we_o,
output wire[4:0] reg_addr_o,
output wire[31:0] reg_wdata_o,
input wire[31:0] reg_rdata_i,
output wire mem_we_o,
output wire[31:0] mem_addr_o,
output wire[31:0] mem_wdata_o,
input wire[31:0] mem_rdata_i,
output wire op_req_o,
output wire halt_req_o,
output wire reset_req_o
);
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
// jtag_driver
wire dtm_ack_o;
wire dtm_req_valid_o;
wire[DTM_REQ_BITS - 1:0] dtm_req_data_o;
// jtag_dm
wire dm_ack_o;
wire[DM_RESP_BITS-1:0] dm_resp_data_o;
wire dm_resp_valid_o;
wire dm_op_req_o;
wire dm_halt_req_o;
wire dm_reset_req_o;
jtag_driver #(
.DMI_ADDR_BITS(DMI_ADDR_BITS),
.DMI_DATA_BITS(DMI_DATA_BITS),
.DMI_OP_BITS(DMI_OP_BITS)
) u_jtag_driver(
.rst_n(jtag_rst_n),
.jtag_TCK(jtag_pin_TCK),
.jtag_TDI(jtag_pin_TDI),
.jtag_TMS(jtag_pin_TMS),
.jtag_TDO(jtag_pin_TDO),
.dm_resp_i(dm_resp_valid_o),
.dm_resp_data_i(dm_resp_data_o),
.dtm_ack_o(dtm_ack_o),
.dm_ack_i(dm_ack_o),
.dtm_req_valid_o(dtm_req_valid_o),
.dtm_req_data_o(dtm_req_data_o)
);
jtag_dm #(
.DMI_ADDR_BITS(DMI_ADDR_BITS),
.DMI_DATA_BITS(DMI_DATA_BITS),
.DMI_OP_BITS(DMI_OP_BITS)
) u_jtag_dm(
.clk(clk),
.rst_n(jtag_rst_n),
.dm_ack_o(dm_ack_o),
.dtm_req_valid_i(dtm_req_valid_o),
.dtm_req_data_i(dtm_req_data_o),
.dtm_ack_i(dtm_ack_o),
.dm_resp_data_o(dm_resp_data_o),
.dm_resp_valid_o(dm_resp_valid_o),
.dm_reg_we_o(reg_we_o),
.dm_reg_addr_o(reg_addr_o),
.dm_reg_wdata_o(reg_wdata_o),
.dm_reg_rdata_i(reg_rdata_i),
.dm_mem_we_o(mem_we_o),
.dm_mem_addr_o(mem_addr_o),
.dm_mem_wdata_o(mem_wdata_o),
.dm_mem_rdata_i(mem_rdata_i),
.dm_op_req_o(op_req_o),
.dm_halt_req_o(halt_req_o),
.dm_reset_req_o(reset_req_o)
);
endmodule

View File

@ -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

View File

@ -0,0 +1,75 @@
/*
Copyright 2023 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module bootrom_top(
input wire clk_i,
input wire rst_ni,
input wire req_i,
input wire we_i,
input wire [ 3:0] be_i,
input wire [31:0] addr_i,
input wire [31:0] data_i,
output wire gnt_o,
output wire rvalid_o,
output wire [31:0] data_o
);
localparam RomSize = 5;
wire [RomSize-1:0][31:0] mem;
assign mem = {
32'h0000006f,
32'h000500e7,
32'h02000537,
32'h0005a023,
32'h02c005b7
};
reg [5:0] addr_q;
always @(posedge clk_i) begin
if (req_i) begin
addr_q <= addr_i[7:2];
end
end
reg rvalid_q;
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
rvalid_q <= 1'b0;
end else begin
rvalid_q <= req_i;
end
end
reg[31:0] rdata;
always @(*) begin
rdata = 32'h0;
if (addr_q < 6'd38) begin
rdata = mem[addr_q];
end
end
assign gnt_o = req_i;
assign data_o = rdata;
assign rvalid_o = rvalid_q;
endmodule

View File

@ -1,98 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// GPIO
module gpio(
input wire clk,
input wire rst,
input wire we_i,
input wire[31:0] addr_i,
input wire[31:0] data_i,
output reg[31:0] data_o,
input wire[1:0] io_pin_i,
output wire[31:0] reg_ctrl,
output wire[31:0] reg_data
);
// GPIO
localparam GPIO_CTRL = 4'h0;
// GPIO
localparam GPIO_DATA = 4'h4;
// 21IO16IO
// 0: 12
reg[31:0] gpio_ctrl;
//
reg[31:0] gpio_data;
assign reg_ctrl = gpio_ctrl;
assign reg_data = gpio_data;
//
always @ (posedge clk) begin
if (rst == 1'b0) begin
gpio_data <= 32'h0;
gpio_ctrl <= 32'h0;
end else begin
if (we_i == 1'b1) begin
case (addr_i[3:0])
GPIO_CTRL: begin
gpio_ctrl <= data_i;
end
GPIO_DATA: begin
gpio_data <= data_i;
end
endcase
end else begin
if (gpio_ctrl[1:0] == 2'b10) begin
gpio_data[0] <= io_pin_i[0];
end
if (gpio_ctrl[3:2] == 2'b10) begin
gpio_data[1] <= io_pin_i[1];
end
end
end
end
//
always @ (*) begin
if (rst == 1'b0) begin
data_o = 32'h0;
end else begin
case (addr_i[3:0])
GPIO_CTRL: begin
data_o = gpio_ctrl;
end
GPIO_DATA: begin
data_o = gpio_data;
end
default: begin
data_o = 32'h0;
end
endcase
end
end
endmodule

View File

@ -0,0 +1,64 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "gpio",
clocking: [{clock: "clk_i", reset: "rst_ni"}],
bus_interfaces: [
{ protocol: "tlul", direction: "device" }
],
regwidth: "32",
registers: [
{ name: "IO_MODE",
desc: "gpio input/output mode register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "gpio input or output mode, 2 bits for each gpio",
}
]
}
{ name: "INT_MODE",
desc: "gpio interrupt mode register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "gpio interrupt mode, 2 bits for each gpio",
}
]
}
{ name: "INT_PENDING",
desc: "gpio interrupt pending register",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "15:0",
name: "GPIO_INT_PENDING",
swaccess: "rw1c",
desc: "gpio interrupt pending, 1 bits for each gpio",
}
]
}
{ name: "DATA",
desc: "gpio data register",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "15:0",
desc: "gpio input or output data, 1 bits for each gpio",
}
]
}
{ name: "FILTER",
desc: "gpio input filter enable register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "15:0",
desc: "gpio input filter enable, 1 bits for each gpio",
}
]
}
]
}

View File

@ -0,0 +1,176 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 目前最多支持16个GPIO
module gpio_core #(
parameter int GPIO_NUM = 2
)(
input logic clk_i,
input logic rst_ni,
output logic [GPIO_NUM-1:0] gpio_oe_o,
output logic [GPIO_NUM-1:0] gpio_data_o,
input logic [GPIO_NUM-1:0] gpio_data_i,
output logic irq_gpio0_o,
output logic irq_gpio1_o,
output logic irq_gpio2_4_o,
output logic irq_gpio5_7_o,
output logic irq_gpio8_o,
output logic irq_gpio9_o,
output logic irq_gpio10_12_o,
output logic irq_gpio13_15_o,
input logic reg_we_i,
input logic reg_re_i,
input logic [31:0] reg_wdata_i,
input logic [ 3:0] reg_be_i,
input logic [31:0] reg_addr_i,
output logic [31:0] reg_rdata_o
);
localparam logic [1:0] INTR_MODE_NONE = 2'd0;
localparam logic [1:0] INTR_MODE_RAISE_EDGE = 2'd1;
localparam logic [1:0] INTR_MODE_FALL_EDGE = 2'd2;
localparam logic [1:0] INTR_MODE_DOUBLE_EDGE = 2'd3;
localparam logic [1:0] GPIO_MODE_NONE = 2'd0;
localparam logic [1:0] GPIO_MODE_INPUT = 2'd1;
localparam logic [1:0] GPIO_MODE_OUTPUT = 2'd2;
import gpio_reg_pkg::*;
gpio_reg_pkg::gpio_reg2hw_t reg2hw;
gpio_reg_pkg::gpio_hw2reg_t hw2reg;
logic [GPIO_NUM-1:0] gpio_oe;
logic [GPIO_NUM-1:0] gpio_ie;
logic [GPIO_NUM-1:0] gpio_data;
logic [GPIO_NUM-1:0] gpio_filter_enable;
logic [GPIO_NUM-1:0] gpio_filter_data;
logic [GPIO_NUM-1:0] gpio_raise_detect;
logic [GPIO_NUM-1:0] gpio_fall_detect;
logic [GPIO_NUM-1:0] gpio_intr_trigge;
// 输入滤波使能
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_filter_enable
assign gpio_filter_enable[i] = reg2hw.filter.q[i];
end
// 输出使能
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_oe
assign gpio_oe[i] = reg2hw.io_mode.q[i*2+1:i*2] == GPIO_MODE_OUTPUT;
end
assign gpio_oe_o = gpio_oe;
// 输出数据
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_data
assign gpio_data[i] = reg2hw.data.q[i];
end
assign gpio_data_o = gpio_data;
// 输入使能
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_ie
assign gpio_ie[i] = reg2hw.io_mode.q[i*2+1:i*2] == GPIO_MODE_INPUT;
end
// 硬件写data数据
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_h2r_data
assign hw2reg.data.d[i] = gpio_ie[i] ? gpio_filter_data[i] : reg2hw.data.q[i];
end
// 硬件写data使能
assign hw2reg.data.de = |gpio_ie;
// 中断有效
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_intr_trigge
assign gpio_intr_trigge[i] = ((reg2hw.int_mode.q[i*2+1:i*2] == INTR_MODE_RAISE_EDGE) & gpio_raise_detect[i]) |
((reg2hw.int_mode.q[i*2+1:i*2] == INTR_MODE_FALL_EDGE) & gpio_fall_detect[i]) |
((reg2hw.int_mode.q[i*2+1:i*2] == INTR_MODE_DOUBLE_EDGE) & (gpio_raise_detect[i] | gpio_fall_detect[i]));
end
// 硬件写中断pending数据
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_intr_pending
assign hw2reg.int_pending.d[i] = gpio_intr_trigge[i] ? 1'b1 : reg2hw.int_pending.q[i];
end
// 硬件写中断pending使能
assign hw2reg.int_pending.de = |gpio_intr_trigge;
// 中断输出信号
if (GPIO_NUM >= 1) begin : g_num_ge_1
assign irq_gpio0_o = reg2hw.int_pending.q[0];
end
if (GPIO_NUM >= 2) begin : g_num_ge_2
assign irq_gpio1_o = reg2hw.int_pending.q[1];
end
if (GPIO_NUM >= 5) begin : g_num_ge_5
assign irq_gpio2_4_o = reg2hw.int_pending.q[2] | reg2hw.int_pending.q[3] | reg2hw.int_pending.q[4];
end
if (GPIO_NUM >= 8) begin : g_num_ge_8
assign irq_gpio5_7_o = reg2hw.int_pending.q[5] | reg2hw.int_pending.q[6] | reg2hw.int_pending.q[7];
end
if (GPIO_NUM >= 9) begin : g_num_ge_9
assign irq_gpio8_o = reg2hw.int_pending.q[8];
end
if (GPIO_NUM >= 10) begin : g_num_ge_10
assign irq_gpio9_o = reg2hw.int_pending.q[9];
end
if (GPIO_NUM >= 13) begin : g_num_ge_13
assign irq_gpio10_12_o = reg2hw.int_pending.q[10] | reg2hw.int_pending.q[11] | reg2hw.int_pending.q[12];
end
if (GPIO_NUM >= 16) begin : g_num_ge_16
assign irq_gpio13_15_o = reg2hw.int_pending.q[13] | reg2hw.int_pending.q[14] | reg2hw.int_pending.q[15];
end
// 沿检测
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_edge_detect
edge_detect u_edge_detect(
.clk_i (clk_i),
.rst_ni (rst_ni),
.sig_i (gpio_filter_data[i]),
.sig_o (),
.re_o (gpio_raise_detect[i]),
.fe_o (gpio_fall_detect[i])
);
end
// 输入信号滤波
for (genvar i = 0; i < GPIO_NUM; i = i + 1) begin : g_gpio_filter
prim_filter #(
.Cycles(8)
) gpio_filter (
.clk_i (clk_i),
.rst_ni (rst_ni),
.enable_i (gpio_filter_enable[i]),
.filter_i (gpio_data_i[i]),
.filter_o (gpio_filter_data[i])
);
end
gpio_reg_top u_gpio_reg_top (
.clk_i (clk_i),
.rst_ni (rst_ni),
.reg2hw (reg2hw),
.hw2reg (hw2reg),
.reg_we (reg_we_i),
.reg_re (reg_re_i),
.reg_wdata (reg_wdata_i),
.reg_be (reg_be_i),
.reg_addr (reg_addr_i),
.reg_rdata (reg_rdata_o)
);
endmodule

View File

@ -0,0 +1,87 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Register Package auto-generated by `reggen` containing data structure
package gpio_reg_pkg;
// Address widths within the block
parameter int BlockAw = 5;
////////////////////////////
// Typedefs for registers //
////////////////////////////
typedef struct packed {
logic [31:0] q;
} gpio_reg2hw_io_mode_reg_t;
typedef struct packed {
logic [31:0] q;
} gpio_reg2hw_int_mode_reg_t;
typedef struct packed {
logic [15:0] q;
} gpio_reg2hw_int_pending_reg_t;
typedef struct packed {
logic [15:0] q;
} gpio_reg2hw_data_reg_t;
typedef struct packed {
logic [15:0] q;
} gpio_reg2hw_filter_reg_t;
typedef struct packed {
logic [15:0] d;
logic de;
} gpio_hw2reg_int_pending_reg_t;
typedef struct packed {
logic [15:0] d;
logic de;
} gpio_hw2reg_data_reg_t;
// Register -> HW type
typedef struct packed {
gpio_reg2hw_io_mode_reg_t io_mode; // [111:80]
gpio_reg2hw_int_mode_reg_t int_mode; // [79:48]
gpio_reg2hw_int_pending_reg_t int_pending; // [47:32]
gpio_reg2hw_data_reg_t data; // [31:16]
gpio_reg2hw_filter_reg_t filter; // [15:0]
} gpio_reg2hw_t;
// HW -> register type
typedef struct packed {
gpio_hw2reg_int_pending_reg_t int_pending; // [33:17]
gpio_hw2reg_data_reg_t data; // [16:0]
} gpio_hw2reg_t;
// Register offsets
parameter logic [BlockAw-1:0] GPIO_IO_MODE_OFFSET = 5'h0;
parameter logic [BlockAw-1:0] GPIO_INT_MODE_OFFSET = 5'h4;
parameter logic [BlockAw-1:0] GPIO_INT_PENDING_OFFSET = 5'h8;
parameter logic [BlockAw-1:0] GPIO_DATA_OFFSET = 5'hc;
parameter logic [BlockAw-1:0] GPIO_FILTER_OFFSET = 5'h10;
// Register index
typedef enum int {
GPIO_IO_MODE,
GPIO_INT_MODE,
GPIO_INT_PENDING,
GPIO_DATA,
GPIO_FILTER
} gpio_id_e;
// Register width information to check illegal writes
parameter logic [3:0] GPIO_PERMIT [5] = '{
4'b1111, // index[0] GPIO_IO_MODE
4'b1111, // index[1] GPIO_INT_MODE
4'b0011, // index[2] GPIO_INT_PENDING
4'b0011, // index[3] GPIO_DATA
4'b0011 // index[4] GPIO_FILTER
};
endpackage

View File

@ -0,0 +1,270 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Register Top module auto-generated by `reggen`
module gpio_reg_top (
input logic clk_i,
input logic rst_ni,
// To HW
output gpio_reg_pkg::gpio_reg2hw_t reg2hw, // Write
input gpio_reg_pkg::gpio_hw2reg_t hw2reg, // Read
input logic reg_we,
input logic reg_re,
input logic [31:0] reg_wdata,
input logic [ 3:0] reg_be,
input logic [31:0] reg_addr,
output logic [31:0] reg_rdata
);
import gpio_reg_pkg::* ;
localparam int AW = 5;
localparam int DW = 32;
localparam int DBW = DW/8; // Byte Width
logic reg_error;
logic addrmiss, wr_err;
logic [DW-1:0] reg_rdata_next;
assign reg_rdata = reg_rdata_next;
assign reg_error = wr_err;
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
// or <reg>_{wd|we|qs} if field == 1 or 0
logic io_mode_we;
logic [31:0] io_mode_qs;
logic [31:0] io_mode_wd;
logic int_mode_we;
logic [31:0] int_mode_qs;
logic [31:0] int_mode_wd;
logic int_pending_we;
logic [15:0] int_pending_qs;
logic [15:0] int_pending_wd;
logic data_we;
logic [15:0] data_qs;
logic [15:0] data_wd;
logic filter_we;
logic [15:0] filter_qs;
logic [15:0] filter_wd;
// Register instances
// R[io_mode]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_io_mode (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (io_mode_we),
.wd (io_mode_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.io_mode.q),
// to register interface (read)
.qs (io_mode_qs)
);
// R[int_mode]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_int_mode (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (int_mode_we),
.wd (int_mode_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.int_mode.q),
// to register interface (read)
.qs (int_mode_qs)
);
// R[int_pending]: V(False)
prim_subreg #(
.DW (16),
.SWACCESS("W1C"),
.RESVAL (16'h0)
) u_int_pending (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (int_pending_we),
.wd (int_pending_wd),
// from internal hardware
.de (hw2reg.int_pending.de),
.d (hw2reg.int_pending.d),
// to internal hardware
.qe (),
.q (reg2hw.int_pending.q),
// to register interface (read)
.qs (int_pending_qs)
);
// R[data]: V(False)
prim_subreg #(
.DW (16),
.SWACCESS("RW"),
.RESVAL (16'h0)
) u_data (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (data_we),
.wd (data_wd),
// from internal hardware
.de (hw2reg.data.de),
.d (hw2reg.data.d),
// to internal hardware
.qe (),
.q (reg2hw.data.q),
// to register interface (read)
.qs (data_qs)
);
// R[filter]: V(False)
prim_subreg #(
.DW (16),
.SWACCESS("RW"),
.RESVAL (16'h0)
) u_filter (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (filter_we),
.wd (filter_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.filter.q),
// to register interface (read)
.qs (filter_qs)
);
logic [4:0] addr_hit;
always_comb begin
addr_hit = '0;
addr_hit[0] = (reg_addr == GPIO_IO_MODE_OFFSET);
addr_hit[1] = (reg_addr == GPIO_INT_MODE_OFFSET);
addr_hit[2] = (reg_addr == GPIO_INT_PENDING_OFFSET);
addr_hit[3] = (reg_addr == GPIO_DATA_OFFSET);
addr_hit[4] = (reg_addr == GPIO_FILTER_OFFSET);
end
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
// Check sub-word write is permitted
always_comb begin
wr_err = (reg_we &
((addr_hit[0] & (|(GPIO_PERMIT[0] & ~reg_be))) |
(addr_hit[1] & (|(GPIO_PERMIT[1] & ~reg_be))) |
(addr_hit[2] & (|(GPIO_PERMIT[2] & ~reg_be))) |
(addr_hit[3] & (|(GPIO_PERMIT[3] & ~reg_be))) |
(addr_hit[4] & (|(GPIO_PERMIT[4] & ~reg_be)))));
end
assign io_mode_we = addr_hit[0] & reg_we & !reg_error;
assign io_mode_wd = reg_wdata[31:0];
assign int_mode_we = addr_hit[1] & reg_we & !reg_error;
assign int_mode_wd = reg_wdata[31:0];
assign int_pending_we = addr_hit[2] & reg_we & !reg_error;
assign int_pending_wd = reg_wdata[15:0];
assign data_we = addr_hit[3] & reg_we & !reg_error;
assign data_wd = reg_wdata[15:0];
assign filter_we = addr_hit[4] & reg_we & !reg_error;
assign filter_wd = reg_wdata[15:0];
// Read data return
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
addr_hit[0]: begin
reg_rdata_next[31:0] = io_mode_qs;
end
addr_hit[1]: begin
reg_rdata_next[31:0] = int_mode_qs;
end
addr_hit[2]: begin
reg_rdata_next[15:0] = int_pending_qs;
end
addr_hit[3]: begin
reg_rdata_next[15:0] = data_qs;
end
addr_hit[4]: begin
reg_rdata_next[15:0] = filter_qs;
end
default: begin
reg_rdata_next = '1;
end
endcase
end
// Unused signal tieoff
// wdata / byte enable are not always fully used
// add a blanket unused statement to handle lint waivers
logic unused_wdata;
logic unused_be;
assign unused_wdata = ^reg_wdata;
assign unused_be = ^reg_be;
endmodule

View File

@ -0,0 +1,94 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module gpio_top #(
parameter int GPIO_NUM = 2
)(
input logic clk_i,
input logic rst_ni,
output logic [GPIO_NUM-1:0] gpio_oe_o,
output logic [GPIO_NUM-1:0] gpio_data_o,
input logic [GPIO_NUM-1:0] gpio_data_i,
output logic irq_gpio0_o,
output logic irq_gpio1_o,
output logic irq_gpio2_4_o,
output logic irq_gpio5_7_o,
output logic irq_gpio8_o,
output logic irq_gpio9_o,
output logic irq_gpio10_12_o,
output logic irq_gpio13_15_o,
// OBI总线接口信号
input logic req_i,
input logic we_i,
input logic [ 3:0] be_i,
input logic [31:0] addr_i,
input logic [31:0] data_i,
output logic gnt_o,
output logic rvalid_o,
output logic [31:0] data_o
);
logic re;
logic we;
logic [31:0] addr;
logic [31:0] reg_rdata;
assign gnt_o = req_i;
// 读信号
assign re = req_i & (!we_i);
// 写信号
assign we = req_i & we_i;
// 去掉基地址
assign addr = {16'h0, addr_i[15:0]};
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
rvalid_o <= '0;
data_o <= '0;
end else begin
rvalid_o <= req_i;
data_o <= reg_rdata;
end
end
gpio_core #(
.GPIO_NUM(GPIO_NUM)
) u_gpio_core (
.clk_i (clk_i),
.rst_ni (rst_ni),
.gpio_oe_o (gpio_oe_o),
.gpio_data_o(gpio_data_o),
.gpio_data_i(gpio_data_i),
.irq_gpio0_o(irq_gpio0_o),
.irq_gpio1_o(irq_gpio1_o),
.irq_gpio2_4_o(irq_gpio2_4_o),
.irq_gpio5_7_o(irq_gpio5_7_o),
.irq_gpio8_o(irq_gpio8_o),
.irq_gpio9_o(irq_gpio9_o),
.irq_gpio10_12_o(irq_gpio10_12_o),
.irq_gpio13_15_o(irq_gpio13_15_o),
.reg_we_i (we),
.reg_re_i (re),
.reg_wdata_i(data_i),
.reg_be_i (be_i),
.reg_addr_i (addr),
.reg_rdata_o(reg_rdata)
);
endmodule

138
rtl/perips/i2c/i2c.hjson Normal file
View File

@ -0,0 +1,138 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "i2c",
clocking: [{clock: "clk_i", reset: "rst_ni"}],
bus_interfaces: [
{ protocol: "tlul", direction: "device" }
],
regwidth: "32",
registers: [
{ name: "CTRL",
desc: "I2C control register",
swaccess: "rw",
hwaccess: "hrw",
hwqe: "true",
fields: [
{ bits: "0",
name: "START",
desc: "I2C start",
}
{ bits: "1",
name: "INT_EN",
desc: "I2C interrupt enable",
}
{ bits: "2",
name: "INT_PENDING",
swaccess: "rw1c",
desc: "I2C interrupt pending",
}
{ bits: "3",
name: "MODE",
desc: "I2C mode, 0: master, 1: slave",
}
{ bits: "4",
name: "WRITE",
desc: "0: write, 1: read",
}
{ bits: "5",
name: "ERROR",
swaccess: "ro",
desc: "0: no error, 1: error",
}
{ bits: "6",
name: "SLAVE_WR",
swaccess: "ro",
desc: "0: write, 1: read",
}
{ bits: "7",
name: "SLAVE_RDY",
desc: "0: not ready, 1: ready",
}
{ bits: "15:8",
name: "SLAVE_ADDR",
desc: "I2C slave address",
}
{ bits: "31:16",
name: "CLK_DIV",
desc: "I2C clock divider count",
}
]
}
{ name: "MASTER_DATA",
desc: "I2C master transfer data register",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "7:0",
name: "ADDRESS",
desc: "I2C slave address",
}
{ bits: "15:8",
name: "REGREG",
desc: "I2C write or read reg",
}
{ bits: "23:16",
name: "DATA",
desc: "I2C write or read data",
}
]
}
{ name: "SLAVE_ADDR",
desc: "I2C slave read or write address register",
swaccess: "ro",
hwaccess: "hrw",
fields: [
{ bits: "7:0",
name: "ADDR0",
desc: "I2C slave read or write address[7:0]",
}
{ bits: "15:8",
name: "ADDR1",
desc: "I2C slave read or write address[15:8]",
}
{ bits: "23:16",
name: "ADDR2",
desc: "I2C slave read or write address[23:16]",
}
{ bits: "31:24",
name: "ADDR3",
desc: "I2C slave read or write address[31:24]",
}
]
}
{ name: "SLAVE_WDATA",
desc: "I2C slave write data register",
swaccess: "ro",
hwaccess: "hrw",
fields: [
{ bits: "7:0",
name: "WDATA0",
desc: "I2C slave write data[7:0]",
}
{ bits: "15:8",
name: "WDATA1",
desc: "I2C slave write data[15:8]",
}
{ bits: "23:16",
name: "WDATA2",
desc: "I2C slave write data[23:16]",
}
{ bits: "31:24",
name: "WDATA3",
desc: "I2C slave write data[31:24]",
}
]
}
{ name: "SLAVE_RDATA",
desc: "I2C slave read data register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "I2C slave read data",
}
]
}
]
}

Some files were not shown because too many files have changed in this diff Show More