From 8214134b89255611c0cb07e11d90c420953f12e8 Mon Sep 17 00:00:00 2001 From: Blue Liang Date: Mon, 29 Mar 2021 15:14:50 +0800 Subject: [PATCH] tmp commit, unstable Signed-off-by: liangkangnan --- README.md | 2 +- rtl.flist | 44 ++ rtl/core/{clint.v => clint.sv} | 2 +- rtl/core/{csr_reg.v => csr_reg.sv} | 2 +- rtl/core/{defines.v => defines.sv} | 0 rtl/core/{divider.v => divider.sv} | 2 +- rtl/core/{exu.v => exu.sv} | 2 +- ...exu_alu_datapath.v => exu_alu_datapath.sv} | 2 +- rtl/core/{exu_commit.v => exu_commit.sv} | 2 +- rtl/core/{exu_dispatch.v => exu_dispatch.sv} | 2 +- rtl/core/{exu_mem.v => exu_mem.sv} | 2 +- rtl/core/{exu_muldiv.v => exu_muldiv.sv} | 2 +- rtl/core/{gpr_reg.v => gpr_reg.sv} | 2 +- rtl/core/{idu.v => idu.sv} | 2 +- rtl/core/{idu_exu.v => idu_exu.sv} | 2 +- rtl/core/{ifu.v => ifu.sv} | 2 +- rtl/core/{ifu_idu.v => ifu_idu.sv} | 2 +- rtl/core/{pipe_ctrl.v => pipe_ctrl.sv} | 2 +- rtl/core/{rst_ctrl.v => rst_ctrl.sv} | 2 +- .../{tinyriscv_core.v => tinyriscv_core.sv} | 2 +- rtl/debug/{jtag_dm.v => jtag_dm.sv} | 0 rtl/debug/{jtag_driver.v => jtag_driver.sv} | 0 rtl/debug/{jtag_top.v => jtag_top.sv} | 2 +- rtl/perips/{gpio.v => gpio.sv} | 0 rtl/perips/{ram.v => ram.sv} | 2 +- rtl/perips/{rom.v => rom.sv} | 2 +- rtl/perips/{timer.v => timer.sv} | 2 +- rtl/perips/{uart.v => uart.sv} | 2 +- rtl/sys_bus/{rib.v => rib.sv} | 0 ...nyriscv_soc_top.v => tinyriscv_soc_top.sv} | 2 +- ...ll_handshake_rx.v => full_handshake_rx.sv} | 0 ...ll_handshake_tx.v => full_handshake_tx.sv} | 0 rtl/utils/{gen_buf.v => gen_buf.sv} | 0 rtl/utils/{gen_dff.v => gen_dff.sv} | 0 rtl/utils/{gen_ram.v => gen_ram.sv} | 2 +- rtl/utils/{vld_rdy.v => vld_rdy.sv} | 0 sdk/bsp/common.mk | 10 +- sim/.gitignore | 14 +- sim/Makefile | 90 +++ sim/README.md | 47 -- sim/compile_rtl.py | 75 -- sim/compliance_test/.gitignore | 11 - sim/compliance_test/README.md | 11 - sim/compliance_test/compliance_test.py | 96 --- sim/remote_bitbang/.gitignore | 3 + sim/remote_bitbang/Makefile | 124 +++ sim/remote_bitbang/rbs_test.c | 34 + sim/remote_bitbang/remote_bitbang.c | 275 +++++++ sim/remote_bitbang/remote_bitbang.h | 52 ++ sim/remote_bitbang/sim_jtag.c | 29 + sim/sim_default_nowave.py | 28 - sim/sim_jtag.sv | 85 ++ sim/sim_new_nowave.py | 33 - sim/tb_top_verilator.cpp | 108 +++ sim/tb_top_verilator.sv | 48 ++ sim/test_all_isa.py | 43 - sim/test_jtag.py | 72 -- tb/README.md | 3 - tb/compliance_test/tinyriscv_soc_tb.v | 535 ------------- tb/jtag_tb.v | 733 ------------------ tb/tinyriscv_soc_tb.v | 521 ------------- tools/.gitignore | 3 - tools/{BinToMem_CLI.py => BinToMem.py} | 2 + tools/openocd/openocd | Bin 0 -> 15308320 bytes tools/openocd/openocd.exe | Bin 4783339 -> 0 bytes 65 files changed, 930 insertions(+), 2249 deletions(-) create mode 100644 rtl.flist rename rtl/core/{clint.v => clint.sv} (99%) rename rtl/core/{csr_reg.v => csr_reg.sv} (99%) rename rtl/core/{defines.v => defines.sv} (100%) rename rtl/core/{divider.v => divider.sv} (99%) rename rtl/core/{exu.v => exu.sv} (99%) rename rtl/core/{exu_alu_datapath.v => exu_alu_datapath.sv} (99%) rename rtl/core/{exu_commit.v => exu_commit.sv} (99%) rename rtl/core/{exu_dispatch.v => exu_dispatch.sv} (99%) rename rtl/core/{exu_mem.v => exu_mem.sv} (99%) rename rtl/core/{exu_muldiv.v => exu_muldiv.sv} (99%) rename rtl/core/{gpr_reg.v => gpr_reg.sv} (99%) rename rtl/core/{idu.v => idu.sv} (99%) rename rtl/core/{idu_exu.v => idu_exu.sv} (99%) rename rtl/core/{ifu.v => ifu.sv} (99%) rename rtl/core/{ifu_idu.v => ifu_idu.sv} (98%) rename rtl/core/{pipe_ctrl.v => pipe_ctrl.sv} (99%) rename rtl/core/{rst_ctrl.v => rst_ctrl.sv} (98%) rename rtl/core/{tinyriscv_core.v => tinyriscv_core.sv} (99%) rename rtl/debug/{jtag_dm.v => jtag_dm.sv} (100%) rename rtl/debug/{jtag_driver.v => jtag_driver.sv} (100%) rename rtl/debug/{jtag_top.v => jtag_top.sv} (99%) rename rtl/perips/{gpio.v => gpio.sv} (100%) rename rtl/perips/{ram.v => ram.sv} (98%) rename rtl/perips/{rom.v => rom.sv} (98%) rename rtl/perips/{timer.v => timer.sv} (99%) rename rtl/perips/{uart.v => uart.sv} (99%) rename rtl/sys_bus/{rib.v => rib.sv} (100%) rename rtl/top/{tinyriscv_soc_top.v => tinyriscv_soc_top.sv} (99%) rename rtl/utils/{full_handshake_rx.v => full_handshake_rx.sv} (100%) rename rtl/utils/{full_handshake_tx.v => full_handshake_tx.sv} (100%) rename rtl/utils/{gen_buf.v => gen_buf.sv} (100%) rename rtl/utils/{gen_dff.v => gen_dff.sv} (100%) rename rtl/utils/{gen_ram.v => gen_ram.sv} (98%) rename rtl/utils/{vld_rdy.v => vld_rdy.sv} (100%) create mode 100644 sim/Makefile delete mode 100644 sim/compile_rtl.py delete mode 100644 sim/compliance_test/.gitignore delete mode 100644 sim/compliance_test/README.md delete mode 100644 sim/compliance_test/compliance_test.py create mode 100644 sim/remote_bitbang/.gitignore create mode 100644 sim/remote_bitbang/Makefile create mode 100644 sim/remote_bitbang/rbs_test.c create mode 100644 sim/remote_bitbang/remote_bitbang.c create mode 100644 sim/remote_bitbang/remote_bitbang.h create mode 100644 sim/remote_bitbang/sim_jtag.c delete mode 100644 sim/sim_default_nowave.py create mode 100644 sim/sim_jtag.sv delete mode 100644 sim/sim_new_nowave.py create mode 100644 sim/tb_top_verilator.cpp create mode 100644 sim/tb_top_verilator.sv delete mode 100644 sim/test_all_isa.py delete mode 100644 sim/test_jtag.py delete mode 100644 tb/README.md delete mode 100644 tb/compliance_test/tinyriscv_soc_tb.v delete mode 100644 tb/jtag_tb.v delete mode 100644 tb/tinyriscv_soc_tb.v rename tools/{BinToMem_CLI.py => BinToMem.py} (97%) create mode 100644 tools/openocd/openocd delete mode 100644 tools/openocd/openocd.exe diff --git a/README.md b/README.md index 2604523..139597f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -本分支(bram)是在master分支的基础上,将指令和数据存储器由LUTRAM(DRAM)改为BRAM,以便可以运行更大的(C语言)程序。 + diff --git a/rtl.flist b/rtl.flist new file mode 100644 index 0000000..db251d4 --- /dev/null +++ b/rtl.flist @@ -0,0 +1,44 @@ + ++incdir+../rtl/core + +../rtl/core/clint.sv +../rtl/core/csr_reg.sv +../rtl/core/defines.sv +../rtl/core/divider.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_ctrl.sv +../rtl/core/tinyriscv_core.sv + +../rtl/debug/jtag_dm.sv +../rtl/debug/jtag_driver.sv +../rtl/debug/jtag_top.sv + +../rtl/perips/gpio.sv +../rtl/perips/ram.sv +../rtl/perips/rom.sv +../rtl/perips/timer.sv +../rtl/perips/uart.sv + +../rtl/sys_bus/rib.sv + +../rtl/top/tinyriscv_soc_top.sv + +../rtl/utils/full_handshake_rx.sv +../rtl/utils/full_handshake_tx.sv +../rtl/utils/gen_buf.sv +../rtl/utils/gen_dff.sv +../rtl/utils/gen_ram.sv +../rtl/utils/vld_rdy.sv + + diff --git a/rtl/core/clint.v b/rtl/core/clint.sv similarity index 99% rename from rtl/core/clint.v rename to rtl/core/clint.sv index 6537ae8..2421b1b 100644 --- a/rtl/core/clint.v +++ b/rtl/core/clint.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // core local interruptor module // жϹٲģ diff --git a/rtl/core/csr_reg.v b/rtl/core/csr_reg.sv similarity index 99% rename from rtl/core/csr_reg.v rename to rtl/core/csr_reg.sv index f473270..8a19f46 100644 --- a/rtl/core/csr_reg.v +++ b/rtl/core/csr_reg.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // CSR寄存器模块 module csr_reg( diff --git a/rtl/core/defines.v b/rtl/core/defines.sv similarity index 100% rename from rtl/core/defines.v rename to rtl/core/defines.sv diff --git a/rtl/core/divider.v b/rtl/core/divider.sv similarity index 99% rename from rtl/core/divider.v rename to rtl/core/divider.sv index 1c4196d..253d7b8 100644 --- a/rtl/core/divider.v +++ b/rtl/core/divider.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 除法模块 // 试商法实现32位整数除法 diff --git a/rtl/core/exu.v b/rtl/core/exu.sv similarity index 99% rename from rtl/core/exu.v rename to rtl/core/exu.sv index f65797a..65fca99 100644 --- a/rtl/core/exu.v +++ b/rtl/core/exu.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 执行模块 // 纯组合逻辑电路 diff --git a/rtl/core/exu_alu_datapath.v b/rtl/core/exu_alu_datapath.sv similarity index 99% rename from rtl/core/exu_alu_datapath.v rename to rtl/core/exu_alu_datapath.sv index 1e03e81..ee78d21 100644 --- a/rtl/core/exu_alu_datapath.v +++ b/rtl/core/exu_alu_datapath.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" `define DATAPATH_MUX_WIDTH (32+32+16) diff --git a/rtl/core/exu_commit.v b/rtl/core/exu_commit.sv similarity index 99% rename from rtl/core/exu_commit.v rename to rtl/core/exu_commit.sv index e69893d..98edbd0 100644 --- a/rtl/core/exu_commit.v +++ b/rtl/core/exu_commit.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" module exu_commit( diff --git a/rtl/core/exu_dispatch.v b/rtl/core/exu_dispatch.sv similarity index 99% rename from rtl/core/exu_dispatch.v rename to rtl/core/exu_dispatch.sv index 50892b1..cd39713 100644 --- a/rtl/core/exu_dispatch.v +++ b/rtl/core/exu_dispatch.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" module exu_dispatch( diff --git a/rtl/core/exu_mem.v b/rtl/core/exu_mem.sv similarity index 99% rename from rtl/core/exu_mem.v rename to rtl/core/exu_mem.sv index d46e30f..2a16784 100644 --- a/rtl/core/exu_mem.v +++ b/rtl/core/exu_mem.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" module exu_mem( diff --git a/rtl/core/exu_muldiv.v b/rtl/core/exu_muldiv.sv similarity index 99% rename from rtl/core/exu_muldiv.v rename to rtl/core/exu_muldiv.sv index 2433f4b..a3c0873 100644 --- a/rtl/core/exu_muldiv.v +++ b/rtl/core/exu_muldiv.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" module exu_muldiv( diff --git a/rtl/core/gpr_reg.v b/rtl/core/gpr_reg.sv similarity index 99% rename from rtl/core/gpr_reg.v rename to rtl/core/gpr_reg.sv index 8d0941f..885f518 100644 --- a/rtl/core/gpr_reg.v +++ b/rtl/core/gpr_reg.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 通用寄存器模块 module gpr_reg( diff --git a/rtl/core/idu.v b/rtl/core/idu.sv similarity index 99% rename from rtl/core/idu.v rename to rtl/core/idu.sv index 9cf9def..8ca9b17 100644 --- a/rtl/core/idu.v +++ b/rtl/core/idu.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 译码模块 // 纯组合逻辑电路 diff --git a/rtl/core/idu_exu.v b/rtl/core/idu_exu.sv similarity index 99% rename from rtl/core/idu_exu.v rename to rtl/core/idu_exu.sv index 79f38ae..ae1c1d1 100644 --- a/rtl/core/idu_exu.v +++ b/rtl/core/idu_exu.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 将译码结果向执行模块传递 module idu_exu( diff --git a/rtl/core/ifu.v b/rtl/core/ifu.sv similarity index 99% rename from rtl/core/ifu.v rename to rtl/core/ifu.sv index 8ab8193..b2ad29c 100644 --- a/rtl/core/ifu.v +++ b/rtl/core/ifu.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 取指模块 module ifu( diff --git a/rtl/core/ifu_idu.v b/rtl/core/ifu_idu.sv similarity index 98% rename from rtl/core/ifu_idu.v rename to rtl/core/ifu_idu.sv index 0a8bc12..9d3e996 100644 --- a/rtl/core/ifu_idu.v +++ b/rtl/core/ifu_idu.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 将指令向译码模块传递 module ifu_idu( diff --git a/rtl/core/pipe_ctrl.v b/rtl/core/pipe_ctrl.sv similarity index 99% rename from rtl/core/pipe_ctrl.v rename to rtl/core/pipe_ctrl.sv index 174f9ec..0be7f8e 100644 --- a/rtl/core/pipe_ctrl.v +++ b/rtl/core/pipe_ctrl.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 流水线控制模块 // 发出暂停、冲刷流水线信号 diff --git a/rtl/core/rst_ctrl.v b/rtl/core/rst_ctrl.sv similarity index 98% rename from rtl/core/rst_ctrl.v rename to rtl/core/rst_ctrl.sv index ced1b74..dc00ead 100644 --- a/rtl/core/rst_ctrl.v +++ b/rtl/core/rst_ctrl.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // 复位控制模块 module rst_ctrl( diff --git a/rtl/core/tinyriscv_core.v b/rtl/core/tinyriscv_core.sv similarity index 99% rename from rtl/core/tinyriscv_core.v rename to rtl/core/tinyriscv_core.sv index 98bbde3..d925b72 100644 --- a/rtl/core/tinyriscv_core.v +++ b/rtl/core/tinyriscv_core.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "defines.v" +`include "defines.sv" // tinyriscv处理器核顶层模块 module tinyriscv_core( diff --git a/rtl/debug/jtag_dm.v b/rtl/debug/jtag_dm.sv similarity index 100% rename from rtl/debug/jtag_dm.v rename to rtl/debug/jtag_dm.sv diff --git a/rtl/debug/jtag_driver.v b/rtl/debug/jtag_driver.sv similarity index 100% rename from rtl/debug/jtag_driver.v rename to rtl/debug/jtag_driver.sv diff --git a/rtl/debug/jtag_top.v b/rtl/debug/jtag_top.sv similarity index 99% rename from rtl/debug/jtag_top.v rename to rtl/debug/jtag_top.sv index e7e207e..089e058 100644 --- a/rtl/debug/jtag_top.v +++ b/rtl/debug/jtag_top.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "../core/defines.v" +`include "../core/defines.sv" // JTAG顶层模块 module jtag_top #( diff --git a/rtl/perips/gpio.v b/rtl/perips/gpio.sv similarity index 100% rename from rtl/perips/gpio.v rename to rtl/perips/gpio.sv diff --git a/rtl/perips/ram.v b/rtl/perips/ram.sv similarity index 98% rename from rtl/perips/ram.v rename to rtl/perips/ram.sv index a5d2cda..5b380b1 100644 --- a/rtl/perips/ram.v +++ b/rtl/perips/ram.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "../core/defines.v" +`include "../core/defines.sv" module ram #( diff --git a/rtl/perips/rom.v b/rtl/perips/rom.sv similarity index 98% rename from rtl/perips/rom.v rename to rtl/perips/rom.sv index 8c689d3..1220acd 100644 --- a/rtl/perips/rom.v +++ b/rtl/perips/rom.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "../core/defines.v" +`include "../core/defines.sv" module rom #( diff --git a/rtl/perips/timer.v b/rtl/perips/timer.sv similarity index 99% rename from rtl/perips/timer.v rename to rtl/perips/timer.sv index 6781779..dba580e 100644 --- a/rtl/perips/timer.v +++ b/rtl/perips/timer.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "../core/defines.v" +`include "../core/defines.sv" // 32位向上计数定时器模块 module timer( diff --git a/rtl/perips/uart.v b/rtl/perips/uart.sv similarity index 99% rename from rtl/perips/uart.v rename to rtl/perips/uart.sv index 892e094..bf109fa 100644 --- a/rtl/perips/uart.v +++ b/rtl/perips/uart.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "../core/defines.v" +`include "../core/defines.sv" // 串口收发模块(默认: 115200, 8,N,1) module uart( diff --git a/rtl/sys_bus/rib.v b/rtl/sys_bus/rib.sv similarity index 100% rename from rtl/sys_bus/rib.v rename to rtl/sys_bus/rib.sv diff --git a/rtl/top/tinyriscv_soc_top.v b/rtl/top/tinyriscv_soc_top.sv similarity index 99% rename from rtl/top/tinyriscv_soc_top.v rename to rtl/top/tinyriscv_soc_top.sv index 84ec790..8de9457 100644 --- a/rtl/top/tinyriscv_soc_top.v +++ b/rtl/top/tinyriscv_soc_top.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "../core/defines.v" +`include "../core/defines.sv" // tinyriscv soc顶层模块 module tinyriscv_soc_top( diff --git a/rtl/utils/full_handshake_rx.v b/rtl/utils/full_handshake_rx.sv similarity index 100% rename from rtl/utils/full_handshake_rx.v rename to rtl/utils/full_handshake_rx.sv diff --git a/rtl/utils/full_handshake_tx.v b/rtl/utils/full_handshake_tx.sv similarity index 100% rename from rtl/utils/full_handshake_tx.v rename to rtl/utils/full_handshake_tx.sv diff --git a/rtl/utils/gen_buf.v b/rtl/utils/gen_buf.sv similarity index 100% rename from rtl/utils/gen_buf.v rename to rtl/utils/gen_buf.sv diff --git a/rtl/utils/gen_dff.v b/rtl/utils/gen_dff.sv similarity index 100% rename from rtl/utils/gen_dff.v rename to rtl/utils/gen_dff.sv diff --git a/rtl/utils/gen_ram.v b/rtl/utils/gen_ram.sv similarity index 98% rename from rtl/utils/gen_ram.v rename to rtl/utils/gen_ram.sv index b0cff73..2879e39 100644 --- a/rtl/utils/gen_ram.v +++ b/rtl/utils/gen_ram.sv @@ -14,7 +14,7 @@ limitations under the License. */ -`include "../core/defines.v" +`include "../core/defines.sv" module gen_ram #( diff --git a/rtl/utils/vld_rdy.v b/rtl/utils/vld_rdy.sv similarity index 100% rename from rtl/utils/vld_rdy.v rename to rtl/utils/vld_rdy.sv diff --git a/sdk/bsp/common.mk b/sdk/bsp/common.mk index 51587dc..7b39a96 100644 --- a/sdk/bsp/common.mk +++ b/sdk/bsp/common.mk @@ -1,6 +1,5 @@ - -RISCV_TOOLS_PATH := $(TOOLCHAIN_DIR)/tools/gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64/bin -RISCV_TOOLS_PREFIX := riscv-none-embed- +RISCV_TOOLS_PATH := /opt/riscv/bin +RISCV_TOOLS_PREFIX := riscv32-unknown-elf- RISCV_GCC := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)gcc) RISCV_AS := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)as) @@ -11,6 +10,8 @@ RISCV_AR := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)ar) RISCV_OBJCOPY := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)objcopy) RISCV_READELF := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)readelf) +BIN_TO_MEM := $(COMMON_DIR)/../../tools/BinToMem.py + .PHONY: all all: $(TARGET) @@ -34,7 +35,7 @@ C_OBJS := $(C_SRCS:.c=.o) LINK_OBJS += $(ASM_OBJS) $(C_OBJS) LINK_DEPS += $(LINKER_SCRIPT) -CLEAN_OBJS += $(TARGET) $(LINK_OBJS) $(TARGET).dump $(TARGET).bin +CLEAN_OBJS += $(TARGET) $(LINK_OBJS) $(TARGET).dump $(TARGET).bin $(TARGET).hex $(TARGET).mem CFLAGS += -march=$(RISCV_ARCH) CFLAGS += -mabi=$(RISCV_ABI) @@ -44,6 +45,7 @@ $(TARGET): $(LINK_OBJS) $(LINK_DEPS) Makefile $(RISCV_GCC) $(CFLAGS) $(INCLUDES) $(LINK_OBJS) -o $@ $(LDFLAGS) $(RISCV_OBJCOPY) -O binary $@ $@.bin $(RISCV_OBJDUMP) --disassemble-all $@ > $@.dump + $(BIN_TO_MEM) $@.bin $@.mem $(ASM_OBJS): %.o: %.S $(RISCV_GCC) $(CFLAGS) $(INCLUDES) -c -o $@ $< diff --git a/sim/.gitignore b/sim/.gitignore index 671f832..d311c34 100644 --- a/sim/.gitignore +++ b/sim/.gitignore @@ -1,10 +1,6 @@ -# Object files -*.o -*.ko -*.obj +testbench_verilator +*.log +*.vcd *.bin -*.dump -inst.data -out.vvp -tinyriscv_soc_tb.vcd -jtag_tb.vcd \ No newline at end of file +cobj_dir/ + diff --git a/sim/Makefile b/sim/Makefile new file mode 100644 index 0000000..7548c8a --- /dev/null +++ b/sim/Makefile @@ -0,0 +1,90 @@ + +PROG := ../sdk/examples/simple/simple.mem +PROG_DIR := $(shell dirname $(PROG)) + +MAKE := make +VERILATOR := verilator + +VERI_FLAGS += +vcd +VERI_CFLAGS += + +VERI_VFLAGS += -DRVFI + +TRACE_ENABLE := 1 + +RTL_FILES = ../rtl.flist + +VERI_OBJ_DIR := cobj_dir + +ifeq ($(findstring +vcd,$(VERI_FLAGS)),+vcd) +VERI_TRACE = "--trace" +VERI_CFLAGS += "-DVCD_TRACE" +else +VERI_TRACE = +endif + +SIM_SRC := sim_jtag.sv + +SIM_SRC += tb_top_verilator.sv \ + tb_top_verilator.cpp + +SIM_TOP_MODULE := tb_top_verilator + +.DEFAULT_GOAL := sim +all: sim + +.PHONY: recompile +recompile: + rm -rf $(VERI_OBJ_DIR) testbench_verilator + $(MAKE) -C ./remote_bitbang clean + $(MAKE) -C $(PROG_DIR) clean + $(MAKE) compile + +.PHONY: compile +compile: remote_bitbang/librbs.so $(PROG) testbench_verilator + +testbench_verilator: + $(VERILATOR) --cc --sv --exe \ + $(VERI_TRACE) \ + --Wno-lint --Wno-UNOPTFLAT \ + --Wno-MODDUP --top-module \ + $(SIM_TOP_MODULE) \ + -f $(RTL_FILES) \ + $(SIM_SRC) \ + --Mdir $(VERI_OBJ_DIR) \ + $(VERI_VFLAGS) \ + -LDFLAGS "-L../remote_bitbang \ + -Wl,--enable-new-dtags -Wl,-rpath,remote_bitbang -lrbs" \ + -CFLAGS "-std=gnu++11 $(VERI_CFLAGS)" + $(MAKE) -C $(VERI_OBJ_DIR) -f V$(SIM_TOP_MODULE).mk + cp $(VERI_OBJ_DIR)/V$(SIM_TOP_MODULE) testbench_verilator + +remote_bitbang/librbs.so: + $(MAKE) -C ./remote_bitbang all + +$(PROG): + $(MAKE) -C $(PROG_DIR) + +.PHONY: run +run: + ./testbench_verilator "+firmware=$(PROG)" + +.PHONY: sim +sim: recompile run + +.PHONY: clean +clean: + rm -rf $(VERI_OBJ_DIR) testbench_verilator *.log *.vcd + $(MAKE) -C ./remote_bitbang clean + $(MAKE) -C $(PROG_DIR) clean + +.PHONY: help +help: + @echo 'rebuild all:' + @echo 'make PROG=/path/file.mem recompile' + @echo 'run directly:' + @echo 'make PROG=/path/file.mem run' + @echo 'rebuild & run:' + @echo 'make PROG=/path/file.mem sim' + @echo 'clean obj files:' + @echo 'make PROG=/path/file.mem clean' diff --git a/sim/README.md b/sim/README.md index edb8386..b28b04f 100644 --- a/sim/README.md +++ b/sim/README.md @@ -1,50 +1,3 @@ -# compile_rtl.py -编译rtl代码。 -使用方法: - -`python compile_rtl.py [rtl目录相对路径]` - -比如: - -`python compile_rtl.py ..` - -# sim_new_nowave.py - -对指定的bin文件(重新生成inst.data文件)进行测试。 - -使用方法: - -windows系统下: - -`python sim_new_nowave.py ..\tests\isa\generated\rv32ui-p-add.bin inst.data` - -Linux系统下: - -`python sim_new_nowave.py ../tests/isa/generated/rv32ui-p-add.bin inst.data` - -# sim_default_nowave.py - -对已经存在的inst.data文件进行测试。 - -使用方法: - -`python sim_default_nowave.py` - -# test_all_isa.py - -一次性测试../tests/isa/generated目录下的所有指令。 - -使用方法: - -`python test_all_isa.py` - -# test_jtag.py - -测试JTAG的内存读、写功能。 - -使用方法: - -`python test_jtag.py` diff --git a/sim/compile_rtl.py b/sim/compile_rtl.py deleted file mode 100644 index 2a3220f..0000000 --- a/sim/compile_rtl.py +++ /dev/null @@ -1,75 +0,0 @@ -import sys -import filecmp -import subprocess -import sys -import os - - -# 主函数 -def main(): - rtl_dir = sys.argv[1] - - if rtl_dir != r'..': - tb_file = r'/tb/compliance_test/tinyriscv_soc_tb.v' - else: - tb_file = r'/tb/tinyriscv_soc_tb.v' - - # iverilog程序 - iverilog_cmd = ['iverilog'] - # 顶层模块 - #iverilog_cmd += ['-s', r'tinyriscv_soc_tb'] - # 编译生成文件 - iverilog_cmd += ['-o', r'out.vvp'] - # 头文件(defines.v)路径 - iverilog_cmd += ['-I', rtl_dir + r'/rtl/core'] - # 宏定义,仿真输出文件 - iverilog_cmd += ['-D', r'OUTPUT="signature.output"'] - # testbench文件 - iverilog_cmd.append(rtl_dir + tb_file) - # ../rtl/core - iverilog_cmd.append(rtl_dir + r'/rtl/core/clint.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/csr_reg.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/defines.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/divider.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_alu_datapath.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_commit.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_dispatch.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_mem.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_muldiv.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/gpr_reg.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/idu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/idu_exu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/ifu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/ifu_idu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/pipe_ctrl.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/tinyriscv_core.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/rst_ctrl.v') - # ../rtl/perips - iverilog_cmd.append(rtl_dir + r'/rtl/perips/ram.v') - iverilog_cmd.append(rtl_dir + r'/rtl/perips/rom.v') - iverilog_cmd.append(rtl_dir + r'/rtl/perips/timer.v') - iverilog_cmd.append(rtl_dir + r'/rtl/perips/uart.v') - iverilog_cmd.append(rtl_dir + r'/rtl/perips/gpio.v') - # ../rtl/debug - iverilog_cmd.append(rtl_dir + r'/rtl/debug/jtag_dm.v') - iverilog_cmd.append(rtl_dir + r'/rtl/debug/jtag_driver.v') - iverilog_cmd.append(rtl_dir + r'/rtl/debug/jtag_top.v') - # ../rtl/sys_bus - iverilog_cmd.append(rtl_dir + r'/rtl/sys_bus/rib.v') - # ../rtl/utils - iverilog_cmd.append(rtl_dir + r'/rtl/utils/full_handshake_rx.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/full_handshake_tx.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/gen_buf.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/gen_dff.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/gen_ram.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/vld_rdy.v') - # ../rtl/top - iverilog_cmd.append(rtl_dir + r'/rtl/top/tinyriscv_soc_top.v') - - # 编译 - process = subprocess.Popen(iverilog_cmd) - process.wait(timeout=5) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/sim/compliance_test/.gitignore b/sim/compliance_test/.gitignore deleted file mode 100644 index 6eb8a5d..0000000 --- a/sim/compliance_test/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Object files -*.o -*.ko -*.obj -*.bin -*.dump -inst.data -out.vvp -tinyriscv_soc_tb.vcd -run.log -signature.output diff --git a/sim/compliance_test/README.md b/sim/compliance_test/README.md deleted file mode 100644 index 2ff6b19..0000000 --- a/sim/compliance_test/README.md +++ /dev/null @@ -1,11 +0,0 @@ -对新的指令测试项进行测试。 - -使用方法: - -Windows系统下: - -`python compliance_test.py ..\..\tests\riscv-compliance\build_generated\rv32i\I-ADD-01.elf.bin inst.data` - -Linux系统下: - -`python compliance_test.py ../../tests/riscv-compliance/build_generated/rv32i/I-ADD-01.elf.bin inst.data` \ No newline at end of file diff --git a/sim/compliance_test/compliance_test.py b/sim/compliance_test/compliance_test.py deleted file mode 100644 index 01c679e..0000000 --- a/sim/compliance_test/compliance_test.py +++ /dev/null @@ -1,96 +0,0 @@ -import sys -import filecmp -import subprocess -import sys -import os - - -# 找出path目录下的所有reference_output文件 -def list_ref_files(path): - files = [] - list_dir = os.walk(path) - for maindir, subdir, all_file in list_dir: - for filename in all_file: - apath = os.path.join(maindir, filename) - if apath.endswith('.reference_output'): - files.append(apath) - - return files - -# 根据bin文件找到对应的reference_output文件 -def get_reference_file(bin_file): - file_path, file_name = os.path.split(bin_file) - tmp = file_name.split('.') - # 得到bin文件的前缀部分 - prefix = tmp[0] - #print('bin prefix: %s' % prefix) - - files = [] - if (bin_file.find('rv32im') != -1): - files = list_ref_files(r'../../tests/riscv-compliance/riscv-test-suite/rv32im/references') - elif (bin_file.find('rv32i') != -1): - files = list_ref_files(r'../../tests/riscv-compliance/riscv-test-suite/rv32i/references') - elif (bin_file.find('rv32Zicsr') != -1): - files = list_ref_files(r'../../tests/riscv-compliance/riscv-test-suite/rv32Zicsr/references') - elif (bin_file.find('rv32Zifencei') != -1): - files = list_ref_files(r'../../tests/riscv-compliance/riscv-test-suite/rv32Zifencei/references') - else: - return None - - # 根据bin文件前缀找到对应的reference_output文件 - for file in files: - if (file.find(prefix) != -1): - return file - - return None - -# 主函数 -def main(): - #print(sys.argv[0] + ' ' + sys.argv[1] + ' ' + sys.argv[2]) - - # 1.将bin文件转成mem文件 - cmd = r'python ../../tools/BinToMem_CLI.py' + ' ' + sys.argv[1] + ' ' + sys.argv[2] - f = os.popen(cmd) - f.close() - - # 2.编译rtl文件 - cmd = r'python ../compile_rtl.py' + r' ../..' - f = os.popen(cmd) - f.close() - - # 3.运行 - logfile = open('run.log', 'w') - vvp_cmd = [r'vvp'] - vvp_cmd.append(r'out.vvp') - process = subprocess.Popen(vvp_cmd, stdout=logfile, stderr=logfile) - process.wait(timeout=5) - logfile.close() - - # 4.比较结果 - ref_file = get_reference_file(sys.argv[1]) - if (ref_file != None): - # 如果文件大小不一致,直接报fail - if (os.path.getsize('signature.output') != os.path.getsize(ref_file)): - print('!!! FAIL, size != !!!') - return - f1 = open('signature.output') - f2 = open(ref_file) - f1_lines = f1.readlines() - i = 0 - # 逐行比较 - for line in f2.readlines(): - # 只要有一行内容不一样就报fail - if (f1_lines[i] != line): - print('!!! FAIL, content != !!!') - f1.close() - f2.close() - return - i = i + 1 - f1.close() - f2.close() - print('### PASS ###') - else: - print('No ref file found, please check result by yourself.') - -if __name__ == '__main__': - sys.exit(main()) diff --git a/sim/remote_bitbang/.gitignore b/sim/remote_bitbang/.gitignore new file mode 100644 index 0000000..0015e3f --- /dev/null +++ b/sim/remote_bitbang/.gitignore @@ -0,0 +1,3 @@ +*.o +*.d +*.so \ No newline at end of file diff --git a/sim/remote_bitbang/Makefile b/sim/remote_bitbang/Makefile new file mode 100644 index 0000000..8deb36a --- /dev/null +++ b/sim/remote_bitbang/Makefile @@ -0,0 +1,124 @@ +# Copyright (C) 2020 ETH Zurich and University of Bologna +# +# 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. +# +# +# Author: Robert Balas (balasr@iis.ee.ethz.ch) + +CFLAGS = -Wall -Wextra -Wno-missing-field-initializers \ + -Wno-unused-function -Wno-missing-braces \ + -O2 -g -march=native \ + -DENABLE_LOGGING -DNDEBUG +CFLAGS_DBG = +# we need gnu11 and no-strict-aliasing +ALL_CFLAGS = -std=gnu11 -fno-strict-aliasing $(CFLAGS) +ALL_CFLAGS_DBG = -std=gnu11 -Wall -Wextra -Wno-missing-field-initializers \ + -Wno-unused-function -Wno-missing-braces \ + -O0 -g -fno-strict-aliasing \ + -fsanitize=address -fno-omit-frame-pointer \ + -DENABLE_LOGGING -DENABLE_DEBUG $(CFLAGS_DBG)\ +# -fsanitize=undefined \ +# -fsanitize=leak \ + + +# TODO: better path? +LIB_DIRS = +LIBS = +INCLUDE_DIRS = ./ + + +LDFLAGS = $(addprefix -L, $(LIB_DIRS)) +LDLIBS = $(addprefix -l, $(LIBS)) + +SRCS = remote_bitbang.c sim_jtag.c +OBJS = $(SRCS:.c=.o) +INCLUDES = $(addprefix -I, $(INCLUDE_DIRS)) + +HEADERS = $(wildcard *.h) + +# libs +SV_LIB = librbs.so + +# header file dependency generation +DEPDIR := .d +DEPDIRS := $(addsuffix /$(DEPDIR),.) +# goal: make gcc put a dependency file called obj.Td (derived from subdir/obj.o) +# in subdir/.d/ +DEPFLAGS = -MT $@ -MMD -MP -MF $(@D)/$(DEPDIR)/$(patsubst %.o,%.Td,$(@F)) +# move gcc generated header dependencies to DEPDIR +# this rename step is here to make the header dependency generation "atomic" +POSTCOMPILE = @mv -f $(@D)/$(DEPDIR)/$(patsubst %.o,%.Td,$(@F)) \ + $(@D)/$(DEPDIR)/$(patsubst %.o,%.d,$(@F)) && touch $@ + +# GNU recommendations for install targets +prefix = /usr/local +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +includedir = $(prefix)/include + +INSTALL = install +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = ${INSTALL} -m 644 + +CTAGS = ctags + +# compilation targets +all: sv-lib + +debug: ALL_CFLAGS = $(ALL_CFLAGS_DBG) +debug: all + +sv-lib: ALL_CFLAGS += -fPIC +sv-lib: $(SV_LIB) + +#compilation boilerplate +$(SV_LIB): $(OBJS) + $(LD) -shared -E --exclude-libs ALL -o $(SV_LIB) $(LDFLAGS) \ + $(OBJS) $(LDLIBS) + +# $@ = name of target +# $< = first dependency +%.o: %.c +%.o: %.c $(DEPDIR)/%.d $(DEPDIRS) + $(CC) $(DEPFLAGS) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) \ + -c $(CPPFLAGS) $< -o $@ $(LDLIBS) + $(POSTCOMPILE) + +# check if we need to create the dependencies folders (gcc doesn't) +$(DEPDIRS): + $(shell mkdir -p $(DEPDIRS) > /dev/null) +# make won't fail if the dependency file doesn't exist +$(addsuffix /$(DEPDIR)/%.d,. main benchmark test dpi): ; + +# prevent automatic deletion as intermediate file +.PRECIOUS: $(addsuffix /$(DEPDIR)/%.d,. main benchmark test dpi) + +# emacs tag generation +.PHONY: TAGS +TAGS: + $(CTAGS) -R -e -h=".c.h" --tag-relative=always \ + . $(LIB_DIRS) $(INCLUDE_DIRS) $(BINUTILS_PATH)/bfd + +# TODO: missing install targets +# cleanup +.PHONY: clean +clean: + rm -rf $(SV_LIB) $(OBJS) $(DEPDIRS) + +.PHONY: distclean +distclean: clean + rm -f TAGS + +# include auto generated header dependency information +include $(wildcard $(addsuffix /*.d,$(DEPDIRS))) diff --git a/sim/remote_bitbang/rbs_test.c b/sim/remote_bitbang/rbs_test.c new file mode 100644 index 0000000..328574e --- /dev/null +++ b/sim/remote_bitbang/rbs_test.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2020 ETH Zurich and University of Bologna + * + * 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. + * + * + * Author: Robert Balas (balasr@iis.ee.ethz.ch) + */ + +#include +#include "remote_bitbang.h" + +int main() +{ + unsigned char jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn; + unsigned char jtag_TDO = 0; + + printf("calling rbs_init\n"); + int v = rbs_init(0); + + printf("tick 1\n"); + rbs_tick(&jtag_TCK, &jtag_TMS, &jtag_TDI, &jtag_TRSTn, jtag_TDO); + printf("jtag exit is %d\n", rbs_done()); + return 0; +} diff --git a/sim/remote_bitbang/remote_bitbang.c b/sim/remote_bitbang/remote_bitbang.c new file mode 100644 index 0000000..e77c00d --- /dev/null +++ b/sim/remote_bitbang/remote_bitbang.c @@ -0,0 +1,275 @@ +// See LICENSE.Berkeley for license details. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "remote_bitbang.h" + +int rbs_init(uint16_t port) +{ + socket_fd = 0; + client_fd = 0; + recv_start = 0; + recv_end = 0; + rbs_err = 0; + + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == -1) { + fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + fcntl(socket_fd, F_SETFL, O_NONBLOCK); + int reuseaddr = 1; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, + sizeof(int)) == -1) { + fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + + if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + if (listen(socket_fd, 1) == -1) { + fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + socklen_t addrlen = sizeof(addr); + if (getsockname(socket_fd, (struct sockaddr *)&addr, &addrlen) == -1) { + fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + tck = 1; + tms = 1; + tdi = 1; + trstn = 1; + quit = 0; + + fprintf(stderr, "JTAG remote bitbang server is ready\n"); + fprintf(stderr, "Listening on port %d\n", ntohs(addr.sin_port)); + return 1; +} + +void rbs_accept() +{ + fprintf(stderr, "Attempting to accept client socket\n"); + int again = 1; + while (again != 0) { + client_fd = accept(socket_fd, NULL, NULL); + if (client_fd == -1) { + if (errno == EAGAIN) { + // No client waiting to connect right now. + } else { + fprintf(stderr, "failed to accept on socket: %s (%d)\n", + strerror(errno), errno); + again = 0; + abort(); + } + } else { + fcntl(client_fd, F_SETFL, O_NONBLOCK); + fprintf(stderr, "Accepted successfully."); + again = 0; + } + } +} + +void rbs_tick(unsigned char *jtag_tck, unsigned char *jtag_tms, + unsigned char *jtag_tdi, unsigned char *jtag_trstn, + unsigned char jtag_tdo) +{ + if (client_fd > 0) { + tdo = jtag_tdo; + rbs_execute_command(); + } else { + rbs_accept(); + } + + *jtag_tck = tck; + *jtag_tms = tms; + *jtag_tdi = tdi; + *jtag_trstn = trstn; +} + +void rbs_reset() +{ + // trstn = 0; +} + +void rbs_set_pins(char _tck, char _tms, char _tdi) +{ + tck = _tck; + tms = _tms; + tdi = _tdi; +} + +void rbs_execute_command() +{ + char command; + int again = 1; + while (again) { + ssize_t num_read = read(client_fd, &command, sizeof(command)); + if (num_read == -1) { + if (errno == EAGAIN) { + // We'll try again the next call. + if (VERBOSE) + fprintf( + stderr, + "Received no command. Will try again on the next call\n"); + } else { + fprintf(stderr, + "remote_bitbang failed to read on socket: %s (%d)\n", + strerror(errno), errno); + again = 0; + abort(); + } + } else if (num_read == 0) { + fprintf(stderr, "No command received. Stopping further reads.\n"); + // again = 1; + return; + } else { + again = 0; + } + } + + int dosend = 0; + + char tosend = '?'; + + switch (command) { + case 'B': + if (VERBOSE) + fprintf(stderr, "*BLINK*\n"); + break; + case 'b': + if (VERBOSE) + fprintf(stderr, "blink off\n"); + break; + case 'r': + if (VERBOSE) + fprintf(stderr, "r-reset\n"); + rbs_reset(); + break; // This is wrong. 'r' has other bits that indicated TRST and + // SRST. + case 's': + if (VERBOSE) + fprintf(stderr, "s-reset\n"); + rbs_reset(); + break; // This is wrong. + case 't': + if (VERBOSE) + fprintf(stderr, "t-reset\n"); + rbs_reset(); + break; // This is wrong. + case 'u': + if (VERBOSE) + fprintf(stderr, "u-reset\n"); + rbs_reset(); + break; // This is wrong. + case '0': + if (VERBOSE) + fprintf(stderr, "Write 0 0 0\n"); + rbs_set_pins(0, 0, 0); + break; + case '1': + if (VERBOSE) + fprintf(stderr, "Write 0 0 1\n"); + rbs_set_pins(0, 0, 1); + break; + case '2': + if (VERBOSE) + fprintf(stderr, "Write 0 1 0\n"); + rbs_set_pins(0, 1, 0); + break; + case '3': + if (VERBOSE) + fprintf(stderr, "Write 0 1 1\n"); + rbs_set_pins(0, 1, 1); + break; + case '4': + if (VERBOSE) + fprintf(stderr, "Write 1 0 0\n"); + rbs_set_pins(1, 0, 0); + break; + case '5': + if (VERBOSE) + fprintf(stderr, "Write 1 0 1\n"); + rbs_set_pins(1, 0, 1); + break; + case '6': + if (VERBOSE) + fprintf(stderr, "Write 1 1 0\n"); + rbs_set_pins(1, 1, 0); + break; + case '7': + if (VERBOSE) + fprintf(stderr, "Write 1 1 1\n"); + rbs_set_pins(1, 1, 1); + break; + case 'R': + if (VERBOSE) + fprintf(stderr, "Read req\n"); + dosend = 1; + tosend = tdo ? '1' : '0'; + break; + case 'Q': + if (VERBOSE) + fprintf(stderr, "Quit req\n"); + quit = 1; + break; + default: + fprintf(stderr, "remote_bitbang got unsupported command '%c'\n", + command); + } + if (dosend) { + while (1) { + ssize_t bytes = write(client_fd, &tosend, sizeof(tosend)); + if (bytes == -1) { + fprintf(stderr, "failed to write to socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + if (bytes > 0) { + break; + } + } + } + + if (quit) { + fprintf(stderr, "Remote end disconnected\n"); + close(client_fd); + client_fd = 0; + } +} + +unsigned char rbs_done() +{ + return quit; +} + +int rbs_exit_code() +{ + return rbs_err; +} diff --git a/sim/remote_bitbang/remote_bitbang.h b/sim/remote_bitbang/remote_bitbang.h new file mode 100644 index 0000000..460819e --- /dev/null +++ b/sim/remote_bitbang/remote_bitbang.h @@ -0,0 +1,52 @@ +// See LICENSE.Berkeley for license details. + +#ifndef REMOTE_BITBANG_H +#define REMOTE_BITBANG_H + +#include +#include + +#define VERBOSE 0 + +int rbs_err; + +unsigned char tck; +unsigned char tms; +unsigned char tdi; +unsigned char trstn; +unsigned char tdo; +unsigned char quit; + +int socket_fd; +int client_fd; + +static const ssize_t buf_size = 64 * 1024; +char recv_buf[64 * 1024]; +ssize_t recv_start, recv_end; + +// Create a new server, listening for connections from localhost on the given +// port. +int rbs_init(uint16_t port); + +// Do a bit of work. +void rbs_tick(unsigned char *jtag_tck, unsigned char *jtag_tms, + unsigned char *jtag_tdi, unsigned char *jtag_trstn, + unsigned char jtag_tdo); + +unsigned char rbs_done(); + +int rbs_exit_code(); + +// Check for a client connecting, and accept if there is one. +void rbs_accept(); +// Execute any commands the client has for us. +// But we only execute 1 because we need time for the +// simulation to run. +void rbs_execute_command(); + +// Reset. Currently does nothing. +void rbs_reset(); + +void rbs_set_pins(char _tck, char _tms, char _tdi); + +#endif diff --git a/sim/remote_bitbang/sim_jtag.c b/sim/remote_bitbang/sim_jtag.c new file mode 100644 index 0000000..769ba88 --- /dev/null +++ b/sim/remote_bitbang/sim_jtag.c @@ -0,0 +1,29 @@ +// See LICENSE.SiFive for license details. + +#include +#include +#include +#include "remote_bitbang.h" + +int init = 0; + +int jtag_tick(int port, unsigned char *jtag_TCK, unsigned char *jtag_TMS, + unsigned char *jtag_TDI, unsigned char *jtag_TRSTn, + unsigned char jtag_TDO) + +{ + if (!init) { + if (port < 0 || port > UINT16_MAX) + fprintf(stderr, "Port number of out range: %d\n", port); + init = rbs_init(port); + } + + rbs_tick(jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn, jtag_TDO); + if (VERBOSE) + fprintf( + stderr, + "Tick with: TCK=%hhd TMS=%hhd TDI=%hhd TRSTn=%hhd --> TDO=%hhd\n", + *jtag_TCK, *jtag_TMS, *jtag_TDI, *jtag_TRSTn, jtag_TDO); + + return rbs_done() ? (rbs_exit_code() << 1 | 1) : 0; +} diff --git a/sim/sim_default_nowave.py b/sim/sim_default_nowave.py deleted file mode 100644 index b0bc422..0000000 --- a/sim/sim_default_nowave.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys -import filecmp -import subprocess -import sys -import os - - -# 主函数 -def main(): - #print(sys.argv[0] + ' ' + sys.argv[1] + ' ' + sys.argv[2]) - - # 1.编译rtl文件 - cmd = r'python compile_rtl.py' + r' ..' - f = os.popen(cmd) - f.close() - - # 2.运行 - vvp_cmd = [r'vvp'] - vvp_cmd.append(r'out.vvp') - process = subprocess.Popen(vvp_cmd) - try: - process.wait(timeout=10) - except subprocess.TimeoutExpired: - print('!!!Fail, vvp exec timeout!!!') - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/sim/sim_jtag.sv b/sim/sim_jtag.sv new file mode 100644 index 0000000..83d823d --- /dev/null +++ b/sim/sim_jtag.sv @@ -0,0 +1,85 @@ +// See LICENSE.SiFive for license details. +//VCS coverage exclude_file +import "DPI-C" function int jtag_tick +( + input int port, + output bit jtag_TCK, + output bit jtag_TMS, + output bit jtag_TDI, + output bit jtag_TRSTn, + + input bit jtag_TDO +); + +module sim_jtag #( + parameter TICK_DELAY = 50, + parameter PORT = 0 + )( + + input clock, + input reset, + + input enable, + input init_done, + + output jtag_TCK, + output jtag_TMS, + output jtag_TDI, + output jtag_TRSTn, + + input jtag_TDO_data, + input jtag_TDO_driven, + + output [31:0] exit + ); + + reg [31:0] tickCounterReg; + wire [31:0] tickCounterNxt; + + assign tickCounterNxt = (tickCounterReg == 0) ? TICK_DELAY : (tickCounterReg - 1); + + bit r_reset; + + wire [31:0] random_bits = $random; + + wire #0.1 __jtag_TDO = jtag_TDO_driven ? + jtag_TDO_data : random_bits[0]; + + bit __jtag_TCK; + bit __jtag_TMS; + bit __jtag_TDI; + bit __jtag_TRSTn; + int __exit; + + reg init_done_sticky; + + assign #0.1 jtag_TCK = __jtag_TCK; + assign #0.1 jtag_TMS = __jtag_TMS; + assign #0.1 jtag_TDI = __jtag_TDI; + assign #0.1 jtag_TRSTn = __jtag_TRSTn; + + assign #0.1 exit = __exit; + + always @(posedge clock) begin + r_reset <= reset; + if (reset || r_reset) begin + __exit = 0; + tickCounterReg <= TICK_DELAY; + init_done_sticky <= 1'b0; + end else begin + init_done_sticky <= init_done | init_done_sticky; + if (enable && init_done_sticky) begin + tickCounterReg <= tickCounterNxt; + if (tickCounterReg == 0) begin + __exit = jtag_tick(PORT, + __jtag_TCK, + __jtag_TMS, + __jtag_TDI, + __jtag_TRSTn, + __jtag_TDO); + end + end // if (enable && init_done_sticky) + end // else: !if(reset || r_reset) + end // always @ (posedge clock) + +endmodule diff --git a/sim/sim_new_nowave.py b/sim/sim_new_nowave.py deleted file mode 100644 index 83885cd..0000000 --- a/sim/sim_new_nowave.py +++ /dev/null @@ -1,33 +0,0 @@ -import sys -import filecmp -import subprocess -import sys -import os - - -# 主函数 -def main(): - #print(sys.argv[0] + ' ' + sys.argv[1] + ' ' + sys.argv[2]) - - # 1.将bin文件转成mem文件 - cmd = r'python ../tools/BinToMem_CLI.py' + ' ' + sys.argv[1] + ' ' + sys.argv[2] - f = os.popen(cmd) - f.close() - - # 2.编译rtl文件 - cmd = r'python compile_rtl.py' + r' ..' - f = os.popen(cmd) - f.close() - - # 3.运行 - vvp_cmd = [r'vvp'] - vvp_cmd.append(r'out.vvp') - process = subprocess.Popen(vvp_cmd) - try: - process.wait(timeout=20) - except subprocess.TimeoutExpired: - print('!!!Fail, vvp exec timeout!!!') - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/sim/tb_top_verilator.cpp b/sim/tb_top_verilator.cpp new file mode 100644 index 0000000..53234cf --- /dev/null +++ b/sim/tb_top_verilator.cpp @@ -0,0 +1,108 @@ +// Copyright 2018 Robert Balas +// +// 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. + + +// Top level wrapper for a verilator RI5CY testbench +// Contributor: Robert Balas + +#include "svdpi.h" +#include "Vtb_top_verilator__Dpi.h" +#include "Vtb_top_verilator.h" +#include "verilated_vcd_c.h" +#include "verilated.h" + +#include +#include +#include +#include +#include +#include +#include + +//void dump_memory(); +double sc_time_stamp(); + +static vluint64_t t = 0; +Vtb_top_verilator *top; + +int main(int argc, char **argv, char **env) +{ + Verilated::commandArgs(argc, argv); + Verilated::traceEverOn(true); + top = new Vtb_top_verilator(); + + //svSetScope(svGetScopeFromName( + // "TOP.tb_top_verilator.u_ram.ram")); + //Verilated::scopesDump(); + +#ifdef VCD_TRACE + VerilatedVcdC *tfp = new VerilatedVcdC; + top->trace(tfp, 99); + tfp->open("verilator_tb.vcd"); +#endif + top->fetch_enable_i = 1; + top->clk_i = 0; + top->rst_ni = 0; + + top->eval(); + //dump_memory(); + + while (!Verilated::gotFinish()) { + if (t > 40) + top->rst_ni = 1; + top->clk_i = !top->clk_i; + top->eval(); +#ifdef VCD_TRACE + tfp->dump(t); +#endif + t += 5; + if (t > 1000) + break; + } +#ifdef VCD_TRACE + tfp->close(); +#endif + delete top; + exit(0); +} + +double sc_time_stamp() +{ + return t; +} +/* +void dump_memory() +{ + errno = 0; + std::ofstream mem_file; + svLogicVecVal addr = {0}; + + mem_file.exceptions(std::ofstream::failbit | std::ofstream::badbit); + try { + mem_file.open("memory_dump.bin"); + for (size_t i = 0; i < 1048576; i++) { + addr.aval = i; + uint32_t val = read_byte(&addr); + mem_file << std::setfill('0') << std::setw(2) << std::hex << val + << std::endl; + } + mem_file.close(); + + std::cout << "finished dumping memory" << std::endl; + + } catch (std::ofstream::failure e) { + std::cerr << "exception opening/reading/closing file memory_dump.bin\n"; + } +} +*/ diff --git a/sim/tb_top_verilator.sv b/sim/tb_top_verilator.sv new file mode 100644 index 0000000..19f2200 --- /dev/null +++ b/sim/tb_top_verilator.sv @@ -0,0 +1,48 @@ +// Copyright 2018 Robert Balas +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. + +// Top level wrapper for a verilator RI5CY testbench +// Contributor: Robert Balas + + +module tb_top_verilator #( + + ) ( + input clk_i, + input rst_ni, + input fetch_enable_i + ); + + + + + + initial begin: load_prog + automatic logic [1023:0] firmware; + + if($value$plusargs("firmware=%s", firmware)) begin + //if($test$plusargs("verbose")) + $display("[TESTBENCH] %t: loading firmware %0s ...", + $time, firmware); + $readmemh (firmware, u_tinyriscv_soc_top.u_rom.u_gen_ram.ram); + //$display("mem[0x80]=0x%x", u_ram.ram.mem[32]); + //$display("mem[0x84]=0x%x", u_ram.ram.mem[33]); + end else begin + $display("No firmware specified"); + end + end + + + tinyriscv_soc_top u_tinyriscv_soc_top( + .clk(clk_i), + .rst_ext_i(rst_ni) + ); + +endmodule // tb_top_verilator diff --git a/sim/test_all_isa.py b/sim/test_all_isa.py deleted file mode 100644 index 2f811f6..0000000 --- a/sim/test_all_isa.py +++ /dev/null @@ -1,43 +0,0 @@ -import os -import subprocess -import sys - - -# 找出path目录下的所有bin文件 -def list_binfiles(path): - files = [] - list_dir = os.walk(path) - for maindir, subdir, all_file in list_dir: - for filename in all_file: - apath = os.path.join(maindir, filename) - if apath.endswith('.bin'): - files.append(apath) - - return files - -# 主函数 -def main(): - bin_files = list_binfiles(r'../tests/isa/generated') - - anyfail = False - - # 对每一个bin文件进行测试 - for file in bin_files: - #print(file) - cmd = r'python sim_new_nowave.py' + ' ' + file + ' ' + 'inst.data' - f = os.popen(cmd) - r = f.read() - f.close() - if (r.find('TEST_PASS') != -1): - print(file + ' PASS') - else: - print(file + ' !!!FAIL!!!') - anyfail = True - break - - if (anyfail == False): - print('Congratulation, All PASS...') - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/sim/test_jtag.py b/sim/test_jtag.py deleted file mode 100644 index e1c43db..0000000 --- a/sim/test_jtag.py +++ /dev/null @@ -1,72 +0,0 @@ -import sys -import filecmp -import subprocess -import sys -import os - - -# 主函数 -def main(): - rtl_dir = '..' - - tb_file = r'/tb/jtag_tb.v' - - # iverilog程序 - iverilog_cmd = ['iverilog'] - # 顶层模块 - #iverilog_cmd += ['-s', r'tinyriscv_soc_tb'] - # 编译生成文件 - iverilog_cmd += ['-o', r'out.vvp'] - # 头文件(defines.v)路径 - iverilog_cmd += ['-I', rtl_dir + r'/rtl/core'] - # 宏定义,仿真输出文件 - iverilog_cmd += ['-D', r'OUTPUT="signature.output"'] - # testbench文件 - iverilog_cmd.append(rtl_dir + tb_file) - # ../rtl/core - iverilog_cmd.append(rtl_dir + r'/rtl/core/clint.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/csr_reg.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/defines.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/divider.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_alu_datapath.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_commit.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_dispatch.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_mem.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/exu_muldiv.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/gpr_reg.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/idu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/idu_exu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/ifu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/ifu_idu.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/pipe_ctrl.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/tinyriscv_core.v') - iverilog_cmd.append(rtl_dir + r'/rtl/core/rst_ctrl.v') - # ../rtl/perips - iverilog_cmd.append(rtl_dir + r'/rtl/perips/ram.v') - iverilog_cmd.append(rtl_dir + r'/rtl/perips/rom.v') - iverilog_cmd.append(rtl_dir + r'/rtl/perips/timer.v') - iverilog_cmd.append(rtl_dir + r'/rtl/perips/uart.v') - iverilog_cmd.append(rtl_dir + r'/rtl/perips/gpio.v') - # ../rtl/debug - iverilog_cmd.append(rtl_dir + r'/rtl/debug/jtag_dm.v') - iverilog_cmd.append(rtl_dir + r'/rtl/debug/jtag_driver.v') - iverilog_cmd.append(rtl_dir + r'/rtl/debug/jtag_top.v') - # ../rtl/sys_bus - iverilog_cmd.append(rtl_dir + r'/rtl/sys_bus/rib.v') - # ../rtl/utils - iverilog_cmd.append(rtl_dir + r'/rtl/utils/full_handshake_rx.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/full_handshake_tx.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/gen_buf.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/gen_dff.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/gen_ram.v') - iverilog_cmd.append(rtl_dir + r'/rtl/utils/vld_rdy.v') - # ../rtl/top - iverilog_cmd.append(rtl_dir + r'/rtl/top/tinyriscv_soc_top.v') - - # 编译 - process = subprocess.Popen(iverilog_cmd) - process.wait(timeout=5) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tb/README.md b/tb/README.md deleted file mode 100644 index 783f464..0000000 --- a/tb/README.md +++ /dev/null @@ -1,3 +0,0 @@ -tinyriscv_soc_tb.v是适用于旧的指令测试testbench文件。 - -compliance_test/tinyriscv_soc_tb.v是适用于新的指令测试testbench文件。 \ No newline at end of file diff --git a/tb/compliance_test/tinyriscv_soc_tb.v b/tb/compliance_test/tinyriscv_soc_tb.v deleted file mode 100644 index 92854ca..0000000 --- a/tb/compliance_test/tinyriscv_soc_tb.v +++ /dev/null @@ -1,535 +0,0 @@ -`timescale 1 ns / 1 ps - -`include "defines.v" - -// select one option only -`define TEST_PROG 1 -//`define TEST_JTAG 1 - - -// testbench module -module tinyriscv_soc_tb; - - reg clk; - reg rst_n; - - - always #10 clk = ~clk; // 50MHz - - wire[31:0] x3 = tinyriscv_soc_top_0.u_tinyriscv_core.u_gpr_reg.regs[3]; - wire[31:0] x26 = tinyriscv_soc_top_0.u_tinyriscv_core.u_gpr_reg.regs[26]; - wire[31:0] x27 = tinyriscv_soc_top_0.u_tinyriscv_core.u_gpr_reg.regs[27]; - - wire[31:0] ex_end_flag = tinyriscv_soc_top_0.u_ram.u_gen_ram.ram[4]; - wire[31:0] begin_signature = tinyriscv_soc_top_0.u_ram.u_gen_ram.ram[2]; - wire[31:0] end_signature = tinyriscv_soc_top_0.u_ram.u_gen_ram.ram[3]; - - integer r; - integer fd; - -`ifdef TEST_JTAG - reg TCK; - reg TMS; - reg TDI; - wire TDO; - - integer i; - reg[39:0] shift_reg; - reg in; - wire[39:0] req_data = tinyriscv_soc_top_0.u_jtag_top.u_jtag_driver.dtm_req_data; - wire[4:0] ir_reg = tinyriscv_soc_top_0.u_jtag_top.u_jtag_driver.ir_reg; - wire dtm_req_valid = tinyriscv_soc_top_0.u_jtag_top.u_jtag_driver.dtm_req_valid; - wire[31:0] dmstatus = tinyriscv_soc_top_0.u_jtag_top.u_jtag_dm.dmstatus; -`endif - - initial begin - clk = 0; - rst_n = 1'b1; -`ifdef TEST_JTAG - TCK = 1; - TMS = 1; - TDI = 1; -`endif - $display("test running..."); - #100 - rst_n = 1'b0; - #100 - rst_n = 1'b1; - #200 -/* -`ifdef TEST_PROG - wait(x26 == 32'b1) // wait sim end, when x26 == 1 - #100 - if (x27 == 32'b1) begin - $display("~~~~~~~~~~~~~~~~~~~ TEST_PASS ~~~~~~~~~~~~~~~~~~~"); - $display("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - $display("~~~~~~~~~ ##### ## #### #### ~~~~~~~~~"); - $display("~~~~~~~~~ # # # # # # ~~~~~~~~~"); - $display("~~~~~~~~~ # # # # #### #### ~~~~~~~~~"); - $display("~~~~~~~~~ ##### ###### # #~~~~~~~~~"); - $display("~~~~~~~~~ # # # # # # #~~~~~~~~~"); - $display("~~~~~~~~~ # # # #### #### ~~~~~~~~~"); - $display("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - end else begin - $display("~~~~~~~~~~~~~~~~~~~ TEST_FAIL ~~~~~~~~~~~~~~~~~~~~"); - $display("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - $display("~~~~~~~~~~###### ## # # ~~~~~~~~~~"); - $display("~~~~~~~~~~# # # # # ~~~~~~~~~~"); - $display("~~~~~~~~~~##### # # # # ~~~~~~~~~~"); - $display("~~~~~~~~~~# ###### # # ~~~~~~~~~~"); - $display("~~~~~~~~~~# # # # # ~~~~~~~~~~"); - $display("~~~~~~~~~~# # # # ######~~~~~~~~~~"); - $display("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - $display("fail testnum = %2d", x3); - for (r = 0; r < 32; r = r + 1) - $display("x%2d = 0x%x", r, tinyriscv_soc_top_0.u_tinyriscv_core.u_gpr_reg.regs[r]); - end -`endif -*/ - - wait(ex_end_flag == 32'h1); // wait sim end - - fd = $fopen(`OUTPUT); // OUTPUT的值在命令行里定义 - for (r = begin_signature; r < end_signature; r = r + 4) begin - $fdisplay(fd, "%x", tinyriscv_soc_top_0.u_rom.u_gen_ram.ram[r[31:2]]); - end - $fclose(fd); - -`ifdef TEST_JTAG - // reset - for (i = 0; i < 8; i++) begin - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - end - - // IR - shift_reg = 40'b10001; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SELECT-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SELECT-IR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // CAPTURE-IR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-IR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-IR & EXIT1-IR - for (i = 5; i > 0; i--) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #100 - in = TDO; - TCK = 1; - #100 - TCK = 0; - - shift_reg = {{(35){1'b0}}, in, shift_reg[4:1]}; - end - - // PAUSE-IR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // EXIT2-IR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // UPDATE-IR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // dmi write - shift_reg = {6'h10, {(32){1'b0}}, 2'b10}; - - // SELECT-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i--) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #100 - in = TDO; - TCK = 1; - #100 - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - // PAUSE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // EXIT2-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // UPDATE-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - $display("ir_reg = 0x%x", ir_reg); - $display("dtm_req_valid = %d", dtm_req_valid); - $display("req_data = 0x%x", req_data); - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - $display("dmstatus = 0x%x", dmstatus); - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SELECT-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // dmi read - shift_reg = {6'h11, {(32){1'b0}}, 2'b01}; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i--) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #100 - in = TDO; - TCK = 1; - #100 - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - // PAUSE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // EXIT2-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // UPDATE-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SELECT-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // dmi read - shift_reg = {6'h11, {(32){1'b0}}, 2'b00}; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i--) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #100 - in = TDO; - TCK = 1; - #100 - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - #100 - - $display("shift_reg = 0x%x", shift_reg[33:2]); - - if (dmstatus == shift_reg[33:2]) begin - $display("######################"); - $display("### jtag test pass ###"); - $display("######################"); - end else begin - $display("######################"); - $display("!!! jtag test fail !!!"); - $display("######################"); - end -`endif - - $finish; - end - - // sim timeout - initial begin - #500000 - $display("Time Out."); - $finish; - end - - // read mem data - initial begin - $readmemh ("inst.data", tinyriscv_soc_top_0.u_rom.u_gen_ram.ram); - end - - // generate wave file, used by gtkwave - initial begin - $dumpfile("tinyriscv_soc_tb.vcd"); - $dumpvars(0, tinyriscv_soc_tb); - end - - tinyriscv_soc_top tinyriscv_soc_top_0( - .clk(clk), - .rst_ext_i(rst_n) -`ifdef TEST_JTAG - , - .jtag_TCK(TCK), - .jtag_TMS(TMS), - .jtag_TDI(TDI), - .jtag_TDO(TDO) -`endif - ); - -endmodule diff --git a/tb/jtag_tb.v b/tb/jtag_tb.v deleted file mode 100644 index 880cdaa..0000000 --- a/tb/jtag_tb.v +++ /dev/null @@ -1,733 +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. - */ - -`timescale 1 ns / 1 ps - -`include "defines.v" - - -`define JTAG_CLK 500 // 1MHz. This value do not less than 100 - - -module jtag_tb; - - reg clk; - reg rst_n; - - reg TCK; - reg TMS; - reg TDI; - wire TDO; - - reg[39:0] shift_reg; - reg in; - reg[39:0] resp_data; - - - always #10 clk = ~clk; // core clock = 50MHz - - - integer i; - integer j; - - - task tap_reset; - begin - for (i = 0; i < 8; i = i + 1) begin - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - end - end - endtask - - task select_ir; - input[39:0] ir; - - begin - // IR - shift_reg = ir; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SELECT-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SELECT-IR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // CAPTURE-IR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-IR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-IR & EXIT1-IR - for (i = 5; i > 0; i = i - 1) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #`JTAG_CLK - in = TDO; - TCK = 1; - #`JTAG_CLK - TCK = 0; - - shift_reg = {{(35){1'b0}}, in, shift_reg[4:1]}; - end - - // PAUSE-IR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // EXIT2-IR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // UPDATE-IR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - end - endtask - - task dmi_write; - input[5:0] addr; - input[31:0] data; - output[39:0] out; - - begin - // op write - shift_reg = {addr, data, 2'b10}; - - // SELECT-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i = i - 1) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #`JTAG_CLK - in = TDO; - TCK = 1; - #`JTAG_CLK - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - // PAUSE-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // EXIT2-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // UPDATE-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // op nop - shift_reg = {addr, {(32){1'b0}}, 2'b00}; - - // SELECT-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i = i - 1) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #`JTAG_CLK - in = TDO; - TCK = 1; - #`JTAG_CLK - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - // PAUSE-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // EXIT2-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // UPDATE-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - out = shift_reg; - end - endtask - - task dmi_read; - input[5:0] addr; - output[39:0] out; - - begin - // op read - shift_reg = {addr, {(32){1'b0}}, 2'b01}; - - // SELECT-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i = i - 1) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #`JTAG_CLK - in = TDO; - TCK = 1; - #`JTAG_CLK - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - // PAUSE-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // EXIT2-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // UPDATE-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // op nop - shift_reg = {addr, {(32){1'b0}}, 2'b00}; - - // SELECT-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i = i - 1) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #`JTAG_CLK - in = TDO; - TCK = 1; - #`JTAG_CLK - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - // PAUSE-DR - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // EXIT2-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // UPDATE-DR - TMS = 1; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #`JTAG_CLK - TCK = 1; - #`JTAG_CLK - TCK = 0; - - out = shift_reg; - end - endtask - - - initial begin - clk = 0; - rst_n = 1'b1; - - TCK = 1; - TMS = 1; - TDI = 1; - shift_reg = 40'h0; - resp_data = 40'h0; - in = 1'b0; - - $display("test running..."); - #100 - rst_n = 1'b0; - #100 - rst_n = 1'b1; - #200 - - /*************************** start test ***************************/ - // reset TAP state machine - tap_reset(); - // select dm regs - select_ir(40'b10001); - // reset dm module - dmi_write(6'h10, 32'h0, resp_data); - - // read dmstatus reg - dmi_read(6'h11, resp_data); - $display("dmstatus = 0x%x", resp_data[33:2]); - - // write data to memory - dmi_write(6'h38, 32'h20050404, resp_data); // write sbcs - dmi_write(6'h39, 32'h0, resp_data); // write sbaddress0 - for (j = 0; j < 5; j = j + 1) begin - $display("write: addr = 0x%x, data = 0x%x", j * 4, 32'h0 + j); - dmi_write(6'h3c, 32'h0 + j, resp_data); // write sbdata0 - end - - // read data from memory - dmi_write(6'h38, 32'h20158404, resp_data); // write sbcs - dmi_write(6'h39, 32'h0, resp_data); // write sbaddress0 - for (j = 0; j < 5; j = j + 1) begin - dmi_read(6'h3c, resp_data); // read sbdata0 - $display("read: addr = 0x%x, data = 0x%x", j * 4, resp_data[33:2]); - end - - /////////////////////////////////////////////////////////// - // Check whether the data read is equal to the data written. - /////////////////////////////////////////////////////////// - - $finish; - end - - - // sim timeout - initial begin - #10000000 - $display("Time Out."); - $finish; - end - - // generate wave file, used by gtkwave - initial begin - $dumpfile("jtag_tb.vcd"); - $dumpvars(0, jtag_tb); - end - - tinyriscv_soc_top tinyriscv_soc_top_0( - .clk(clk), - .rst_ext_i(rst_n), - .jtag_TCK(TCK), - .jtag_TMS(TMS), - .jtag_TDI(TDI), - .jtag_TDO(TDO) - ); - -endmodule diff --git a/tb/tinyriscv_soc_tb.v b/tb/tinyriscv_soc_tb.v deleted file mode 100644 index 68dd84a..0000000 --- a/tb/tinyriscv_soc_tb.v +++ /dev/null @@ -1,521 +0,0 @@ -`timescale 1 ns / 1 ps - -`include "defines.v" - -// select one option only -`define TEST_PROG 1 -//`define TEST_JTAG 1 - - -// testbench module -module tinyriscv_soc_tb; - - reg clk; - reg rst_n; - - - always #10 clk = ~clk; // 50MHz - - wire[31:0] x3 = tinyriscv_soc_top_0.u_tinyriscv_core.u_gpr_reg.regs[3]; - wire[31:0] x26 = tinyriscv_soc_top_0.u_tinyriscv_core.u_gpr_reg.regs[26]; - wire[31:0] x27 = tinyriscv_soc_top_0.u_tinyriscv_core.u_gpr_reg.regs[27]; - - integer r; - -`ifdef TEST_JTAG - reg TCK; - reg TMS; - reg TDI; - wire TDO; - - integer i; - reg[39:0] shift_reg; - reg in; - wire[39:0] req_data = tinyriscv_soc_top_0.u_jtag_top.u_jtag_driver.dtm_req_data; - wire[4:0] ir_reg = tinyriscv_soc_top_0.u_jtag_top.u_jtag_driver.ir_reg; - wire dtm_req_valid = tinyriscv_soc_top_0.u_jtag_top.u_jtag_driver.dtm_req_valid; - wire[31:0] dmstatus = tinyriscv_soc_top_0.u_jtag_top.u_jtag_dm.dmstatus; -`endif - - initial begin - clk = 0; - rst_n = 1'b1; -`ifdef TEST_JTAG - TCK = 1; - TMS = 1; - TDI = 1; -`endif - $display("test running..."); - #100 - rst_n = 1'b0; - #100 - rst_n = 1'b1; - #200 - -`ifdef TEST_PROG - wait(x26 == 32'b1) // wait sim end, when x26 == 1 - #100 - if (x27 == 32'b1) begin - $display("~~~~~~~~~~~~~~~~~~~ TEST_PASS ~~~~~~~~~~~~~~~~~~~"); - $display("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - $display("~~~~~~~~~ ##### ## #### #### ~~~~~~~~~"); - $display("~~~~~~~~~ # # # # # # ~~~~~~~~~"); - $display("~~~~~~~~~ # # # # #### #### ~~~~~~~~~"); - $display("~~~~~~~~~ ##### ###### # #~~~~~~~~~"); - $display("~~~~~~~~~ # # # # # # #~~~~~~~~~"); - $display("~~~~~~~~~ # # # #### #### ~~~~~~~~~"); - $display("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - end else begin - $display("~~~~~~~~~~~~~~~~~~~ TEST_FAIL ~~~~~~~~~~~~~~~~~~~~"); - $display("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - $display("~~~~~~~~~~###### ## # # ~~~~~~~~~~"); - $display("~~~~~~~~~~# # # # # ~~~~~~~~~~"); - $display("~~~~~~~~~~##### # # # # ~~~~~~~~~~"); - $display("~~~~~~~~~~# ###### # # ~~~~~~~~~~"); - $display("~~~~~~~~~~# # # # # ~~~~~~~~~~"); - $display("~~~~~~~~~~# # # # ######~~~~~~~~~~"); - $display("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - $display("fail testnum = %2d", x3); - for (r = 0; r < 32; r = r + 1) - $display("x%2d = 0x%x", r, tinyriscv_soc_top_0.u_tinyriscv_core.u_gpr_reg.regs[r]); - end -`endif - -`ifdef TEST_JTAG - // reset - for (i = 0; i < 8; i++) begin - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - end - - // IR - shift_reg = 40'b10001; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SELECT-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SELECT-IR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // CAPTURE-IR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-IR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-IR & EXIT1-IR - for (i = 5; i > 0; i--) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #100 - in = TDO; - TCK = 1; - #100 - TCK = 0; - - shift_reg = {{(35){1'b0}}, in, shift_reg[4:1]}; - end - - // PAUSE-IR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // EXIT2-IR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // UPDATE-IR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // dmi write - shift_reg = {6'h10, {(32){1'b0}}, 2'b10}; - - // SELECT-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i--) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #100 - in = TDO; - TCK = 1; - #100 - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - // PAUSE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // EXIT2-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // UPDATE-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - $display("ir_reg = 0x%x", ir_reg); - $display("dtm_req_valid = %d", dtm_req_valid); - $display("req_data = 0x%x", req_data); - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - $display("dmstatus = 0x%x", dmstatus); - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SELECT-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // dmi read - shift_reg = {6'h11, {(32){1'b0}}, 2'b01}; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i--) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #100 - in = TDO; - TCK = 1; - #100 - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - // PAUSE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // EXIT2-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // UPDATE-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // IDLE - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SELECT-DR - TMS = 1; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // dmi read - shift_reg = {6'h11, {(32){1'b0}}, 2'b00}; - - // CAPTURE-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR - TMS = 0; - TCK = 0; - #100 - TCK = 1; - #100 - TCK = 0; - - // SHIFT-DR & EXIT1-DR - for (i = 40; i > 0; i--) begin - if (shift_reg[0] == 1'b1) - TDI = 1'b1; - else - TDI = 1'b0; - - if (i == 1) - TMS = 1; - - TCK = 0; - #100 - in = TDO; - TCK = 1; - #100 - TCK = 0; - - shift_reg = {in, shift_reg[39:1]}; - end - - #100 - - $display("shift_reg = 0x%x", shift_reg[33:2]); - - if (dmstatus == shift_reg[33:2]) begin - $display("######################"); - $display("### jtag test pass ###"); - $display("######################"); - end else begin - $display("######################"); - $display("!!! jtag test fail !!!"); - $display("######################"); - end -`endif - - $finish; - end - - // sim timeout - initial begin - #1000000 - $display("Time Out."); - $finish; - end - - // read mem data - initial begin - $readmemh ("inst.data", tinyriscv_soc_top_0.u_rom.u_gen_ram.ram); - end - - // generate wave file, used by gtkwave - initial begin - $dumpfile("tinyriscv_soc_tb.vcd"); - $dumpvars(0, tinyriscv_soc_tb); - end - - tinyriscv_soc_top tinyriscv_soc_top_0( - .clk(clk), - .rst_ext_i(rst_n) -`ifdef TEST_JTAG - , - .jtag_TCK(TCK), - .jtag_TMS(TMS), - .jtag_TDI(TDI), - .jtag_TDO(TDO) -`endif - ); - -endmodule diff --git a/tools/.gitignore b/tools/.gitignore index 65c5a67..4c37608 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -4,6 +4,3 @@ *.obj *.bin *.dump - -__pycache__ -gnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64 \ No newline at end of file diff --git a/tools/BinToMem_CLI.py b/tools/BinToMem.py similarity index 97% rename from tools/BinToMem_CLI.py rename to tools/BinToMem.py index 4fe5747..c7971cf 100644 --- a/tools/BinToMem_CLI.py +++ b/tools/BinToMem.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + import sys import os diff --git a/tools/openocd/openocd b/tools/openocd/openocd new file mode 100644 index 0000000000000000000000000000000000000000..eb7034340d90087b26c83fd98619c4940eade052 GIT binary patch literal 15308320 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