├── docs ├── biRISC-V.png ├── dual_issue.png ├── linux-boot.png ├── riscv_isa_spec.pdf ├── riscv_privileged_spec.pdf ├── linux.md ├── custom.md ├── integration.md └── configuration.md ├── tb ├── tb_tcm │ ├── test.elf │ ├── mem_api.h │ ├── sc_reset_gen.h │ ├── elf_load.h │ ├── makefile │ ├── makefile.generate_verilated │ ├── makefile.build_sysc_tb │ ├── makefile.build_verilated │ ├── testbench_vbase.h │ ├── riscv_tcm_top_rtl.h │ ├── main.cpp │ ├── axi4_lite.h │ ├── elf_load.cpp │ ├── testbench.h │ ├── riscv_tcm_top_rtl.cpp │ └── axi4.h ├── tb_top │ ├── test.elf │ ├── mem_api.h │ ├── sc_reset_gen.h │ ├── elf_load.h │ ├── axi4_defines.h │ ├── makefile │ ├── makefile.generate_verilated │ ├── makefile.build_sysc_tb │ ├── makefile.build_verilated │ ├── tb_axi4_mem.h │ ├── testbench_vbase.h │ ├── main.cpp │ ├── riscv_top.h │ ├── tb_memory.h │ ├── elf_load.cpp │ ├── tb_axi4_mem.cpp │ ├── testbench.h │ ├── axi4.h │ └── riscv_top.cpp └── tb_core_icarus │ ├── test.elf │ ├── makefile │ ├── tcm_mem_ram.v │ ├── gtksettings.sav │ ├── tb_top.v │ └── tcm_mem.v ├── src ├── icache │ ├── icache_data_ram.v │ └── icache_tag_ram.v ├── dcache │ ├── dcache_core_tag_ram.v │ ├── dcache_core_data_ram.v │ ├── dcache_pmem_mux.v │ ├── dcache_mux.v │ └── dcache_axi_axi.v ├── tcm │ ├── tcm_mem_ram.v │ └── dport_mux.v └── core │ ├── biriscv_multiplier.v │ ├── biriscv_xilinx_2r1w.v │ ├── biriscv_alu.v │ └── biriscv_divider.v └── README.md /docs/biRISC-V.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/biriscv/HEAD/docs/biRISC-V.png -------------------------------------------------------------------------------- /tb/tb_tcm/test.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/biriscv/HEAD/tb/tb_tcm/test.elf -------------------------------------------------------------------------------- /tb/tb_top/test.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/biriscv/HEAD/tb/tb_top/test.elf -------------------------------------------------------------------------------- /docs/dual_issue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/biriscv/HEAD/docs/dual_issue.png -------------------------------------------------------------------------------- /docs/linux-boot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/biriscv/HEAD/docs/linux-boot.png -------------------------------------------------------------------------------- /docs/riscv_isa_spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/biriscv/HEAD/docs/riscv_isa_spec.pdf -------------------------------------------------------------------------------- /tb/tb_core_icarus/test.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/biriscv/HEAD/tb/tb_core_icarus/test.elf -------------------------------------------------------------------------------- /docs/riscv_privileged_spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultraembedded/biriscv/HEAD/docs/riscv_privileged_spec.pdf -------------------------------------------------------------------------------- /tb/tb_tcm/mem_api.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEM_API_H__ 2 | #define __MEM_API_H__ 3 | 4 | #include 5 | 6 | //-------------------------------------------------------------------- 7 | // Abstract interface for memory access 8 | //-------------------------------------------------------------------- 9 | class mem_api 10 | { 11 | public: 12 | virtual bool create_memory(uint32_t addr, uint32_t size, uint8_t *mem = NULL) = 0; 13 | virtual bool valid_addr(uint32_t addr) = 0; 14 | virtual void write(uint32_t addr, uint8_t data) = 0; 15 | virtual uint8_t read(uint32_t addr) = 0; 16 | }; 17 | 18 | #endif -------------------------------------------------------------------------------- /tb/tb_top/mem_api.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEM_API_H__ 2 | #define __MEM_API_H__ 3 | 4 | #include 5 | 6 | //-------------------------------------------------------------------- 7 | // Abstract interface for memory access 8 | //-------------------------------------------------------------------- 9 | class mem_api 10 | { 11 | public: 12 | virtual bool create_memory(uint32_t addr, uint32_t size, uint8_t *mem = NULL) = 0; 13 | virtual bool valid_addr(uint32_t addr) = 0; 14 | virtual void write(uint32_t addr, uint8_t data) = 0; 15 | virtual uint8_t read(uint32_t addr) = 0; 16 | }; 17 | 18 | #endif -------------------------------------------------------------------------------- /tb/tb_tcm/sc_reset_gen.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //----------------------------------------------------------------- 4 | // Module 5 | //----------------------------------------------------------------- 6 | SC_MODULE(sc_reset_gen) 7 | { 8 | public: 9 | sc_in clk; 10 | sc_signal rst; 11 | 12 | void thread(void) 13 | { 14 | rst.write(true); 15 | wait(); 16 | rst.write(false); 17 | } 18 | 19 | SC_HAS_PROCESS(sc_reset_gen); 20 | sc_reset_gen(sc_module_name name): sc_module(name) 21 | { 22 | SC_CTHREAD(thread, clk); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /tb/tb_top/sc_reset_gen.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //----------------------------------------------------------------- 4 | // Module 5 | //----------------------------------------------------------------- 6 | SC_MODULE(sc_reset_gen) 7 | { 8 | public: 9 | sc_in clk; 10 | sc_signal rst; 11 | 12 | void thread(void) 13 | { 14 | rst.write(true); 15 | wait(); 16 | rst.write(false); 17 | } 18 | 19 | SC_HAS_PROCESS(sc_reset_gen); 20 | sc_reset_gen(sc_module_name name): sc_module(name) 21 | { 22 | SC_CTHREAD(thread, clk); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /tb/tb_tcm/elf_load.h: -------------------------------------------------------------------------------- 1 | #ifndef __ELF_LOAD_H__ 2 | #define __ELF_LOAD_H__ 3 | 4 | #include "mem_api.h" 5 | #include 6 | 7 | //-------------------------------------------------------------------- 8 | // ELF loader 9 | //-------------------------------------------------------------------- 10 | class elf_load 11 | { 12 | public: 13 | elf_load(const char *filename, mem_api *target); 14 | 15 | bool load(void); 16 | uint32_t get_entry_point(void) { return m_entry_point; } 17 | bool get_symbol(const char *symname, uint32_t &value); 18 | 19 | protected: 20 | std::string m_filename; 21 | mem_api * m_target; 22 | uint32_t m_entry_point; 23 | }; 24 | 25 | #endif -------------------------------------------------------------------------------- /tb/tb_top/elf_load.h: -------------------------------------------------------------------------------- 1 | #ifndef __ELF_LOAD_H__ 2 | #define __ELF_LOAD_H__ 3 | 4 | #include "mem_api.h" 5 | #include 6 | 7 | //-------------------------------------------------------------------- 8 | // ELF loader 9 | //-------------------------------------------------------------------- 10 | class elf_load 11 | { 12 | public: 13 | elf_load(const char *filename, mem_api *target); 14 | 15 | bool load(void); 16 | uint32_t get_entry_point(void) { return m_entry_point; } 17 | bool get_symbol(const char *symname, uint32_t &value); 18 | 19 | protected: 20 | std::string m_filename; 21 | mem_api * m_target; 22 | uint32_t m_entry_point; 23 | }; 24 | 25 | #endif -------------------------------------------------------------------------------- /tb/tb_top/axi4_defines.h: -------------------------------------------------------------------------------- 1 | #ifndef AXI4_DEFINES_H 2 | #define AXI4_DEFINES_H 3 | 4 | //-------------------------------------------------------------------- 5 | // Defines 6 | //-------------------------------------------------------------------- 7 | #define AXI4_ADDR_W 32 8 | #define AXI4_DATA_W 32 9 | #define AXI4_AXLEN_W 8 10 | #define AXI4_AXBURST_W 2 11 | #define AXI4_RESP_W 2 12 | #define AXI4_ID_W 4 13 | 14 | //-------------------------------------------------------------------- 15 | // Enumerations 16 | //-------------------------------------------------------------------- 17 | enum eAXI4_BURST 18 | { 19 | AXI4_BURST_FIXED, 20 | AXI4_BURST_INCR, 21 | AXI4_BURST_WRAP 22 | }; 23 | 24 | enum eAXI4_RESP 25 | { 26 | AXI4_RESP_OKAY, 27 | AXI4_RESP_EXOKAY, 28 | AXI4_RESP_SLVERR, 29 | AXI4_RESP_DECERR 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /tb/tb_tcm/makefile: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | ## Tool paths 3 | ############################################################################### 4 | VERILATOR_SRC ?= /usr/share/verilator/include 5 | SYSTEMC_HOME ?= /usr/local/systemc-2.3.1 6 | 7 | TEST_IMAGE ?= $(abspath ./test.elf) 8 | 9 | export VERILATOR_SRC 10 | export SYSTEMC_HOME 11 | 12 | ifeq (,$(wildcard $(VERILATOR_SRC))) 13 | ${error VERILATOR_SRC must be set to VERILATOR_INSTALL/include} 14 | endif 15 | ifeq (,$(wildcard $(SYSTEMC_HOME))) 16 | ${error SYSTEMC_HOME must be set} 17 | endif 18 | 19 | ############################################################################### 20 | ## Makefile 21 | ############################################################################### 22 | .PHONY: build 23 | all: build 24 | 25 | build: 26 | make -f makefile.generate_verilated 27 | make -f makefile.build_verilated 28 | make -f makefile.build_sysc_tb 29 | 30 | clean: 31 | make -f makefile.generate_verilated 32 | make -f makefile.build_verilated $@ 33 | make -f makefile.build_sysc_tb $@ 34 | -rm -rf *.vcd verilated 35 | 36 | run: build 37 | ./build/test.x -f $(TEST_IMAGE) -------------------------------------------------------------------------------- /tb/tb_top/makefile: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | ## Tool paths 3 | ############################################################################### 4 | VERILATOR_SRC ?= /usr/share/verilator/include 5 | SYSTEMC_HOME ?= /usr/local/systemc-2.3.1 6 | 7 | TEST_IMAGE ?= $(abspath ./test.elf) 8 | 9 | export VERILATOR_SRC 10 | export SYSTEMC_HOME 11 | 12 | ifeq (,$(wildcard $(VERILATOR_SRC))) 13 | ${error VERILATOR_SRC must be set to VERILATOR_INSTALL/include} 14 | endif 15 | ifeq (,$(wildcard $(SYSTEMC_HOME))) 16 | ${error SYSTEMC_HOME must be set} 17 | endif 18 | 19 | ############################################################################### 20 | ## Makefile 21 | ############################################################################### 22 | .PHONY: build 23 | all: build 24 | 25 | build: 26 | make -f makefile.generate_verilated 27 | make -f makefile.build_verilated 28 | make -f makefile.build_sysc_tb 29 | 30 | clean: 31 | make -f makefile.generate_verilated 32 | make -f makefile.build_verilated $@ 33 | make -f makefile.build_sysc_tb $@ 34 | -rm -rf *.vcd verilated 35 | 36 | run: build 37 | ./build/test.x -f $(TEST_IMAGE) -------------------------------------------------------------------------------- /docs/linux.md: -------------------------------------------------------------------------------- 1 | ## Booting Linux on biRISC-V 2 | 3 | The core currently implements RV32IM + machine/supervisor/user mode and has basic MMU support. 4 | The mainline Linux kernel requires RV-A (atomics) instruction support (this is a future planned feature for biRISC-V). 5 | 6 | Atomic instruction support can be emulated with a machine mode bootloader (with a performance penalty), allowing unmodified Linux kernel and userspace images to be used. 7 | This currently allows biRISC-V to successfully boot Linux to userspace. 8 | 9 | ### Required SW components 10 | * riscv-linux-boot (SBI bootloader) - [https://github.com/ultraembedded/riscv-linux-boot](https://github.com/ultraembedded/riscv-linux-boot) 11 | * Prebuilt Kernel images - [https://github.com/ultraembedded/riscv-linux-prebuilt](https://github.com/ultraembedded/riscv-linux-prebuilt) 12 | 13 | ### Required HW components 14 | * biRISC-V configured to run Linux (see [configuration guide](configuration.md)) 15 | * 32MB+ SDRAM/DDR available @ 0x80000000 16 | * Xilinx UART-Lite accessible @ 0x92000000 17 | 18 | ### Building combined kernel + bootloader 19 | ``` 20 | cd riscv-linux-boot 21 | make LINUX_DIR=/path/to/riscv-linux-prebuilt VMLINUX=/path/to/riscv-linux-prebuilt/kernel/vmlinux-rv32ima-5.0 DTS_FILE=/path/to/riscv-linux-prebuilt/dts/config32.dts 22 | ``` 23 | 24 | ### Example Output 25 | Running on a Digilent Arty Artix 7 (35T); 26 | 27 | ![Linux-Boot](linux-boot.png) 28 | -------------------------------------------------------------------------------- /tb/tb_tcm/makefile.generate_verilated: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Variables 3 | ############################################################################### 4 | CORE ?= core 5 | PARAMS ?= 6 | OUTPUT_DIR ?= verilated 7 | SRC_DIR ?= ../../src/top 8 | SRC_TYPE ?= v 9 | SRC_V_DIR ?= ../../src/top 10 | OUTPUT_SUFFIX ?= 11 | SRC ?= riscv_tcm_top 12 | NAME ?= riscv_tcm_top 13 | 14 | RTL_INCLUDE = ../../src/core ../../src/tcm 15 | 16 | # Verilator options 17 | VERILATE_PARAMS ?= --trace 18 | VERILATOR_OPTS ?= --pins-sc-uint --unroll-count 512 19 | 20 | OLDER_VERILATOR := $(shell verilator --l2-name v 2>&1 | grep "Invalid Option" | wc -l) 21 | 22 | ifeq ($(OLDER_VERILATOR),0) 23 | VERILATOR_OPTS += --l2-name v 24 | endif 25 | 26 | TARGETS ?= $(OUTPUT_DIR)/V$(NAME) 27 | 28 | ############################################################################### 29 | # Rules 30 | ############################################################################### 31 | all: $(TARGETS) 32 | 33 | $(OUTPUT_DIR): 34 | mkdir -p $@ 35 | 36 | $(OUTPUT_DIR)/V$(NAME): $(SRC_DIR)/$(SRC).$(SRC_TYPE) | $(OUTPUT_DIR) 37 | verilator --sc $(patsubst $(OUTPUT_DIR)/V$(NAME), $(SRC_V_DIR)/$(NAME), $@) --Mdir $(OUTPUT_DIR) -I./$(SRC_V_DIR) $(patsubst %,-I%,$(RTL_INCLUDE)) $(VERILATOR_OPTS) $(VERILATE_PARAMS) 38 | 39 | clean: 40 | rm -rf $(TARGETS) $(OUTPUT_DIR) 41 | -------------------------------------------------------------------------------- /tb/tb_top/makefile.generate_verilated: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Variables 3 | ############################################################################### 4 | CORE ?= core 5 | PARAMS ?= 6 | OUTPUT_DIR ?= verilated 7 | SRC_DIR ?= ../../src/top 8 | SRC_TYPE ?= v 9 | SRC_V_DIR ?= ../../src/top 10 | OUTPUT_SUFFIX ?= 11 | SRC ?= riscv_top 12 | NAME ?= riscv_top 13 | 14 | RTL_INCLUDE = ../../src/core ../../src/icache ../../src/dcache 15 | 16 | # Verilator options 17 | VERILATE_PARAMS ?= --trace 18 | VERILATOR_OPTS ?= --pins-sc-uint --unroll-count 512 19 | 20 | OLDER_VERILATOR := $(shell verilator --l2-name v 2>&1 | grep "Invalid Option" | wc -l) 21 | 22 | ifeq ($(OLDER_VERILATOR),0) 23 | VERILATOR_OPTS += --l2-name v 24 | endif 25 | 26 | TARGETS ?= $(OUTPUT_DIR)/V$(NAME) 27 | 28 | ############################################################################### 29 | # Rules 30 | ############################################################################### 31 | all: $(TARGETS) 32 | 33 | $(OUTPUT_DIR): 34 | mkdir -p $@ 35 | 36 | $(OUTPUT_DIR)/V$(NAME): $(SRC_DIR)/$(SRC).$(SRC_TYPE) | $(OUTPUT_DIR) 37 | verilator --sc $(patsubst $(OUTPUT_DIR)/V$(NAME), $(SRC_V_DIR)/$(NAME), $@) --Mdir $(OUTPUT_DIR) -I./$(SRC_V_DIR) $(patsubst %,-I%,$(RTL_INCLUDE)) $(VERILATOR_OPTS) $(VERILATE_PARAMS) 38 | 39 | clean: 40 | rm -rf $(TARGETS) $(OUTPUT_DIR) 41 | -------------------------------------------------------------------------------- /tb/tb_tcm/makefile.build_sysc_tb: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Variables 3 | ############################################################################### 4 | VERILATOR_SRC ?= /usr/share/verilator/include 5 | SYSTEMC_HOME ?= /usr/local/systemc-2.3.1 6 | 7 | OBJ_DIR ?= obj/ 8 | EXE_DIR ?= build/ 9 | SRC_DIR ?= ./ 10 | 11 | TARGET ?= test.x 12 | 13 | # Additional include directories 14 | INCLUDE_PATH ?= 15 | INCLUDE_PATH += $(SRC_DIR) 16 | INCLUDE_PATH += ./verilated 17 | INCLUDE_PATH += $(VERILATOR_SRC) 18 | INCLUDE_PATH += $(VERILATOR_SRC)/vltstd 19 | INCLUDE_PATH += $(SYSTEMC_HOME)/include 20 | 21 | # Dependancies 22 | LIB_PATH ?= 23 | LIB_PATH += ./lib 24 | LIBS = -lsyscverilated -lelf -lbfd 25 | 26 | # Flags 27 | CFLAGS ?= -fpic -O2 28 | CFLAGS += $(patsubst %,-I%,$(INCLUDE_PATH)) 29 | CFLAGS += -DVM_TRACE=1 30 | LDFLAGS ?= -O2 31 | LDFLAGS += -L$(SYSTEMC_HOME)/lib-linux64 32 | LDFLAGS += $(patsubst %,-L%,$(LIB_PATH)) 33 | 34 | EXTRA_CLEAN_FILES ?= 35 | 36 | # SRC / Object list 37 | src2obj = $(OBJ_DIR)$(patsubst %$(suffix $(1)),%.o,$(notdir $(1))) 38 | SRC ?= $(foreach src,$(SRC_DIR),$(wildcard $(src)/*.cpp)) 39 | OBJ ?= $(foreach src,$(SRC),$(call src2obj,$(src))) 40 | 41 | ############################################################################### 42 | # Rules 43 | ############################################################################### 44 | define template_c 45 | $(call src2obj,$(1)): $(1) | $(OBJ_DIR) 46 | g++ $(CFLAGS) -c $$< -o $$@ 47 | endef 48 | 49 | all: $(EXE_DIR)$(TARGET) 50 | 51 | $(OBJ_DIR) $(EXE_DIR): 52 | mkdir -p $@ 53 | 54 | $(foreach src,$(SRC),$(eval $(call template_c,$(src)))) 55 | 56 | $(EXE_DIR)$(TARGET): $(OBJ) | $(EXE_DIR) 57 | g++ $(LDFLAGS) $(OBJ) -o $@ -lsystemc $(LIBS) 58 | 59 | clean: 60 | rm -rf $(EXE_DIR) $(OBJ_DIR) $(EXTRA_CLEAN_FILES) 61 | -------------------------------------------------------------------------------- /tb/tb_top/makefile.build_sysc_tb: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Variables 3 | ############################################################################### 4 | VERILATOR_SRC ?= /usr/share/verilator/include 5 | SYSTEMC_HOME ?= /usr/local/systemc-2.3.1 6 | 7 | OBJ_DIR ?= obj/ 8 | EXE_DIR ?= build/ 9 | SRC_DIR ?= ./ 10 | 11 | TARGET ?= test.x 12 | 13 | # Additional include directories 14 | INCLUDE_PATH ?= 15 | INCLUDE_PATH += $(SRC_DIR) 16 | INCLUDE_PATH += ./verilated 17 | INCLUDE_PATH += $(VERILATOR_SRC) 18 | INCLUDE_PATH += $(VERILATOR_SRC)/vltstd 19 | INCLUDE_PATH += $(SYSTEMC_HOME)/include 20 | 21 | # Dependancies 22 | LIB_PATH ?= 23 | LIB_PATH += ./lib 24 | LIBS = -lsyscverilated -lelf -lbfd 25 | 26 | # Flags 27 | CFLAGS ?= -fpic -O2 28 | CFLAGS += $(patsubst %,-I%,$(INCLUDE_PATH)) 29 | CFLAGS += -DVM_TRACE=1 30 | LDFLAGS ?= -O2 31 | LDFLAGS += -L$(SYSTEMC_HOME)/lib-linux64 32 | LDFLAGS += $(patsubst %,-L%,$(LIB_PATH)) 33 | 34 | EXTRA_CLEAN_FILES ?= 35 | 36 | # SRC / Object list 37 | src2obj = $(OBJ_DIR)$(patsubst %$(suffix $(1)),%.o,$(notdir $(1))) 38 | SRC ?= $(foreach src,$(SRC_DIR),$(wildcard $(src)/*.cpp)) 39 | OBJ ?= $(foreach src,$(SRC),$(call src2obj,$(src))) 40 | 41 | ############################################################################### 42 | # Rules 43 | ############################################################################### 44 | define template_c 45 | $(call src2obj,$(1)): $(1) | $(OBJ_DIR) 46 | g++ $(CFLAGS) -c $$< -o $$@ 47 | endef 48 | 49 | all: $(EXE_DIR)$(TARGET) 50 | 51 | $(OBJ_DIR) $(EXE_DIR): 52 | mkdir -p $@ 53 | 54 | $(foreach src,$(SRC),$(eval $(call template_c,$(src)))) 55 | 56 | $(EXE_DIR)$(TARGET): $(OBJ) | $(EXE_DIR) 57 | g++ $(LDFLAGS) $(OBJ) -o $@ -lsystemc $(LIBS) 58 | 59 | clean: 60 | rm -rf $(EXE_DIR) $(OBJ_DIR) $(EXTRA_CLEAN_FILES) 61 | -------------------------------------------------------------------------------- /tb/tb_tcm/makefile.build_verilated: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Variables 3 | ############################################################################### 4 | VERILATOR_SRC ?= /usr/share/verilator/include 5 | SYSTEMC_HOME ?= /usr/local/systemc-2.3.1 6 | 7 | SRC_DIR ?= verilated/ 8 | OBJ_DIR ?= obj_verilated/ 9 | LIB_DIR ?= lib/ 10 | 11 | LIBNAME ?= libsyscverilated.a 12 | 13 | # Additional include directories 14 | INCLUDE_PATH ?= 15 | INCLUDE_PATH += $(SRC_DIR) 16 | INCLUDE_PATH += $(SYSTEMC_HOME)/include 17 | INCLUDE_PATH += $(VERILATOR_SRC) 18 | INCLUDE_PATH += $(VERILATOR_SRC)/vltstd 19 | 20 | # Flags 21 | CFLAGS ?= 22 | CFLAGS += -DVM_TRACE=1 -DVL_USER_FINISH=1 23 | CFLAGS += -fpic 24 | CFLAGS += $(patsubst %,-I%,$(INCLUDE_PATH)) 25 | CFLAGS += $(EXTRA_CFLAGS) 26 | 27 | LIB_OPT ?= $(SYSTEMC_HOME)/lib-linux64/libsystemc.a 28 | 29 | # SRC / Object list 30 | src2obj = $(OBJ_DIR)$(patsubst %$(suffix $(1)),%.o,$(notdir $(1))) 31 | SRC_LIST = $(foreach src,$(SRC_DIR),$(wildcard $(src)/*.cpp)) 32 | SRC_LIST += $(VERILATOR_SRC)/verilated.cpp 33 | SRC_LIST += $(VERILATOR_SRC)/verilated_vcd_c.cpp 34 | SRC_LIST += $(VERILATOR_SRC)/verilated_vcd_sc.cpp 35 | 36 | OBJ ?= $(foreach src,$(SRC_LIST),$(call src2obj,$(src))) 37 | 38 | ############################################################################### 39 | # Rules 40 | ############################################################################### 41 | define template_c 42 | $(call src2obj,$(1)): $(1) | $(OBJ_DIR) 43 | g++ $(CFLAGS) -c $$< -o $$@ 44 | endef 45 | 46 | all: $(LIB_DIR)$(LIBNAME) 47 | 48 | $(OBJ_DIR) $(LIB_DIR): 49 | mkdir -p $@ 50 | 51 | $(foreach src,$(SRC_LIST),$(eval $(call template_c,$(src)))) 52 | 53 | $(LIB_DIR)$(LIBNAME): $(OBJ) | $(LIB_DIR) 54 | g++ -shared -o $(LIB_DIR)$(LIBNAME) $(LIB_OPT) $(OBJ) 55 | 56 | clean: 57 | rm -rf $(LIB_DIR) $(OBJ_DIR) 58 | -------------------------------------------------------------------------------- /tb/tb_top/makefile.build_verilated: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Variables 3 | ############################################################################### 4 | VERILATOR_SRC ?= /usr/share/verilator/include 5 | SYSTEMC_HOME ?= /usr/local/systemc-2.3.1 6 | 7 | SRC_DIR ?= verilated/ 8 | OBJ_DIR ?= obj_verilated/ 9 | LIB_DIR ?= lib/ 10 | 11 | LIBNAME ?= libsyscverilated.a 12 | 13 | # Additional include directories 14 | INCLUDE_PATH ?= 15 | INCLUDE_PATH += $(SRC_DIR) 16 | INCLUDE_PATH += $(SYSTEMC_HOME)/include 17 | INCLUDE_PATH += $(VERILATOR_SRC) 18 | INCLUDE_PATH += $(VERILATOR_SRC)/vltstd 19 | 20 | # Flags 21 | CFLAGS ?= 22 | CFLAGS += -DVM_TRACE=1 -DVL_USER_FINISH=1 23 | CFLAGS += -fpic 24 | CFLAGS += $(patsubst %,-I%,$(INCLUDE_PATH)) 25 | CFLAGS += $(EXTRA_CFLAGS) 26 | 27 | LIB_OPT ?= $(SYSTEMC_HOME)/lib-linux64/libsystemc.a 28 | 29 | # SRC / Object list 30 | src2obj = $(OBJ_DIR)$(patsubst %$(suffix $(1)),%.o,$(notdir $(1))) 31 | SRC_LIST = $(foreach src,$(SRC_DIR),$(wildcard $(src)/*.cpp)) 32 | SRC_LIST += $(VERILATOR_SRC)/verilated.cpp 33 | SRC_LIST += $(VERILATOR_SRC)/verilated_vcd_c.cpp 34 | SRC_LIST += $(VERILATOR_SRC)/verilated_vcd_sc.cpp 35 | 36 | OBJ ?= $(foreach src,$(SRC_LIST),$(call src2obj,$(src))) 37 | 38 | ############################################################################### 39 | # Rules 40 | ############################################################################### 41 | define template_c 42 | $(call src2obj,$(1)): $(1) | $(OBJ_DIR) 43 | g++ $(CFLAGS) -c $$< -o $$@ 44 | endef 45 | 46 | all: $(LIB_DIR)$(LIBNAME) 47 | 48 | $(OBJ_DIR) $(LIB_DIR): 49 | mkdir -p $@ 50 | 51 | $(foreach src,$(SRC_LIST),$(eval $(call template_c,$(src)))) 52 | 53 | $(LIB_DIR)$(LIBNAME): $(OBJ) | $(LIB_DIR) 54 | g++ -shared -o $(LIB_DIR)$(LIBNAME) $(LIB_OPT) $(OBJ) 55 | 56 | clean: 57 | rm -rf $(LIB_DIR) $(OBJ_DIR) 58 | -------------------------------------------------------------------------------- /src/icache/icache_data_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module icache_data_ram 27 | ( 28 | // Inputs 29 | input clk_i 30 | ,input rst_i 31 | ,input [ 9:0] addr_i 32 | ,input [ 63:0] data_i 33 | ,input wr_i 34 | 35 | // Outputs 36 | ,output [ 63:0] data_o 37 | ); 38 | 39 | 40 | 41 | 42 | //----------------------------------------------------------------- 43 | // Single Port RAM 8KB 44 | // Mode: Read First 45 | //----------------------------------------------------------------- 46 | reg [63:0] ram [1023:0] /*verilator public*/; 47 | reg [63:0] ram_read_q; 48 | 49 | // Synchronous write 50 | always @ (posedge clk_i) 51 | begin 52 | if (wr_i) 53 | ram[addr_i] <= data_i; 54 | ram_read_q <= ram[addr_i]; 55 | end 56 | 57 | assign data_o = ram_read_q; 58 | 59 | 60 | 61 | endmodule 62 | -------------------------------------------------------------------------------- /src/icache/icache_tag_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module icache_tag_ram 27 | ( 28 | // Inputs 29 | input clk_i 30 | ,input rst_i 31 | ,input [ 7:0] addr_i 32 | ,input [ 19:0] data_i 33 | ,input wr_i 34 | 35 | // Outputs 36 | ,output [ 19:0] data_o 37 | ); 38 | 39 | 40 | 41 | 42 | //----------------------------------------------------------------- 43 | // Single Port RAM 0KB 44 | // Mode: Read First 45 | //----------------------------------------------------------------- 46 | reg [19:0] ram [255:0] /*verilator public*/; 47 | reg [19:0] ram_read_q; 48 | 49 | // Synchronous write 50 | always @ (posedge clk_i) 51 | begin 52 | if (wr_i) 53 | ram[addr_i] <= data_i; 54 | ram_read_q <= ram[addr_i]; 55 | end 56 | 57 | assign data_o = ram_read_q; 58 | 59 | 60 | 61 | endmodule 62 | -------------------------------------------------------------------------------- /tb/tb_core_icarus/makefile: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Variables: Program ELF 3 | ############################################################################### 4 | ELF_FILE ?= test.elf 5 | 6 | OBJCOPY ?= riscv32-unknown-elf-objcopy 7 | ifeq ($(shell which $(OBJCOPY)),) 8 | ${error $(OBJCOPY) missing from PATH} 9 | endif 10 | ifeq ($(shell which iverilog),) 11 | ${error iverilog missing from PATH - Icarus Verilog required} 12 | endif 13 | 14 | 15 | ############################################################################### 16 | # Variables: Defaults 17 | ############################################################################### 18 | TRACE ?= 1 19 | 20 | SRC_V_DIR ?= ../../src/core . 21 | SRC_DIR ?= . 22 | 23 | EXE ?= output.out 24 | 25 | ############################################################################### 26 | # Variables: Verilog 27 | ############################################################################### 28 | SRC_V ?= $(foreach src,$(SRC_V_DIR),$(wildcard $(src)/*.v)) 29 | 30 | VFLAGS += $(patsubst %,-I%,$(SRC_V_DIR)) 31 | VFLAGS += -DTRACE=$(TRACE) 32 | VFLAGS += -Dverilog_sim 33 | 34 | ############################################################################### 35 | # Variables: Lists of objects, source and deps 36 | ############################################################################### 37 | BUILD_DIR ?= build/ 38 | 39 | ############################################################################### 40 | # Rules 41 | ############################################################################### 42 | all: run 43 | 44 | $(BUILD_DIR): 45 | @mkdir -p $@ 46 | 47 | $(BUILD_DIR)/tcm.bin: $(ELF_FILE) | $(BUILD_DIR) 48 | $(OBJCOPY) $< -O binary $@ 49 | 50 | $(BUILD_DIR)/$(EXE): $(SRC_V) | $(BUILD_DIR) 51 | @echo "# Compiling verilog" 52 | iverilog $(VFLAGS) -o $@ $(SRC_V) 53 | 54 | run: $(BUILD_DIR)/$(EXE) $(BUILD_DIR)/tcm.bin 55 | vvp $(BUILD_DIR)/$(EXE) -vcd 56 | 57 | view: 58 | gtkwave waveform.vcd gtksettings.sav 59 | 60 | clean: 61 | rm -rf $(BUILD_DIR) *.vcd 62 | 63 | -------------------------------------------------------------------------------- /src/dcache/dcache_core_tag_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module dcache_core_tag_ram 27 | ( 28 | // Inputs 29 | input clk0_i 30 | ,input rst0_i 31 | ,input [ 7:0] addr0_i 32 | ,input clk1_i 33 | ,input rst1_i 34 | ,input [ 7:0] addr1_i 35 | ,input [ 20:0] data1_i 36 | ,input wr1_i 37 | 38 | // Outputs 39 | ,output [ 20:0] data0_o 40 | ); 41 | 42 | 43 | 44 | //----------------------------------------------------------------- 45 | // Tag RAM 0KB (256 x 21) 46 | // Mode: Write First 47 | //----------------------------------------------------------------- 48 | /* verilator lint_off MULTIDRIVEN */ 49 | reg [20:0] ram [255:0] /*verilator public*/; 50 | /* verilator lint_on MULTIDRIVEN */ 51 | 52 | reg [20:0] ram_read0_q; 53 | 54 | always @ (posedge clk1_i) 55 | begin 56 | if (wr1_i) 57 | ram[addr1_i] = data1_i; 58 | 59 | ram_read0_q = ram[addr0_i]; 60 | end 61 | 62 | assign data0_o = ram_read0_q; 63 | 64 | 65 | endmodule 66 | -------------------------------------------------------------------------------- /tb/tb_core_icarus/tcm_mem_ram.v: -------------------------------------------------------------------------------- 1 | 2 | module tcm_mem_ram 3 | ( 4 | // Inputs 5 | input clk0_i 6 | ,input rst0_i 7 | ,input [ 13:0] addr0_i 8 | ,input [ 63:0] data0_i 9 | ,input [ 7:0] wr0_i 10 | ,input clk1_i 11 | ,input rst1_i 12 | ,input [ 13:0] addr1_i 13 | ,input [ 63:0] data1_i 14 | ,input [ 7:0] wr1_i 15 | 16 | // Outputs 17 | ,output [ 63:0] data0_o 18 | ,output [ 63:0] data1_o 19 | ); 20 | 21 | 22 | 23 | //----------------------------------------------------------------- 24 | // Dual Port RAM 128KB 25 | // Mode: Read First 26 | //----------------------------------------------------------------- 27 | /* verilator lint_off MULTIDRIVEN */ 28 | reg [63:0] ram [16383:0] /*verilator public*/; 29 | /* verilator lint_on MULTIDRIVEN */ 30 | 31 | reg [63:0] ram_read0_q; 32 | reg [63:0] ram_read1_q; 33 | 34 | 35 | // Synchronous write 36 | always @ (posedge clk0_i) 37 | begin 38 | if (wr0_i[0]) 39 | ram[addr0_i][7:0] <= data0_i[7:0]; 40 | if (wr0_i[1]) 41 | ram[addr0_i][15:8] <= data0_i[15:8]; 42 | if (wr0_i[2]) 43 | ram[addr0_i][23:16] <= data0_i[23:16]; 44 | if (wr0_i[3]) 45 | ram[addr0_i][31:24] <= data0_i[31:24]; 46 | if (wr0_i[4]) 47 | ram[addr0_i][39:32] <= data0_i[39:32]; 48 | if (wr0_i[5]) 49 | ram[addr0_i][47:40] <= data0_i[47:40]; 50 | if (wr0_i[6]) 51 | ram[addr0_i][55:48] <= data0_i[55:48]; 52 | if (wr0_i[7]) 53 | ram[addr0_i][63:56] <= data0_i[63:56]; 54 | 55 | ram_read0_q <= ram[addr0_i]; 56 | end 57 | 58 | always @ (posedge clk1_i) 59 | begin 60 | if (wr1_i[0]) 61 | ram[addr1_i][7:0] <= data1_i[7:0]; 62 | if (wr1_i[1]) 63 | ram[addr1_i][15:8] <= data1_i[15:8]; 64 | if (wr1_i[2]) 65 | ram[addr1_i][23:16] <= data1_i[23:16]; 66 | if (wr1_i[3]) 67 | ram[addr1_i][31:24] <= data1_i[31:24]; 68 | if (wr1_i[4]) 69 | ram[addr1_i][39:32] <= data1_i[39:32]; 70 | if (wr1_i[5]) 71 | ram[addr1_i][47:40] <= data1_i[47:40]; 72 | if (wr1_i[6]) 73 | ram[addr1_i][55:48] <= data1_i[55:48]; 74 | if (wr1_i[7]) 75 | ram[addr1_i][63:56] <= data1_i[63:56]; 76 | 77 | ram_read1_q <= ram[addr1_i]; 78 | end 79 | 80 | assign data0_o = ram_read0_q; 81 | assign data1_o = ram_read1_q; 82 | 83 | 84 | 85 | endmodule 86 | -------------------------------------------------------------------------------- /tb/tb_top/tb_axi4_mem.h: -------------------------------------------------------------------------------- 1 | #ifndef TB_AXI4_MEM_H 2 | #define TB_AXI4_MEM_H 3 | 4 | #include "axi4.h" 5 | #include "axi4_defines.h" 6 | #include "tb_memory.h" 7 | 8 | //------------------------------------------------------------- 9 | // tb_axi4_mem: AXI4 testbench memory 10 | //------------------------------------------------------------- 11 | class tb_axi4_mem: public sc_module, public tb_memory 12 | { 13 | public: 14 | //------------------------------------------------------------- 15 | // Interface I/O 16 | //------------------------------------------------------------- 17 | sc_in clk_in; 18 | sc_in rst_in; 19 | 20 | sc_in axi_in; 21 | sc_out axi_out; 22 | 23 | //------------------------------------------------------------- 24 | // Constructor 25 | //------------------------------------------------------------- 26 | SC_HAS_PROCESS(tb_axi4_mem); 27 | tb_axi4_mem(sc_module_name name): sc_module(name) 28 | { 29 | SC_CTHREAD(process, clk_in.pos()); 30 | m_enable_delays = true; 31 | } 32 | 33 | //------------------------------------------------------------- 34 | // Trace 35 | //------------------------------------------------------------- 36 | void add_trace(sc_trace_file *vcd, std::string prefix) 37 | { 38 | #undef TRACE_SIGNAL 39 | #define TRACE_SIGNAL(s) sc_trace(vcd,s,prefix + #s) 40 | 41 | TRACE_SIGNAL(axi_out); 42 | TRACE_SIGNAL(axi_in); 43 | 44 | #undef TRACE_SIGNAL 45 | } 46 | 47 | //------------------------------------------------------------- 48 | // API 49 | //------------------------------------------------------------- 50 | void enable_delays(bool enable) { m_enable_delays = enable; } 51 | void write(uint32_t addr, uint8_t data); 52 | uint8_t read(uint32_t addr); 53 | void write32(uint32_t addr, uint32_t data, uint8_t strb = 0xF); 54 | uint32_t read32(uint32_t addr); 55 | 56 | void process(void); 57 | bool delay_cycle(void) { return m_enable_delays ? rand() & 1 : 0; } 58 | 59 | sc_uint calc_wrap_mask(sc_uint len); 60 | sc_uint calc_next_addr(sc_uint addr, sc_uint type, sc_uint len); 61 | 62 | protected: 63 | bool m_enable_delays; 64 | }; 65 | 66 | #endif -------------------------------------------------------------------------------- /docs/custom.md: -------------------------------------------------------------------------------- 1 | ## Custom Features (non RISC-V standard) 2 | 3 | ### Timer 4 | 5 | The timer supported in bi-RISC-V is a 32-bit cycle counter with the option to generate timer interrupts on match. 6 | 7 | The RISC-V privileged spec refers to memory mapped **mtime** and **mtimecmp** registers. 8 | In bi-RISC-V these are mapped to CSR registers for fast access and low external dependence. 9 | 10 | **mtime** is mapped to CSR **mcycle** and **rdtime** and is limited to 32-bits (continuously counting, wrapping). 11 | **mtimecmp** is mapped to a custom CSR address and is limited to 32-bits and will generate an interrupt on matching **mtime** (interrupt routed to **MSTATUS.MTIP**). 12 | 13 | ``` 14 | #define csr_read(reg) ({ uint32_t __tmp; \ 15 | asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ 16 | __tmp; }) 17 | 18 | #define csr_write(reg, val) ({ \ 19 | asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) 20 | 21 | void timer_set_mtimecmp(uint32_t next) 22 | { 23 | csr_write(0x7c0, next); 24 | } 25 | 26 | uint32_t timer_get_mtime(void) 27 | { 28 | return csr_read(0xc00); // or 0xc01 29 | } 30 | void timer_set_mtime(uint32_t value) 31 | { 32 | csr_write(0xc01, value); 33 | } 34 | ``` 35 | 36 | ### Instruction Cache Flush 37 | 38 | Flushing the instruction cache is achieved using **fence.i** which is in-keeping with the behaviour specified in the *Zifence* section of the RISC-V ISA specification; 39 | 40 | ``` 41 | void icache_flush(void) 42 | { 43 | asm volatile ("fence.i"); 44 | } 45 | ``` 46 | 47 | ### Data Cache Control 48 | 49 | Cacheable regions of memory are specified at the core build time using the following parameters; 50 | 51 | ``` 52 | ,.MEM_CACHE_ADDR_MIN(32'h80000000) 53 | ,.MEM_CACHE_ADDR_MAX(32'h8fffffff) 54 | ``` 55 | 56 | The data cache also has the following dynamic controls; 57 | * Flush: Writeback all dirty lines, mark all lines as invalid (global flush). 58 | * Writeback: Writeback a specific line (if dirty), leave line as valid in the cache (if it was present). 59 | * Invalidate: Invalidate a specific line without writing back if dirty, mark line as invalid in the cache (if it was present). 60 | 61 | These controls are mapped to **pmpcfg0**, **pmpcfg1** and **pmpcfg2** CSRs currently; 62 | 63 | ``` 64 | void dcache_flush(void) 65 | { 66 | asm volatile ("csrw pmpcfg0, x0"); // 0x3a0 67 | } 68 | void dcache_writeback(uint32_t addr) 69 | { 70 | asm volatile ("csrw pmpcfg1, %0": : "r" (addr)); // 0x3a1 71 | } 72 | void dcache_invalidate(uint32_t addr) 73 | { 74 | asm volatile ("csrw pmpcfg2, %0": : "r" (addr)); // 0x3a2 75 | } 76 | ``` 77 | 78 | However, these mappings can be changed by altering the following definitions; 79 | ``` 80 | `define CSR_DFLUSH 12'h3a0 81 | `define CSR_DWRITEBACK 12'h3a1 82 | `define CSR_DINVALIDATE 12'h3a2 83 | ``` 84 | -------------------------------------------------------------------------------- /tb/tb_tcm/testbench_vbase.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTBENCH_VBASE_H 2 | #define TESTBENCH_VBASE_H 3 | 4 | #include 5 | #include "verilated.h" 6 | #include "verilated_vcd_sc.h" 7 | 8 | #define verilator_trace_enable(vcd_filename, dut) \ 9 | if (waves_enabled()) \ 10 | { \ 11 | Verilated::traceEverOn(true); \ 12 | VerilatedVcdC *v_vcd = new VerilatedVcdC; \ 13 | sc_core::sc_time delay_us; \ 14 | if (waves_delayed(delay_us)) \ 15 | dut->trace_enable (v_vcd, delay_us); \ 16 | else \ 17 | dut->trace_enable (v_vcd); \ 18 | v_vcd->open (vcd_filename); \ 19 | this->m_verilate_vcd = v_vcd; \ 20 | } 21 | 22 | //----------------------------------------------------------------- 23 | // Module 24 | //----------------------------------------------------------------- 25 | class testbench_vbase: public sc_module 26 | { 27 | public: 28 | sc_in clk; 29 | sc_in rst; 30 | 31 | virtual void set_testcase(int tc) { } 32 | virtual void set_delays(bool en) { } 33 | virtual void set_iterations(int iterations) { } 34 | virtual void set_argcv(int argc, char* argv[]) { } 35 | 36 | virtual void process(void) { while (1) wait(); } 37 | virtual void monitor(void) { while (1) wait(); } 38 | 39 | SC_HAS_PROCESS(testbench_vbase); 40 | testbench_vbase(sc_module_name name): sc_module(name) 41 | { 42 | SC_CTHREAD(process, clk); 43 | SC_CTHREAD(monitor, clk); 44 | } 45 | 46 | virtual void add_trace(sc_trace_file * fp, std::string prefix) { } 47 | 48 | virtual void abort(void) 49 | { 50 | cout << "TB: Aborted at " << sc_time_stamp() << endl; 51 | if (m_verilate_vcd) 52 | { 53 | m_verilate_vcd->flush(); 54 | m_verilate_vcd->close(); 55 | m_verilate_vcd = NULL; 56 | } 57 | } 58 | 59 | bool waves_enabled(void) 60 | { 61 | char *s = getenv("ENABLE_WAVES"); 62 | if (s && !strcmp(s, "no")) 63 | return false; 64 | else 65 | return true; 66 | } 67 | 68 | bool waves_delayed(sc_core::sc_time &delay) 69 | { 70 | char *s = getenv("WAVES_DELAY_US"); 71 | if (s != NULL) 72 | { 73 | uint32_t us = strtoul(s, NULL, 0); 74 | printf("WAVES: Delay start until %duS\n", us); 75 | delay = sc_core::sc_time(us, SC_US); 76 | return true; 77 | } 78 | else 79 | return false; 80 | } 81 | 82 | std::string getenv_str(std::string name, std::string defval) 83 | { 84 | char *s = getenv(name.c_str()); 85 | if (!s || (s && !strcmp(s, ""))) 86 | return defval; 87 | else 88 | return std::string(s); 89 | } 90 | 91 | protected: 92 | VerilatedVcdC *m_verilate_vcd; 93 | }; 94 | 95 | #endif -------------------------------------------------------------------------------- /tb/tb_top/testbench_vbase.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTBENCH_VBASE_H 2 | #define TESTBENCH_VBASE_H 3 | 4 | #include 5 | #include "verilated.h" 6 | #include "verilated_vcd_sc.h" 7 | 8 | #define verilator_trace_enable(vcd_filename, dut) \ 9 | if (waves_enabled()) \ 10 | { \ 11 | Verilated::traceEverOn(true); \ 12 | VerilatedVcdC *v_vcd = new VerilatedVcdC; \ 13 | sc_core::sc_time delay_us; \ 14 | if (waves_delayed(delay_us)) \ 15 | dut->trace_enable (v_vcd, delay_us); \ 16 | else \ 17 | dut->trace_enable (v_vcd); \ 18 | v_vcd->open (vcd_filename); \ 19 | this->m_verilate_vcd = v_vcd; \ 20 | } 21 | 22 | //----------------------------------------------------------------- 23 | // Module 24 | //----------------------------------------------------------------- 25 | class testbench_vbase: public sc_module 26 | { 27 | public: 28 | sc_in clk; 29 | sc_in rst; 30 | 31 | virtual void set_testcase(int tc) { } 32 | virtual void set_delays(bool en) { } 33 | virtual void set_iterations(int iterations) { } 34 | virtual void set_argcv(int argc, char* argv[]) { } 35 | 36 | virtual void process(void) { while (1) wait(); } 37 | virtual void monitor(void) { while (1) wait(); } 38 | 39 | SC_HAS_PROCESS(testbench_vbase); 40 | testbench_vbase(sc_module_name name): sc_module(name) 41 | { 42 | SC_CTHREAD(process, clk); 43 | SC_CTHREAD(monitor, clk); 44 | } 45 | 46 | virtual void add_trace(sc_trace_file * fp, std::string prefix) { } 47 | 48 | virtual void abort(void) 49 | { 50 | cout << "TB: Aborted at " << sc_time_stamp() << endl; 51 | if (m_verilate_vcd) 52 | { 53 | m_verilate_vcd->flush(); 54 | m_verilate_vcd->close(); 55 | m_verilate_vcd = NULL; 56 | } 57 | } 58 | 59 | bool waves_enabled(void) 60 | { 61 | char *s = getenv("ENABLE_WAVES"); 62 | if (s && !strcmp(s, "no")) 63 | return false; 64 | else 65 | return true; 66 | } 67 | 68 | bool waves_delayed(sc_core::sc_time &delay) 69 | { 70 | char *s = getenv("WAVES_DELAY_US"); 71 | if (s != NULL) 72 | { 73 | uint32_t us = strtoul(s, NULL, 0); 74 | printf("WAVES: Delay start until %duS\n", us); 75 | delay = sc_core::sc_time(us, SC_US); 76 | return true; 77 | } 78 | else 79 | return false; 80 | } 81 | 82 | std::string getenv_str(std::string name, std::string defval) 83 | { 84 | char *s = getenv(name.c_str()); 85 | if (!s || (s && !strcmp(s, ""))) 86 | return defval; 87 | else 88 | return std::string(s); 89 | } 90 | 91 | protected: 92 | VerilatedVcdC *m_verilate_vcd; 93 | }; 94 | 95 | #endif -------------------------------------------------------------------------------- /src/dcache/dcache_core_data_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module dcache_core_data_ram 27 | ( 28 | // Inputs 29 | input clk0_i 30 | ,input rst0_i 31 | ,input [ 10:0] addr0_i 32 | ,input [ 31:0] data0_i 33 | ,input [ 3:0] wr0_i 34 | ,input clk1_i 35 | ,input rst1_i 36 | ,input [ 10:0] addr1_i 37 | ,input [ 31:0] data1_i 38 | ,input [ 3:0] wr1_i 39 | 40 | // Outputs 41 | ,output [ 31:0] data0_o 42 | ,output [ 31:0] data1_o 43 | ); 44 | 45 | 46 | 47 | //----------------------------------------------------------------- 48 | // Dual Port RAM 8KB 49 | // Mode: Read First 50 | //----------------------------------------------------------------- 51 | /* verilator lint_off MULTIDRIVEN */ 52 | reg [31:0] ram [2047:0] /*verilator public*/; 53 | /* verilator lint_on MULTIDRIVEN */ 54 | 55 | reg [31:0] ram_read0_q; 56 | reg [31:0] ram_read1_q; 57 | 58 | 59 | // Synchronous write 60 | always @ (posedge clk0_i) 61 | begin 62 | if (wr0_i[0]) 63 | ram[addr0_i][7:0] <= data0_i[7:0]; 64 | if (wr0_i[1]) 65 | ram[addr0_i][15:8] <= data0_i[15:8]; 66 | if (wr0_i[2]) 67 | ram[addr0_i][23:16] <= data0_i[23:16]; 68 | if (wr0_i[3]) 69 | ram[addr0_i][31:24] <= data0_i[31:24]; 70 | 71 | ram_read0_q <= ram[addr0_i]; 72 | end 73 | 74 | always @ (posedge clk1_i) 75 | begin 76 | if (wr1_i[0]) 77 | ram[addr1_i][7:0] <= data1_i[7:0]; 78 | if (wr1_i[1]) 79 | ram[addr1_i][15:8] <= data1_i[15:8]; 80 | if (wr1_i[2]) 81 | ram[addr1_i][23:16] <= data1_i[23:16]; 82 | if (wr1_i[3]) 83 | ram[addr1_i][31:24] <= data1_i[31:24]; 84 | 85 | ram_read1_q <= ram[addr1_i]; 86 | end 87 | 88 | assign data0_o = ram_read0_q; 89 | assign data1_o = ram_read1_q; 90 | 91 | 92 | 93 | endmodule 94 | -------------------------------------------------------------------------------- /tb/tb_core_icarus/gtksettings.sav: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI 3 | [*] Mon Feb 24 23:52:21 2020 4 | [*] 5 | [timestart] 0 6 | [size] 2560 1385 7 | [pos] -1 -1 8 | *-12.000000 9125 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 9 | [treeopen] tb_top. 10 | [treeopen] tb_top.u_dut. 11 | [treeopen] tb_top.u_dut.u_issue. 12 | [treeopen] tb_top.u_dut.u_issue.u_regfile. 13 | [sst_width] 202 14 | [signals_width] 206 15 | [sst_expanded] 1 16 | [sst_vpaned_height] 420 17 | @28 18 | tb_top.clk 19 | tb_top.rst 20 | @800200 21 | -I 22 | @28 23 | tb_top.mem_i_rd_w 24 | @22 25 | tb_top.mem_i_pc_w[31:0] 26 | @28 27 | tb_top.mem_i_valid_w 28 | @22 29 | tb_top.mem_i_inst_w[63:0] 30 | @1000200 31 | -I 32 | @800200 33 | -D 34 | @28 35 | tb_top.mem_d_rd_w 36 | @22 37 | tb_top.mem_d_wr_w[3:0] 38 | tb_top.mem_d_addr_w[31:0] 39 | tb_top.u_mem.mem_d_req_tag_i[10:0] 40 | tb_top.mem_d_data_wr_w[31:0] 41 | @29 42 | tb_top.mem_d_accept_w 43 | @28 44 | tb_top.mem_d_ack_w 45 | @22 46 | tb_top.u_mem.mem_d_resp_tag_o[10:0] 47 | tb_top.mem_d_data_rd_w[31:0] 48 | @28 49 | tb_top.mem_d_error_w 50 | @1000200 51 | -D 52 | @800200 53 | -PC 54 | @22 55 | tb_top.u_dut.u_frontend.u_fetch.pc_f_q[31:0] 56 | tb_top.u_dut.u_frontend.u_fetch.pc_d_q[31:0] 57 | tb_top.u_dut.u_issue.pc_x_q[31:0] 58 | tb_top.u_dut.u_issue.u_pipe0_ctrl.pc_e1_q[31:0] 59 | tb_top.u_dut.u_issue.u_pipe0_ctrl.pc_e2_q[31:0] 60 | tb_top.u_dut.u_issue.u_pipe0_ctrl.pc_wb_q[31:0] 61 | @1000200 62 | -PC 63 | @800200 64 | -Regfile 65 | @22 66 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x0_zero_w[31:0] 67 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x1_ra_w[31:0] 68 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x2_sp_w[31:0] 69 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x3_gp_w[31:0] 70 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x4_tp_w[31:0] 71 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x5_t0_w[31:0] 72 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x6_t1_w[31:0] 73 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x7_t2_w[31:0] 74 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x8_s0_w[31:0] 75 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x9_s1_w[31:0] 76 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x10_a0_w[31:0] 77 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x11_a1_w[31:0] 78 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x12_a2_w[31:0] 79 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x13_a3_w[31:0] 80 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x14_a4_w[31:0] 81 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x15_a5_w[31:0] 82 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x16_a6_w[31:0] 83 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x17_a7_w[31:0] 84 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x18_s2_w[31:0] 85 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x19_s3_w[31:0] 86 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x20_s4_w[31:0] 87 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x21_s5_w[31:0] 88 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x22_s6_w[31:0] 89 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x23_s7_w[31:0] 90 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x24_s8_w[31:0] 91 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x25_s9_w[31:0] 92 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x26_s10_w[31:0] 93 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x27_s11_w[31:0] 94 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x28_t3_w[31:0] 95 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x29_t4_w[31:0] 96 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x30_t5_w[31:0] 97 | tb_top.u_dut.u_issue.u_regfile.REGFILE.x31_t6_w[31:0] 98 | @1000200 99 | -Regfile 100 | [pattern_trace] 1 101 | [pattern_trace] 0 102 | -------------------------------------------------------------------------------- /src/tcm/tcm_mem_ram.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module tcm_mem_ram 27 | ( 28 | // Inputs 29 | input clk0_i 30 | ,input rst0_i 31 | ,input [ 12:0] addr0_i 32 | ,input [ 63:0] data0_i 33 | ,input [ 7:0] wr0_i 34 | ,input clk1_i 35 | ,input rst1_i 36 | ,input [ 12:0] addr1_i 37 | ,input [ 63:0] data1_i 38 | ,input [ 7:0] wr1_i 39 | 40 | // Outputs 41 | ,output [ 63:0] data0_o 42 | ,output [ 63:0] data1_o 43 | ); 44 | 45 | 46 | 47 | //----------------------------------------------------------------- 48 | // Dual Port RAM 64KB 49 | // Mode: Read First 50 | //----------------------------------------------------------------- 51 | /* verilator lint_off MULTIDRIVEN */ 52 | reg [63:0] ram [8191:0] /*verilator public*/; 53 | /* verilator lint_on MULTIDRIVEN */ 54 | 55 | reg [63:0] ram_read0_q; 56 | reg [63:0] ram_read1_q; 57 | 58 | 59 | // Synchronous write 60 | always @ (posedge clk0_i) 61 | begin 62 | if (wr0_i[0]) 63 | ram[addr0_i][7:0] <= data0_i[7:0]; 64 | if (wr0_i[1]) 65 | ram[addr0_i][15:8] <= data0_i[15:8]; 66 | if (wr0_i[2]) 67 | ram[addr0_i][23:16] <= data0_i[23:16]; 68 | if (wr0_i[3]) 69 | ram[addr0_i][31:24] <= data0_i[31:24]; 70 | if (wr0_i[4]) 71 | ram[addr0_i][39:32] <= data0_i[39:32]; 72 | if (wr0_i[5]) 73 | ram[addr0_i][47:40] <= data0_i[47:40]; 74 | if (wr0_i[6]) 75 | ram[addr0_i][55:48] <= data0_i[55:48]; 76 | if (wr0_i[7]) 77 | ram[addr0_i][63:56] <= data0_i[63:56]; 78 | 79 | ram_read0_q <= ram[addr0_i]; 80 | end 81 | 82 | always @ (posedge clk1_i) 83 | begin 84 | if (wr1_i[0]) 85 | ram[addr1_i][7:0] <= data1_i[7:0]; 86 | if (wr1_i[1]) 87 | ram[addr1_i][15:8] <= data1_i[15:8]; 88 | if (wr1_i[2]) 89 | ram[addr1_i][23:16] <= data1_i[23:16]; 90 | if (wr1_i[3]) 91 | ram[addr1_i][31:24] <= data1_i[31:24]; 92 | if (wr1_i[4]) 93 | ram[addr1_i][39:32] <= data1_i[39:32]; 94 | if (wr1_i[5]) 95 | ram[addr1_i][47:40] <= data1_i[47:40]; 96 | if (wr1_i[6]) 97 | ram[addr1_i][55:48] <= data1_i[55:48]; 98 | if (wr1_i[7]) 99 | ram[addr1_i][63:56] <= data1_i[63:56]; 100 | 101 | ram_read1_q <= ram[addr1_i]; 102 | end 103 | 104 | assign data0_o = ram_read0_q; 105 | assign data1_o = ram_read1_q; 106 | 107 | 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /tb/tb_core_icarus/tb_top.v: -------------------------------------------------------------------------------- 1 | module tb_top; 2 | 3 | reg clk; 4 | reg rst; 5 | 6 | reg [7:0] mem[131072:0]; 7 | integer i; 8 | integer f; 9 | 10 | initial 11 | begin 12 | $display("Starting bench"); 13 | 14 | if (`TRACE) 15 | begin 16 | $dumpfile("waveform.vcd"); 17 | $dumpvars(0, tb_top); 18 | end 19 | 20 | // Reset 21 | clk = 0; 22 | rst = 1; 23 | repeat (5) @(posedge clk); 24 | rst = 0; 25 | 26 | // Load TCM memory 27 | for (i=0;i<131072;i=i+1) 28 | mem[i] = 0; 29 | 30 | f = $fopenr("./build/tcm.bin"); 31 | i = $fread(mem, f); 32 | for (i=0;i<131072;i=i+1) 33 | u_mem.write(i, mem[i]); 34 | end 35 | 36 | initial 37 | begin 38 | forever 39 | begin 40 | clk = #5 ~clk; 41 | end 42 | end 43 | 44 | wire mem_i_rd_w; 45 | wire mem_i_flush_w; 46 | wire mem_i_invalidate_w; 47 | wire [ 31:0] mem_i_pc_w; 48 | wire [ 31:0] mem_d_addr_w; 49 | wire [ 31:0] mem_d_data_wr_w; 50 | wire mem_d_rd_w; 51 | wire [ 3:0] mem_d_wr_w; 52 | wire mem_d_cacheable_w; 53 | wire [ 10:0] mem_d_req_tag_w; 54 | wire mem_d_invalidate_w; 55 | wire mem_d_writeback_w; 56 | wire mem_d_flush_w; 57 | wire mem_i_accept_w; 58 | wire mem_i_valid_w; 59 | wire mem_i_error_w; 60 | wire [ 63:0] mem_i_inst_w; 61 | wire [ 31:0] mem_d_data_rd_w; 62 | wire mem_d_accept_w; 63 | wire mem_d_ack_w; 64 | wire mem_d_error_w; 65 | wire [ 10:0] mem_d_resp_tag_w; 66 | 67 | riscv_core 68 | u_dut 69 | //----------------------------------------------------------------- 70 | // Ports 71 | //----------------------------------------------------------------- 72 | ( 73 | // Inputs 74 | .clk_i(clk) 75 | ,.rst_i(rst) 76 | ,.mem_d_data_rd_i(mem_d_data_rd_w) 77 | ,.mem_d_accept_i(mem_d_accept_w) 78 | ,.mem_d_ack_i(mem_d_ack_w) 79 | ,.mem_d_error_i(mem_d_error_w) 80 | ,.mem_d_resp_tag_i(mem_d_resp_tag_w) 81 | ,.mem_i_accept_i(mem_i_accept_w) 82 | ,.mem_i_valid_i(mem_i_valid_w) 83 | ,.mem_i_error_i(mem_i_error_w) 84 | ,.mem_i_inst_i(mem_i_inst_w) 85 | ,.intr_i(1'b0) 86 | ,.reset_vector_i(32'h80000000) 87 | ,.cpu_id_i('b0) 88 | 89 | // Outputs 90 | ,.mem_d_addr_o(mem_d_addr_w) 91 | ,.mem_d_data_wr_o(mem_d_data_wr_w) 92 | ,.mem_d_rd_o(mem_d_rd_w) 93 | ,.mem_d_wr_o(mem_d_wr_w) 94 | ,.mem_d_cacheable_o(mem_d_cacheable_w) 95 | ,.mem_d_req_tag_o(mem_d_req_tag_w) 96 | ,.mem_d_invalidate_o(mem_d_invalidate_w) 97 | ,.mem_d_writeback_o(mem_d_writeback_w) 98 | ,.mem_d_flush_o(mem_d_flush_w) 99 | ,.mem_i_rd_o(mem_i_rd_w) 100 | ,.mem_i_flush_o(mem_i_flush_w) 101 | ,.mem_i_invalidate_o(mem_i_invalidate_w) 102 | ,.mem_i_pc_o(mem_i_pc_w) 103 | ); 104 | 105 | tcm_mem 106 | u_mem 107 | ( 108 | // Inputs 109 | .clk_i(clk) 110 | ,.rst_i(rst) 111 | ,.mem_i_rd_i(mem_i_rd_w) 112 | ,.mem_i_flush_i(mem_i_flush_w) 113 | ,.mem_i_invalidate_i(mem_i_invalidate_w) 114 | ,.mem_i_pc_i(mem_i_pc_w) 115 | ,.mem_d_addr_i(mem_d_addr_w) 116 | ,.mem_d_data_wr_i(mem_d_data_wr_w) 117 | ,.mem_d_rd_i(mem_d_rd_w) 118 | ,.mem_d_wr_i(mem_d_wr_w) 119 | ,.mem_d_cacheable_i(mem_d_cacheable_w) 120 | ,.mem_d_req_tag_i(mem_d_req_tag_w) 121 | ,.mem_d_invalidate_i(mem_d_invalidate_w) 122 | ,.mem_d_writeback_i(mem_d_writeback_w) 123 | ,.mem_d_flush_i(mem_d_flush_w) 124 | 125 | // Outputs 126 | ,.mem_i_accept_o(mem_i_accept_w) 127 | ,.mem_i_valid_o(mem_i_valid_w) 128 | ,.mem_i_error_o(mem_i_error_w) 129 | ,.mem_i_inst_o(mem_i_inst_w) 130 | ,.mem_d_data_rd_o(mem_d_data_rd_w) 131 | ,.mem_d_accept_o(mem_d_accept_w) 132 | ,.mem_d_ack_o(mem_d_ack_w) 133 | ,.mem_d_error_o(mem_d_error_w) 134 | ,.mem_d_resp_tag_o(mem_d_resp_tag_w) 135 | ); 136 | 137 | endmodule -------------------------------------------------------------------------------- /tb/tb_core_icarus/tcm_mem.v: -------------------------------------------------------------------------------- 1 | 2 | module tcm_mem 3 | ( 4 | // Inputs 5 | input clk_i 6 | ,input rst_i 7 | ,input mem_i_rd_i 8 | ,input mem_i_flush_i 9 | ,input mem_i_invalidate_i 10 | ,input [ 31:0] mem_i_pc_i 11 | ,input [ 31:0] mem_d_addr_i 12 | ,input [ 31:0] mem_d_data_wr_i 13 | ,input mem_d_rd_i 14 | ,input [ 3:0] mem_d_wr_i 15 | ,input mem_d_cacheable_i 16 | ,input [ 10:0] mem_d_req_tag_i 17 | ,input mem_d_invalidate_i 18 | ,input mem_d_writeback_i 19 | ,input mem_d_flush_i 20 | 21 | // Outputs 22 | ,output mem_i_accept_o 23 | ,output mem_i_valid_o 24 | ,output mem_i_error_o 25 | ,output [ 63:0] mem_i_inst_o 26 | ,output [ 31:0] mem_d_data_rd_o 27 | ,output mem_d_accept_o 28 | ,output mem_d_ack_o 29 | ,output mem_d_error_o 30 | ,output [ 10:0] mem_d_resp_tag_o 31 | ); 32 | 33 | //------------------------------------------------------------- 34 | // Dual Port RAM 35 | //------------------------------------------------------------- 36 | wire muxed_hi_w = mem_d_addr_i[2]; 37 | wire [63:0] data_r_w; 38 | 39 | tcm_mem_ram 40 | u_ram 41 | ( 42 | // Instruction fetch 43 | .clk0_i(clk_i) 44 | ,.rst0_i(rst_i) 45 | ,.addr0_i(mem_i_pc_i[16:3]) 46 | ,.data0_i(64'b0) 47 | ,.wr0_i(8'b0) 48 | 49 | // External access / Data access 50 | ,.clk1_i(clk_i) 51 | ,.rst1_i(rst_i) 52 | ,.addr1_i(mem_d_addr_i[16:3]) 53 | ,.data1_i(muxed_hi_w ? {mem_d_data_wr_i, 32'b0} : {32'b0, mem_d_data_wr_i}) 54 | ,.wr1_i(muxed_hi_w ? {mem_d_wr_i, 4'b0} : {4'b0, mem_d_wr_i}) 55 | 56 | // Outputs 57 | ,.data0_o(mem_i_inst_o) 58 | ,.data1_o(data_r_w) 59 | ); 60 | 61 | reg muxed_hi_q; 62 | 63 | always @ (posedge clk_i ) 64 | if (rst_i) 65 | muxed_hi_q <= 1'b0; 66 | else 67 | muxed_hi_q <= muxed_hi_w; 68 | 69 | //------------------------------------------------------------- 70 | // Instruction Fetch 71 | //------------------------------------------------------------- 72 | reg mem_i_valid_q; 73 | 74 | always @ (posedge clk_i ) 75 | if (rst_i) 76 | mem_i_valid_q <= 1'b0; 77 | else 78 | mem_i_valid_q <= mem_i_rd_i; 79 | 80 | assign mem_i_accept_o = 1'b1; 81 | assign mem_i_valid_o = mem_i_valid_q; 82 | assign mem_i_error_o = 1'b0; 83 | 84 | //------------------------------------------------------------- 85 | // Data Access / Incoming external access 86 | //------------------------------------------------------------- 87 | reg mem_d_accept_q; 88 | reg mem_d_ack_q; 89 | reg [10:0] mem_d_tag_q; 90 | 91 | always @ (posedge clk_i ) 92 | if (rst_i) 93 | begin 94 | mem_d_ack_q <= 1'b0; 95 | mem_d_tag_q <= 11'b0; 96 | end 97 | else if ((mem_d_rd_i || mem_d_wr_i != 4'b0 || mem_d_flush_i || mem_d_invalidate_i || mem_d_writeback_i) && mem_d_accept_o) 98 | begin 99 | mem_d_ack_q <= 1'b1; 100 | mem_d_tag_q <= mem_d_req_tag_i; 101 | end 102 | else 103 | mem_d_ack_q <= 1'b0; 104 | 105 | assign mem_d_ack_o = mem_d_ack_q; 106 | assign mem_d_resp_tag_o = mem_d_tag_q; 107 | assign mem_d_data_rd_o = muxed_hi_q ? data_r_w[63:32] : data_r_w[31:0]; 108 | assign mem_d_error_o = 1'b0; 109 | 110 | assign mem_d_accept_o = 1'b1; 111 | 112 | //------------------------------------------------------------- 113 | // write: Write byte into memory 114 | //------------------------------------------------------------- 115 | task write; /*verilator public*/ 116 | input [31:0] addr; 117 | input [7:0] data; 118 | begin 119 | case (addr[2:0]) 120 | 3'd0: u_ram.ram[addr/8][7:0] = data; 121 | 3'd1: u_ram.ram[addr/8][15:8] = data; 122 | 3'd2: u_ram.ram[addr/8][23:16] = data; 123 | 3'd3: u_ram.ram[addr/8][31:24] = data; 124 | 3'd4: u_ram.ram[addr/8][39:32] = data; 125 | 3'd5: u_ram.ram[addr/8][47:40] = data; 126 | 3'd6: u_ram.ram[addr/8][55:48] = data; 127 | 3'd7: u_ram.ram[addr/8][63:56] = data; 128 | endcase 129 | end 130 | endtask 131 | 132 | 133 | endmodule 134 | -------------------------------------------------------------------------------- /src/dcache/dcache_pmem_mux.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module dcache_pmem_mux 27 | ( 28 | // Inputs 29 | input clk_i 30 | ,input rst_i 31 | ,input outport_accept_i 32 | ,input outport_ack_i 33 | ,input outport_error_i 34 | ,input [ 31:0] outport_read_data_i 35 | ,input select_i 36 | ,input [ 3:0] inport0_wr_i 37 | ,input inport0_rd_i 38 | ,input [ 7:0] inport0_len_i 39 | ,input [ 31:0] inport0_addr_i 40 | ,input [ 31:0] inport0_write_data_i 41 | ,input [ 3:0] inport1_wr_i 42 | ,input inport1_rd_i 43 | ,input [ 7:0] inport1_len_i 44 | ,input [ 31:0] inport1_addr_i 45 | ,input [ 31:0] inport1_write_data_i 46 | 47 | // Outputs 48 | ,output [ 3:0] outport_wr_o 49 | ,output outport_rd_o 50 | ,output [ 7:0] outport_len_o 51 | ,output [ 31:0] outport_addr_o 52 | ,output [ 31:0] outport_write_data_o 53 | ,output inport0_accept_o 54 | ,output inport0_ack_o 55 | ,output inport0_error_o 56 | ,output [ 31:0] inport0_read_data_o 57 | ,output inport1_accept_o 58 | ,output inport1_ack_o 59 | ,output inport1_error_o 60 | ,output [ 31:0] inport1_read_data_o 61 | ); 62 | 63 | 64 | 65 | 66 | //----------------------------------------------------------------- 67 | // Output Mux 68 | //----------------------------------------------------------------- 69 | reg [ 3:0] outport_wr_r; 70 | reg outport_rd_r; 71 | reg [ 7:0] outport_len_r; 72 | reg [ 31:0] outport_addr_r; 73 | reg [ 31:0] outport_write_data_r; 74 | reg select_q; 75 | 76 | always @ * 77 | begin 78 | case (select_i) 79 | 1'd1: 80 | begin 81 | outport_wr_r = inport1_wr_i; 82 | outport_rd_r = inport1_rd_i; 83 | outport_len_r = inport1_len_i; 84 | outport_addr_r = inport1_addr_i; 85 | outport_write_data_r = inport1_write_data_i; 86 | end 87 | default: 88 | begin 89 | outport_wr_r = inport0_wr_i; 90 | outport_rd_r = inport0_rd_i; 91 | outport_len_r = inport0_len_i; 92 | outport_addr_r = inport0_addr_i; 93 | outport_write_data_r = inport0_write_data_i; 94 | end 95 | endcase 96 | end 97 | 98 | assign outport_wr_o = outport_wr_r; 99 | assign outport_rd_o = outport_rd_r; 100 | assign outport_len_o = outport_len_r; 101 | assign outport_addr_o = outport_addr_r; 102 | assign outport_write_data_o = outport_write_data_r; 103 | 104 | // Delayed version of selector to match phase of response signals 105 | always @ (posedge clk_i or posedge rst_i) 106 | if (rst_i) 107 | select_q <= 1'b0; 108 | else 109 | select_q <= select_i; 110 | 111 | assign inport0_ack_o = (select_q == 1'd0) && outport_ack_i; 112 | assign inport0_error_o = (select_q == 1'd0) && outport_error_i; 113 | assign inport0_read_data_o = outport_read_data_i; 114 | assign inport0_accept_o = (select_i == 1'd0) && outport_accept_i; 115 | assign inport1_ack_o = (select_q == 1'd1) && outport_ack_i; 116 | assign inport1_error_o = (select_q == 1'd1) && outport_error_i; 117 | assign inport1_read_data_o = outport_read_data_i; 118 | assign inport1_accept_o = (select_i == 1'd1) && outport_accept_i; 119 | 120 | 121 | endmodule 122 | -------------------------------------------------------------------------------- /tb/tb_tcm/riscv_tcm_top_rtl.h: -------------------------------------------------------------------------------- 1 | #ifndef RISCV_TCM_TOP_RTL_H 2 | #define RISCV_TCM_TOP_RTL_H 3 | 4 | #include 5 | 6 | #include "axi4_lite.h" 7 | #include "axi4.h" 8 | 9 | class Vriscv_tcm_top; 10 | class VerilatedVcdC; 11 | 12 | //------------------------------------------------------------- 13 | // riscv_tcm_top_rtl: RTL wrapper class 14 | //------------------------------------------------------------- 15 | class riscv_tcm_top_rtl: public sc_module 16 | { 17 | public: 18 | sc_in clk_in; 19 | sc_in rst_in; 20 | sc_in rst_cpu_in; 21 | sc_in < sc_uint <32> > intr_in; 22 | 23 | sc_in axi_i_in; 24 | sc_out axi_i_out; 25 | sc_in axi_t_in; 26 | sc_out axi_t_out; 27 | 28 | //------------------------------------------------------------- 29 | // Constructor 30 | //------------------------------------------------------------- 31 | SC_HAS_PROCESS(riscv_tcm_top_rtl); 32 | riscv_tcm_top_rtl(sc_module_name name); 33 | 34 | //------------------------------------------------------------- 35 | // Trace 36 | //------------------------------------------------------------- 37 | virtual void add_trace(sc_trace_file *vcd, std::string prefix) 38 | { 39 | #undef TRACE_SIGNAL 40 | #define TRACE_SIGNAL(s) sc_trace(vcd,s,prefix + #s) 41 | 42 | TRACE_SIGNAL(clk_in); 43 | TRACE_SIGNAL(rst_in); 44 | TRACE_SIGNAL(rst_cpu_in); 45 | TRACE_SIGNAL(intr_in); 46 | TRACE_SIGNAL(axi_i_in); 47 | TRACE_SIGNAL(axi_i_out); 48 | TRACE_SIGNAL(axi_t_in); 49 | TRACE_SIGNAL(axi_t_out); 50 | 51 | #undef TRACE_SIGNAL 52 | } 53 | 54 | void async_outputs(void); 55 | void trace_rtl(void); 56 | void trace_enable(VerilatedVcdC *p); 57 | void trace_enable(VerilatedVcdC *p, sc_core::sc_time start_time); 58 | 59 | //------------------------------------------------------------- 60 | // Signals 61 | //------------------------------------------------------------- 62 | private: 63 | sc_signal m_clk_in; 64 | sc_signal m_rst_in; 65 | sc_signal m_rst_cpu_in; 66 | sc_signal m_axi_i_awready_in; 67 | sc_signal m_axi_i_wready_in; 68 | sc_signal m_axi_i_bvalid_in; 69 | sc_signal > m_axi_i_bresp_in; 70 | sc_signal m_axi_i_arready_in; 71 | sc_signal m_axi_i_rvalid_in; 72 | sc_signal > m_axi_i_rdata_in; 73 | sc_signal > m_axi_i_rresp_in; 74 | sc_signal m_axi_t_awvalid_in; 75 | sc_signal > m_axi_t_awaddr_in; 76 | sc_signal > m_axi_t_awid_in; 77 | sc_signal > m_axi_t_awlen_in; 78 | sc_signal > m_axi_t_awburst_in; 79 | sc_signal m_axi_t_wvalid_in; 80 | sc_signal > m_axi_t_wdata_in; 81 | sc_signal > m_axi_t_wstrb_in; 82 | sc_signal m_axi_t_wlast_in; 83 | sc_signal m_axi_t_bready_in; 84 | sc_signal m_axi_t_arvalid_in; 85 | sc_signal > m_axi_t_araddr_in; 86 | sc_signal > m_axi_t_arid_in; 87 | sc_signal > m_axi_t_arlen_in; 88 | sc_signal > m_axi_t_arburst_in; 89 | sc_signal m_axi_t_rready_in; 90 | sc_signal > m_intr_in; 91 | 92 | sc_signal m_axi_i_awvalid_out; 93 | sc_signal > m_axi_i_awaddr_out; 94 | sc_signal m_axi_i_wvalid_out; 95 | sc_signal > m_axi_i_wdata_out; 96 | sc_signal > m_axi_i_wstrb_out; 97 | sc_signal m_axi_i_bready_out; 98 | sc_signal m_axi_i_arvalid_out; 99 | sc_signal > m_axi_i_araddr_out; 100 | sc_signal m_axi_i_rready_out; 101 | sc_signal m_axi_t_awready_out; 102 | sc_signal m_axi_t_wready_out; 103 | sc_signal m_axi_t_bvalid_out; 104 | sc_signal > m_axi_t_bresp_out; 105 | sc_signal > m_axi_t_bid_out; 106 | sc_signal m_axi_t_arready_out; 107 | sc_signal m_axi_t_rvalid_out; 108 | sc_signal > m_axi_t_rdata_out; 109 | sc_signal > m_axi_t_rresp_out; 110 | sc_signal > m_axi_t_rid_out; 111 | sc_signal m_axi_t_rlast_out; 112 | 113 | public: 114 | Vriscv_tcm_top *m_rtl; 115 | #if VM_TRACE 116 | VerilatedVcdC * m_vcd; 117 | bool m_delay_waves; 118 | sc_core::sc_time m_waves_start; 119 | #endif 120 | }; 121 | 122 | #endif -------------------------------------------------------------------------------- /docs/integration.md: -------------------------------------------------------------------------------- 1 | ## Integration Guide 2 | 3 | ### Core: riscv_tcm_top - CPU + Tightly Coupled Memory 4 | 5 | The top (src/top/riscv_tcm_top.v) contains; 6 | * biRISC-V CPU instance. 7 | * 64KB dual ported RAM for (I/D code and data). 8 | * AXI4 slave port for loading the RAM, DMA access, etc (including support for burst access). 9 | * AXI4-Lite master port for CPU access to peripherals / external memory. 10 | * Separate reset for CPU core to dual ported RAM / AXI interface (to allow program code to be loaded prior to CPU reset de-assertion). 11 | 12 | #### Interfaces 13 | 14 | | Name | Description | 15 | | ------------ | --------------------------------------------------------------------- | 16 | | clk_i | Clock input | 17 | | rst_i | Async reset, active-high. Reset memory / AXI interface. | 18 | | rst_cpu_i | Async reset, active-high. Reset CPU core (excluding AXI / memory). | 19 | | axi_t_* | AXI4 slave interface for access to 64KB TCM memory. | 20 | | axi_i_* | AXI4-Lite master interface for CPU access to peripherals. | 21 | | intr_i | Active high interrupt input (for connection external int controller). | 22 | 23 | #### Configuration 24 | 25 | | Param Name | Description | 26 | | ------------------------- | ----------------------------------------------| 27 | | BOOT_VECTOR | Location of first instruction to execute. | 28 | | TCM_MEM_BASE | Base address of TCM memory. | 29 | | CORE_ID | CPU instance ID (MHARTID). | 30 | | SUPPORT_REGFILE_XILINX | Support Xilinx optimised register file. | 31 | 32 | #### FPGA: Xilinx 33 | * Set SUPPORT_REGFILE_XILINX = 1 to use Xilinx specific register file cells which reduce LUT/FF usage. 34 | * Nothing to do for TCM RAM inference. 35 | 36 | #### FPGA: Altera / Intel 37 | * Set SUPPORT_REGFILE_XILINX = 0 to infer a flop based register file. 38 | * You may need to adjust the TCM RAM inference coding style (src/tcm/tcm_mem_ram.v) - or it may just work.... 39 | 40 | #### ASIC 41 | * Set SUPPORT_REGFILE_XILINX = 0 to infer a flop based register file. 42 | * Replace dual ported TCM RAM (8191x64 with byte write enables) with technology specific cells (src/tcm/tcm_mem_ram.v). 43 | 44 | 45 | ### Core: riscv_top - CPU with instruction and data caches 46 | 47 | The top (src/top/riscv_top.v) contains; 48 | * biRISC-V CPU instance. 49 | * 16KB 2-way set associative instruction cache 50 | * 16KB 2-way set associative data cache with write-back and allocate on write. 51 | * 2 x AXI4 master port for CPU access to instruction / data / peripherals. 52 | 53 | #### Interfaces 54 | 55 | | Name | Description | 56 | | -------------- | --------------------------------------------------------------------- | 57 | | clk_i | Clock input | 58 | | rst_i | Async reset, active-high. Reset memory / AXI interface. | 59 | | axi_i_* | AXI4 master interface for CPU access to instruction memory. | 60 | | axi_d_* | AXI4 master interface for CPU access to data / peripheral memories. | 61 | | intr_i | Active high interrupt input (for connection external int controller). | 62 | | reset_vector_i | Boot vector. | 63 | 64 | #### Configuration 65 | 66 | | Param Name | Description | 67 | | ------------------------- | ----------------------------------------------| 68 | | ICACHE_AXI_ID | AXI ID to use for instruction cache accesses. | 69 | | DCACHE_AXI_ID | AXI ID to use for data cache accesses. | 70 | | TCM_MEM_BASE | Base address of TCM memory. | 71 | | CORE_ID | CPU instance ID (MHARTID). | 72 | | SUPPORT_REGFILE_XILINX | Support Xilinx optimised register file. | 73 | 74 | #### FPGA: Xilinx 75 | * Set SUPPORT_REGFILE_XILINX = 1 to use Xilinx specific register file cells which reduce LUT/FF usage. 76 | * Nothing to do for cache RAM inference. 77 | 78 | #### FPGA: Altera / Intel 79 | * Set SUPPORT_REGFILE_XILINX = 0 to infer a flop based register file. 80 | * You may need to adjust the cache RAM inference coding style or it may just work.... 81 | 82 | #### ASIC 83 | * Set SUPPORT_REGFILE_XILINX = 0 to infer a flop based register file. 84 | * Replace cache RAMS (src/dcache/dcache_core_*ram.v, src/icache/icache_*_ram.v) 85 | -------------------------------------------------------------------------------- /tb/tb_tcm/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sc_reset_gen.h" 2 | #include "testbench.h" 3 | #include 4 | #include 5 | #include 6 | 7 | //-------------------------------------------------------------------- 8 | // Defines 9 | //-------------------------------------------------------------------- 10 | #ifndef SIM_TIME_RESOLUTION 11 | #define SIM_TIME_RESOLUTION 1 12 | #endif 13 | #ifndef SIM_TIME_SCALE 14 | #define SIM_TIME_SCALE SC_NS 15 | #endif 16 | 17 | #ifndef CLK0_PERIOD 18 | #define CLK0_PERIOD 10 19 | #endif 20 | 21 | #ifndef CLK0_NAME 22 | #define CLK0_NAME clk 23 | #endif 24 | 25 | #ifndef RST0_NAME 26 | #define RST0_NAME rst 27 | #endif 28 | 29 | #define xstr(a) str(a) 30 | #define str(a) #a 31 | 32 | //-------------------------------------------------------------------- 33 | // Locals 34 | //-------------------------------------------------------------------- 35 | static testbench *tb = NULL; 36 | 37 | //-------------------------------------------------------------------- 38 | // assert_handler: Handling of sc_assert 39 | //-------------------------------------------------------------------- 40 | static void assert_handler(const sc_report& rep, const sc_actions& actions) 41 | { 42 | sc_report_handler::default_handler(rep, actions & ~SC_ABORT); 43 | 44 | if ( actions & SC_ABORT ) 45 | { 46 | cout << "TEST FAILED" << endl; 47 | if (tb) 48 | tb->abort(); 49 | abort(); 50 | } 51 | } 52 | //-------------------------------------------------------------------- 53 | // exit_override 54 | //-------------------------------------------------------------------- 55 | static void exit_override(void) 56 | { 57 | if (tb) 58 | tb->abort(); 59 | } 60 | //-------------------------------------------------------------------- 61 | // vl_finish: Handling of verilog $finish 62 | //-------------------------------------------------------------------- 63 | void vl_finish (const char* filename, int linenum, const char* hier) 64 | { 65 | // Jump to exit handler! 66 | exit(0); 67 | } 68 | //----------------------------------------------------------------- 69 | // sigint_handler 70 | //----------------------------------------------------------------- 71 | static void sigint_handler(int s) 72 | { 73 | exit_override(); 74 | 75 | // Jump to exit handler! 76 | exit(1); 77 | } 78 | //-------------------------------------------------------------------- 79 | // sc_main 80 | //-------------------------------------------------------------------- 81 | int sc_main(int argc, char* argv[]) 82 | { 83 | bool trace = true; 84 | int seed = 1; 85 | int last_argc = 0; 86 | const char * vcd_name = "sysc_wave"; 87 | 88 | // Env variable seed override 89 | char *s = getenv("SEED"); 90 | if (s && strcmp(s, "")) 91 | seed = strtol(s, NULL, 0); 92 | 93 | for (int i=1;iCLK0_NAME(CLK0_NAME); 145 | tb->RST0_NAME(clk0_rst.rst); 146 | 147 | // Waves 148 | if (trace) 149 | tb->add_trace(sc_create_vcd_trace_file(vcd_name), ""); 150 | 151 | tb->set_argcv(argc - last_argc, &argv[last_argc]); 152 | 153 | // Go! 154 | sc_start(); 155 | 156 | return 0; 157 | } 158 | -------------------------------------------------------------------------------- /tb/tb_top/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sc_reset_gen.h" 2 | #include "testbench.h" 3 | #include 4 | #include 5 | #include 6 | 7 | //-------------------------------------------------------------------- 8 | // Defines 9 | //-------------------------------------------------------------------- 10 | #ifndef SIM_TIME_RESOLUTION 11 | #define SIM_TIME_RESOLUTION 1 12 | #endif 13 | #ifndef SIM_TIME_SCALE 14 | #define SIM_TIME_SCALE SC_NS 15 | #endif 16 | 17 | #ifndef CLK0_PERIOD 18 | #define CLK0_PERIOD 10 19 | #endif 20 | 21 | #ifndef CLK0_NAME 22 | #define CLK0_NAME clk 23 | #endif 24 | 25 | #ifndef RST0_NAME 26 | #define RST0_NAME rst 27 | #endif 28 | 29 | #define xstr(a) str(a) 30 | #define str(a) #a 31 | 32 | //-------------------------------------------------------------------- 33 | // Locals 34 | //-------------------------------------------------------------------- 35 | static testbench *tb = NULL; 36 | 37 | //-------------------------------------------------------------------- 38 | // assert_handler: Handling of sc_assert 39 | //-------------------------------------------------------------------- 40 | static void assert_handler(const sc_report& rep, const sc_actions& actions) 41 | { 42 | sc_report_handler::default_handler(rep, actions & ~SC_ABORT); 43 | 44 | if ( actions & SC_ABORT ) 45 | { 46 | cout << "TEST FAILED" << endl; 47 | if (tb) 48 | tb->abort(); 49 | abort(); 50 | } 51 | } 52 | //-------------------------------------------------------------------- 53 | // exit_override 54 | //-------------------------------------------------------------------- 55 | static void exit_override(void) 56 | { 57 | if (tb) 58 | tb->abort(); 59 | } 60 | //-------------------------------------------------------------------- 61 | // vl_finish: Handling of verilog $finish 62 | //-------------------------------------------------------------------- 63 | void vl_finish (const char* filename, int linenum, const char* hier) 64 | { 65 | // Jump to exit handler! 66 | exit(0); 67 | } 68 | //----------------------------------------------------------------- 69 | // sigint_handler 70 | //----------------------------------------------------------------- 71 | static void sigint_handler(int s) 72 | { 73 | exit_override(); 74 | 75 | // Jump to exit handler! 76 | exit(1); 77 | } 78 | //-------------------------------------------------------------------- 79 | // sc_main 80 | //-------------------------------------------------------------------- 81 | int sc_main(int argc, char* argv[]) 82 | { 83 | bool trace = true; 84 | int seed = 1; 85 | int last_argc = 0; 86 | const char * vcd_name = "sysc_wave"; 87 | 88 | // Env variable seed override 89 | char *s = getenv("SEED"); 90 | if (s && strcmp(s, "")) 91 | seed = strtol(s, NULL, 0); 92 | 93 | for (int i=1;iCLK0_NAME(CLK0_NAME); 145 | tb->RST0_NAME(clk0_rst.rst); 146 | 147 | // Waves 148 | if (trace) 149 | tb->add_trace(sc_create_vcd_trace_file(vcd_name), ""); 150 | 151 | tb->set_argcv(argc - last_argc, &argv[last_argc]); 152 | 153 | // Go! 154 | sc_start(); 155 | 156 | return 0; 157 | } 158 | -------------------------------------------------------------------------------- /tb/tb_top/riscv_top.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef RISCV_TOP_H 3 | #define RISCV_TOP_H 4 | #include 5 | 6 | #include "axi4.h" 7 | #include "axi4.h" 8 | 9 | class Vriscv_top; 10 | class VerilatedVcdC; 11 | 12 | //------------------------------------------------------------- 13 | // riscv_top: RTL wrapper class 14 | //------------------------------------------------------------- 15 | class riscv_top: public sc_module 16 | { 17 | public: 18 | sc_in clk_in; 19 | sc_in rst_in; 20 | sc_in intr_in; 21 | sc_in > reset_vector_in; 22 | 23 | sc_in axi_i_in; 24 | sc_out axi_i_out; 25 | sc_in axi_d_in; 26 | sc_out axi_d_out; 27 | 28 | //------------------------------------------------------------- 29 | // Constructor 30 | //------------------------------------------------------------- 31 | SC_HAS_PROCESS(riscv_top); 32 | riscv_top(sc_module_name name); 33 | 34 | //------------------------------------------------------------- 35 | // Trace 36 | //------------------------------------------------------------- 37 | virtual void add_trace(sc_trace_file *vcd, std::string prefix) 38 | { 39 | #undef TRACE_SIGNAL 40 | #define TRACE_SIGNAL(s) sc_trace(vcd,s,prefix + #s) 41 | 42 | TRACE_SIGNAL(clk_in); 43 | TRACE_SIGNAL(rst_in); 44 | TRACE_SIGNAL(intr_in); 45 | TRACE_SIGNAL(reset_vector_in); 46 | TRACE_SIGNAL(axi_i_in); 47 | TRACE_SIGNAL(axi_i_out); 48 | TRACE_SIGNAL(axi_d_in); 49 | TRACE_SIGNAL(axi_d_out); 50 | 51 | #undef TRACE_SIGNAL 52 | } 53 | 54 | void async_outputs(void); 55 | void trace_rtl(void); 56 | void trace_enable(VerilatedVcdC *p); 57 | void trace_enable(VerilatedVcdC *p, sc_core::sc_time start_time); 58 | 59 | //------------------------------------------------------------- 60 | // Signals 61 | //------------------------------------------------------------- 62 | private: 63 | sc_signal m_clk_in; 64 | sc_signal m_rst_in; 65 | sc_signal m_axi_i_awready_in; 66 | sc_signal m_axi_i_wready_in; 67 | sc_signal m_axi_i_bvalid_in; 68 | sc_signal > m_axi_i_bresp_in; 69 | sc_signal > m_axi_i_bid_in; 70 | sc_signal m_axi_i_arready_in; 71 | sc_signal m_axi_i_rvalid_in; 72 | sc_signal > m_axi_i_rdata_in; 73 | sc_signal > m_axi_i_rresp_in; 74 | sc_signal > m_axi_i_rid_in; 75 | sc_signal m_axi_i_rlast_in; 76 | sc_signal m_axi_d_awready_in; 77 | sc_signal m_axi_d_wready_in; 78 | sc_signal m_axi_d_bvalid_in; 79 | sc_signal > m_axi_d_bresp_in; 80 | sc_signal > m_axi_d_bid_in; 81 | sc_signal m_axi_d_arready_in; 82 | sc_signal m_axi_d_rvalid_in; 83 | sc_signal > m_axi_d_rdata_in; 84 | sc_signal > m_axi_d_rresp_in; 85 | sc_signal > m_axi_d_rid_in; 86 | sc_signal m_axi_d_rlast_in; 87 | sc_signal m_intr_in; 88 | sc_signal > m_reset_vector_in; 89 | 90 | sc_signal m_axi_i_awvalid_out; 91 | sc_signal > m_axi_i_awaddr_out; 92 | sc_signal > m_axi_i_awid_out; 93 | sc_signal > m_axi_i_awlen_out; 94 | sc_signal > m_axi_i_awburst_out; 95 | sc_signal m_axi_i_wvalid_out; 96 | sc_signal > m_axi_i_wdata_out; 97 | sc_signal > m_axi_i_wstrb_out; 98 | sc_signal m_axi_i_wlast_out; 99 | sc_signal m_axi_i_bready_out; 100 | sc_signal m_axi_i_arvalid_out; 101 | sc_signal > m_axi_i_araddr_out; 102 | sc_signal > m_axi_i_arid_out; 103 | sc_signal > m_axi_i_arlen_out; 104 | sc_signal > m_axi_i_arburst_out; 105 | sc_signal m_axi_i_rready_out; 106 | sc_signal m_axi_d_awvalid_out; 107 | sc_signal > m_axi_d_awaddr_out; 108 | sc_signal > m_axi_d_awid_out; 109 | sc_signal > m_axi_d_awlen_out; 110 | sc_signal > m_axi_d_awburst_out; 111 | sc_signal m_axi_d_wvalid_out; 112 | sc_signal > m_axi_d_wdata_out; 113 | sc_signal > m_axi_d_wstrb_out; 114 | sc_signal m_axi_d_wlast_out; 115 | sc_signal m_axi_d_bready_out; 116 | sc_signal m_axi_d_arvalid_out; 117 | sc_signal > m_axi_d_araddr_out; 118 | sc_signal > m_axi_d_arid_out; 119 | sc_signal > m_axi_d_arlen_out; 120 | sc_signal > m_axi_d_arburst_out; 121 | sc_signal m_axi_d_rready_out; 122 | 123 | public: 124 | Vriscv_top *m_rtl; 125 | #if VM_TRACE 126 | VerilatedVcdC * m_vcd; 127 | bool m_delay_waves; 128 | sc_core::sc_time m_waves_start; 129 | #endif 130 | }; 131 | 132 | #endif -------------------------------------------------------------------------------- /src/core/biriscv_multiplier.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.8.1 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module biriscv_multiplier 27 | ( 28 | // Inputs 29 | input clk_i 30 | ,input rst_i 31 | ,input opcode_valid_i 32 | ,input [ 31:0] opcode_opcode_i 33 | ,input [ 31:0] opcode_pc_i 34 | ,input opcode_invalid_i 35 | ,input [ 4:0] opcode_rd_idx_i 36 | ,input [ 4:0] opcode_ra_idx_i 37 | ,input [ 4:0] opcode_rb_idx_i 38 | ,input [ 31:0] opcode_ra_operand_i 39 | ,input [ 31:0] opcode_rb_operand_i 40 | ,input hold_i 41 | 42 | // Outputs 43 | ,output [ 31:0] writeback_value_o 44 | ); 45 | 46 | 47 | 48 | //----------------------------------------------------------------- 49 | // Includes 50 | //----------------------------------------------------------------- 51 | `include "biriscv_defs.v" 52 | 53 | localparam MULT_STAGES = 2; // 2 or 3 54 | 55 | //------------------------------------------------------------- 56 | // Registers / Wires 57 | //------------------------------------------------------------- 58 | reg [31:0] result_e2_q; 59 | reg [31:0] result_e3_q; 60 | 61 | reg [32:0] operand_a_e1_q; 62 | reg [32:0] operand_b_e1_q; 63 | reg mulhi_sel_e1_q; 64 | 65 | //------------------------------------------------------------- 66 | // Multiplier 67 | //------------------------------------------------------------- 68 | wire [64:0] mult_result_w; 69 | reg [32:0] operand_b_r; 70 | reg [32:0] operand_a_r; 71 | reg [31:0] result_r; 72 | 73 | wire mult_inst_w = ((opcode_opcode_i & `INST_MUL_MASK) == `INST_MUL) || 74 | ((opcode_opcode_i & `INST_MULH_MASK) == `INST_MULH) || 75 | ((opcode_opcode_i & `INST_MULHSU_MASK) == `INST_MULHSU) || 76 | ((opcode_opcode_i & `INST_MULHU_MASK) == `INST_MULHU); 77 | 78 | 79 | always @ * 80 | begin 81 | if ((opcode_opcode_i & `INST_MULHSU_MASK) == `INST_MULHSU) 82 | operand_a_r = {opcode_ra_operand_i[31], opcode_ra_operand_i[31:0]}; 83 | else if ((opcode_opcode_i & `INST_MULH_MASK) == `INST_MULH) 84 | operand_a_r = {opcode_ra_operand_i[31], opcode_ra_operand_i[31:0]}; 85 | else // MULHU || MUL 86 | operand_a_r = {1'b0, opcode_ra_operand_i[31:0]}; 87 | end 88 | 89 | always @ * 90 | begin 91 | if ((opcode_opcode_i & `INST_MULHSU_MASK) == `INST_MULHSU) 92 | operand_b_r = {1'b0, opcode_rb_operand_i[31:0]}; 93 | else if ((opcode_opcode_i & `INST_MULH_MASK) == `INST_MULH) 94 | operand_b_r = {opcode_rb_operand_i[31], opcode_rb_operand_i[31:0]}; 95 | else // MULHU || MUL 96 | operand_b_r = {1'b0, opcode_rb_operand_i[31:0]}; 97 | end 98 | 99 | 100 | // Pipeline flops for multiplier 101 | always @(posedge clk_i or posedge rst_i) 102 | if (rst_i) 103 | begin 104 | operand_a_e1_q <= 33'b0; 105 | operand_b_e1_q <= 33'b0; 106 | mulhi_sel_e1_q <= 1'b0; 107 | end 108 | else if (hold_i) 109 | ; 110 | else if (opcode_valid_i && mult_inst_w) 111 | begin 112 | operand_a_e1_q <= operand_a_r; 113 | operand_b_e1_q <= operand_b_r; 114 | mulhi_sel_e1_q <= ~((opcode_opcode_i & `INST_MUL_MASK) == `INST_MUL); 115 | end 116 | else 117 | begin 118 | operand_a_e1_q <= 33'b0; 119 | operand_b_e1_q <= 33'b0; 120 | mulhi_sel_e1_q <= 1'b0; 121 | end 122 | 123 | assign mult_result_w = {{ 32 {operand_a_e1_q[32]}}, operand_a_e1_q}*{{ 32 {operand_b_e1_q[32]}}, operand_b_e1_q}; 124 | 125 | always @ * 126 | begin 127 | result_r = mulhi_sel_e1_q ? mult_result_w[63:32] : mult_result_w[31:0]; 128 | end 129 | 130 | always @(posedge clk_i or posedge rst_i) 131 | if (rst_i) 132 | result_e2_q <= 32'b0; 133 | else if (~hold_i) 134 | result_e2_q <= result_r; 135 | 136 | always @(posedge clk_i or posedge rst_i) 137 | if (rst_i) 138 | result_e3_q <= 32'b0; 139 | else if (~hold_i) 140 | result_e3_q <= result_e2_q; 141 | 142 | assign writeback_value_o = (MULT_STAGES == 3) ? result_e3_q : result_e2_q; 143 | 144 | 145 | endmodule 146 | -------------------------------------------------------------------------------- /src/core/biriscv_xilinx_2r1w.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.8.1 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | //----------------------------------------------------------------- 26 | // Module - Xilinx register file (2 async read, 1 write port) 27 | //----------------------------------------------------------------- 28 | module biriscv_xilinx_2r1w 29 | ( 30 | // Inputs 31 | input clk_i 32 | ,input rst_i 33 | ,input [ 4:0] rd0_i 34 | ,input [ 31:0] rd0_value_i 35 | ,input [ 4:0] ra_i 36 | ,input [ 4:0] rb_i 37 | 38 | // Outputs 39 | ,output [ 31:0] ra_value_o 40 | ,output [ 31:0] rb_value_o 41 | ); 42 | 43 | 44 | //----------------------------------------------------------------- 45 | // Registers / Wires 46 | //----------------------------------------------------------------- 47 | wire [31:0] reg_rs1_w; 48 | wire [31:0] reg_rs2_w; 49 | wire [31:0] rs1_0_15_w; 50 | wire [31:0] rs1_16_31_w; 51 | wire [31:0] rs2_0_15_w; 52 | wire [31:0] rs2_16_31_w; 53 | wire write_enable_w; 54 | wire write_banka_w; 55 | wire write_bankb_w; 56 | 57 | //----------------------------------------------------------------- 58 | // Register File (using RAM16X1D ) 59 | //----------------------------------------------------------------- 60 | genvar i; 61 | 62 | // Registers 0 - 15 63 | generate 64 | for (i=0;i<32;i=i+1) 65 | begin : reg_loop1 66 | RAM16X1D reg_bit1a(.WCLK(clk_i), .WE(write_banka_w), .A0(rd0_i[0]), .A1(rd0_i[1]), .A2(rd0_i[2]), .A3(rd0_i[3]), .D(rd0_value_i[i]), .DPRA0(ra_i[0]), .DPRA1(ra_i[1]), .DPRA2(ra_i[2]), .DPRA3(ra_i[3]), .DPO(rs1_0_15_w[i]), .SPO(/* open */)); 67 | RAM16X1D reg_bit2a(.WCLK(clk_i), .WE(write_banka_w), .A0(rd0_i[0]), .A1(rd0_i[1]), .A2(rd0_i[2]), .A3(rd0_i[3]), .D(rd0_value_i[i]), .DPRA0(rb_i[0]), .DPRA1(rb_i[1]), .DPRA2(rb_i[2]), .DPRA3(rb_i[3]), .DPO(rs2_0_15_w[i]), .SPO(/* open */)); 68 | end 69 | endgenerate 70 | 71 | // Registers 16 - 31 72 | generate 73 | for (i=0;i<32;i=i+1) 74 | begin : reg_loop2 75 | RAM16X1D reg_bit1b(.WCLK(clk_i), .WE(write_bankb_w), .A0(rd0_i[0]), .A1(rd0_i[1]), .A2(rd0_i[2]), .A3(rd0_i[3]), .D(rd0_value_i[i]), .DPRA0(ra_i[0]), .DPRA1(ra_i[1]), .DPRA2(ra_i[2]), .DPRA3(ra_i[3]), .DPO(rs1_16_31_w[i]), .SPO(/* open */)); 76 | RAM16X1D reg_bit2b(.WCLK(clk_i), .WE(write_bankb_w), .A0(rd0_i[0]), .A1(rd0_i[1]), .A2(rd0_i[2]), .A3(rd0_i[3]), .D(rd0_value_i[i]), .DPRA0(rb_i[0]), .DPRA1(rb_i[1]), .DPRA2(rb_i[2]), .DPRA3(rb_i[3]), .DPO(rs2_16_31_w[i]), .SPO(/* open */)); 77 | end 78 | endgenerate 79 | 80 | //----------------------------------------------------------------- 81 | // Combinatorial Assignments 82 | //----------------------------------------------------------------- 83 | assign reg_rs1_w = (ra_i[4] == 1'b0) ? rs1_0_15_w : rs1_16_31_w; 84 | assign reg_rs2_w = (rb_i[4] == 1'b0) ? rs2_0_15_w : rs2_16_31_w; 85 | 86 | assign write_enable_w = (rd0_i != 5'b00000); 87 | 88 | assign write_banka_w = (write_enable_w & (~rd0_i[4])); 89 | assign write_bankb_w = (write_enable_w & rd0_i[4]); 90 | 91 | reg [31:0] ra_value_r; 92 | reg [31:0] rb_value_r; 93 | 94 | // Register read ports 95 | always @ * 96 | begin 97 | if (ra_i == 5'b00000) 98 | ra_value_r = 32'h00000000; 99 | else 100 | ra_value_r = reg_rs1_w; 101 | 102 | if (rb_i == 5'b00000) 103 | rb_value_r = 32'h00000000; 104 | else 105 | rb_value_r = reg_rs2_w; 106 | end 107 | 108 | assign ra_value_o = ra_value_r; 109 | assign rb_value_o = rb_value_r; 110 | 111 | endmodule 112 | 113 | //------------------------------------------------------------- 114 | // RAM16X1D: Verilator target RAM16X1D model 115 | //------------------------------------------------------------- 116 | `ifdef verilator 117 | module RAM16X1D (DPO, SPO, A0, A1, A2, A3, D, DPRA0, DPRA1, DPRA2, DPRA3, WCLK, WE); 118 | 119 | parameter INIT = 16'h0000; 120 | 121 | output DPO, SPO; 122 | 123 | input A0, A1, A2, A3, D, DPRA0, DPRA1, DPRA2, DPRA3, WCLK, WE; 124 | 125 | reg [15:0] mem; 126 | wire [3:0] adr; 127 | 128 | assign adr = {A3, A2, A1, A0}; 129 | assign SPO = mem[adr]; 130 | assign DPO = mem[{DPRA3, DPRA2, DPRA1, DPRA0}]; 131 | 132 | initial 133 | mem = INIT; 134 | 135 | always @(posedge WCLK) 136 | if (WE == 1'b1) 137 | mem[adr] <= D; 138 | 139 | endmodule 140 | `endif 141 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | ## Core Configuration 2 | 3 | #### Static Configuration Parameters 4 | 5 | | Param Name | Valid Range | Description | 6 | | ------------------------- |:--------------------:| ----------------------------------------------| 7 | | SUPPORT_SUPER | 1/0 | Enable supervisor / user privilege levels. | 8 | | SUPPORT_MMU | 1/0 | Enable basic memory management unit. | 9 | | SUPPORT_MULDIV | 1/0 | Enable HW multiply / divide (RV-M). | 10 | | SUPPORT_DUAL_ISSUE | 1/0 | Support superscalar operation. | 11 | | SUPPORT_LOAD_BYPASS | 1/0 | Support load result bypass paths. | 12 | | SUPPORT_MUL_BYPASS | 1/0 | Support multiply result bypass paths. | 13 | | SUPPORT_REGFILE_XILINX | 1/0 | Support Xilinx optimised register file. | 14 | | SUPPORT_BRANCH_PREDICTION | 1/0 | Enable branch prediction structures. | 15 | | NUM_BTB_ENTRIES | 2 - | Number of branch target buffer entries. | 16 | | NUM_BTB_ENTRIES_W | 1 - | Set to log2(NUM_BTB_ENTRIES). | 17 | | NUM_BHT_ENTRIES | 2 - | Number of branch history table entries. | 18 | | NUM_BHT_ENTRIES_W | 1 - | Set to log2(NUM_BHT_ENTRIES_W). | 19 | | BHT_ENABLE | 1/0 | Enable branch history table based prediction. | 20 | | GSHARE_ENABLE | 1/0 | Enable GSHARE branch prediction algorithm. | 21 | | RAS_ENABLE | 1/0 | Enable return address stack prediction. | 22 | | NUM_RAS_ENTRIES | 2 - | Number of return stack addresses supported. | 23 | | NUM_RAS_ENTRIES_W | 1 - | Set to log2(NUM_RAS_ENTRIES_W). | 24 | | EXTRA_DECODE_STAGE | 1/0 | Extra decode pipe stage for improved timing. | 25 | | MEM_CACHE_ADDR_MIN | 32'h0 - 32'hffffffff | Lowest cacheable memory address. | 26 | | MEM_CACHE_ADDR_MAX | 32'h0 - 32'hffffffff | Highest cacheable memory address. | 27 | 28 | 29 | #### Configuration: Default 30 | ``` 31 | .SUPPORT_BRANCH_PREDICTION(1) 32 | ,.SUPPORT_MULDIV(1) 33 | ,.SUPPORT_SUPER(0) 34 | ,.SUPPORT_MMU(0) 35 | ,.SUPPORT_DUAL_ISSUE(1) 36 | ,.SUPPORT_LOAD_BYPASS(1) 37 | ,.SUPPORT_MUL_BYPASS(1) 38 | ,.SUPPORT_REGFILE_XILINX(0) 39 | ,.EXTRA_DECODE_STAGE(0) 40 | ,.MEM_CACHE_ADDR_MIN(32'h80000000) 41 | ,.MEM_CACHE_ADDR_MAX(32'h8fffffff) 42 | ,.NUM_BTB_ENTRIES(32) 43 | ,.NUM_BTB_ENTRIES_W(5) 44 | ,.NUM_BHT_ENTRIES(512) 45 | ,.NUM_BHT_ENTRIES_W(9) 46 | ,.RAS_ENABLE(1) 47 | ,.GSHARE_ENABLE(0) 48 | ,.BHT_ENABLE(1) 49 | ,.NUM_RAS_ENTRIES(8) 50 | ,.NUM_RAS_ENTRIES_W(3) 51 | ``` 52 | 53 | #### Configuration: Minimal Area (RV32I) 54 | ``` 55 | .SUPPORT_BRANCH_PREDICTION(0) 56 | ,.SUPPORT_MULDIV(0) 57 | ,.SUPPORT_SUPER(0) 58 | ,.SUPPORT_MMU(0) 59 | ,.SUPPORT_DUAL_ISSUE(0) 60 | ,.SUPPORT_LOAD_BYPASS(0) 61 | ,.SUPPORT_MUL_BYPASS(0) 62 | ,.SUPPORT_REGFILE_XILINX(0) // Set to 1 if building for Xilinx FPGAs 63 | ,.EXTRA_DECODE_STAGE(0) 64 | ,.MEM_CACHE_ADDR_MIN(32'h80000000) 65 | ,.MEM_CACHE_ADDR_MAX(32'h8fffffff) 66 | ``` 67 | 68 | #### Configuration: Minimal Area (RV32IM) 69 | ``` 70 | .SUPPORT_BRANCH_PREDICTION(0) 71 | ,.SUPPORT_MULDIV(1) 72 | ,.SUPPORT_SUPER(0) 73 | ,.SUPPORT_MMU(0) 74 | ,.SUPPORT_DUAL_ISSUE(0) 75 | ,.SUPPORT_LOAD_BYPASS(0) 76 | ,.SUPPORT_MUL_BYPASS(0) 77 | ,.SUPPORT_REGFILE_XILINX(0) // Set to 1 if building for Xilinx FPGAs 78 | ,.EXTRA_DECODE_STAGE(0) 79 | ,.MEM_CACHE_ADDR_MIN(32'h80000000) 80 | ,.MEM_CACHE_ADDR_MAX(32'h8fffffff) 81 | ``` 82 | 83 | #### Configuration: Linux Capable 84 | ``` 85 | .SUPPORT_BRANCH_PREDICTION(1) 86 | ,.SUPPORT_MULDIV(1) 87 | ,.SUPPORT_SUPER(1) 88 | ,.SUPPORT_MMU(1) 89 | ,.SUPPORT_DUAL_ISSUE(1) 90 | ,.SUPPORT_LOAD_BYPASS(1) 91 | ,.SUPPORT_MUL_BYPASS(1) 92 | ,.SUPPORT_REGFILE_XILINX(0) // Set to 1 if building for Xilinx FPGAs 93 | ,.EXTRA_DECODE_STAGE(1) 94 | ,.MEM_CACHE_ADDR_MIN(32'h80000000) 95 | ,.MEM_CACHE_ADDR_MAX(32'h8fffffff) 96 | ,.NUM_BTB_ENTRIES(32) 97 | ,.NUM_BTB_ENTRIES_W(5) 98 | ,.NUM_BHT_ENTRIES(512) 99 | ,.NUM_BHT_ENTRIES_W(9) 100 | ,.RAS_ENABLE(1) 101 | ,.GSHARE_ENABLE(0) 102 | ,.BHT_ENABLE(1) 103 | ,.NUM_RAS_ENTRIES(8) 104 | ,.NUM_RAS_ENTRIES_W(3) 105 | ``` 106 | 107 | #### Configuration: High FMAX 108 | ``` 109 | .SUPPORT_BRANCH_PREDICTION(1) // Set to 0 for even higher FMAX but much worse IPC 110 | ,.SUPPORT_MULDIV(1) 111 | ,.SUPPORT_SUPER(0) 112 | ,.SUPPORT_MMU(0) 113 | ,.SUPPORT_DUAL_ISSUE(0) 114 | ,.SUPPORT_LOAD_BYPASS(0) 115 | ,.SUPPORT_MUL_BYPASS(0) 116 | ,.SUPPORT_REGFILE_XILINX(0) // Set to 1 if building for Xilinx FPGAs 117 | ,.EXTRA_DECODE_STAGE(1) 118 | ,.MEM_CACHE_ADDR_MIN(32'h80000000) 119 | ,.MEM_CACHE_ADDR_MAX(32'h8fffffff) 120 | ,.NUM_BTB_ENTRIES(16) 121 | ,.NUM_BTB_ENTRIES_W(4) 122 | ,.NUM_BHT_ENTRIES(256) 123 | ,.NUM_BHT_ENTRIES_W(8) 124 | ,.RAS_ENABLE(1) 125 | ,.GSHARE_ENABLE(0) 126 | ,.BHT_ENABLE(1) 127 | ,.NUM_RAS_ENTRIES(8) 128 | ,.NUM_RAS_ENTRIES_W(3) 129 | ``` 130 | -------------------------------------------------------------------------------- /src/dcache/dcache_mux.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module dcache_mux 27 | ( 28 | // Inputs 29 | input clk_i 30 | ,input rst_i 31 | ,input [ 31:0] mem_addr_i 32 | ,input [ 31:0] mem_data_wr_i 33 | ,input mem_rd_i 34 | ,input [ 3:0] mem_wr_i 35 | ,input mem_cacheable_i 36 | ,input [ 10:0] mem_req_tag_i 37 | ,input mem_invalidate_i 38 | ,input mem_writeback_i 39 | ,input mem_flush_i 40 | ,input [ 31:0] mem_cached_data_rd_i 41 | ,input mem_cached_accept_i 42 | ,input mem_cached_ack_i 43 | ,input mem_cached_error_i 44 | ,input [ 10:0] mem_cached_resp_tag_i 45 | ,input [ 31:0] mem_uncached_data_rd_i 46 | ,input mem_uncached_accept_i 47 | ,input mem_uncached_ack_i 48 | ,input mem_uncached_error_i 49 | ,input [ 10:0] mem_uncached_resp_tag_i 50 | 51 | // Outputs 52 | ,output [ 31:0] mem_data_rd_o 53 | ,output mem_accept_o 54 | ,output mem_ack_o 55 | ,output mem_error_o 56 | ,output [ 10:0] mem_resp_tag_o 57 | ,output [ 31:0] mem_cached_addr_o 58 | ,output [ 31:0] mem_cached_data_wr_o 59 | ,output mem_cached_rd_o 60 | ,output [ 3:0] mem_cached_wr_o 61 | ,output mem_cached_cacheable_o 62 | ,output [ 10:0] mem_cached_req_tag_o 63 | ,output mem_cached_invalidate_o 64 | ,output mem_cached_writeback_o 65 | ,output mem_cached_flush_o 66 | ,output [ 31:0] mem_uncached_addr_o 67 | ,output [ 31:0] mem_uncached_data_wr_o 68 | ,output mem_uncached_rd_o 69 | ,output [ 3:0] mem_uncached_wr_o 70 | ,output mem_uncached_cacheable_o 71 | ,output [ 10:0] mem_uncached_req_tag_o 72 | ,output mem_uncached_invalidate_o 73 | ,output mem_uncached_writeback_o 74 | ,output mem_uncached_flush_o 75 | ,output cache_active_o 76 | ); 77 | 78 | 79 | 80 | wire hold_w; 81 | reg cache_access_q; 82 | 83 | assign mem_cached_addr_o = mem_addr_i; 84 | assign mem_cached_data_wr_o = mem_data_wr_i; 85 | assign mem_cached_rd_o = (mem_cacheable_i & ~hold_w) ? mem_rd_i : 1'b0; 86 | assign mem_cached_wr_o = (mem_cacheable_i & ~hold_w) ? mem_wr_i : 4'b0; 87 | assign mem_cached_cacheable_o = mem_cacheable_i; 88 | assign mem_cached_req_tag_o = mem_req_tag_i; 89 | assign mem_cached_invalidate_o = (mem_cacheable_i & ~hold_w) ? mem_invalidate_i : 1'b0; 90 | assign mem_cached_writeback_o = (mem_cacheable_i & ~hold_w) ? mem_writeback_i : 1'b0; 91 | assign mem_cached_flush_o = (mem_cacheable_i & ~hold_w) ? mem_flush_i : 1'b0; 92 | 93 | assign mem_uncached_addr_o = mem_addr_i; 94 | assign mem_uncached_data_wr_o = mem_data_wr_i; 95 | assign mem_uncached_rd_o = (~mem_cacheable_i & ~hold_w) ? mem_rd_i : 1'b0; 96 | assign mem_uncached_wr_o = (~mem_cacheable_i & ~hold_w) ? mem_wr_i : 4'b0; 97 | assign mem_uncached_cacheable_o = mem_cacheable_i; 98 | assign mem_uncached_req_tag_o = mem_req_tag_i; 99 | assign mem_uncached_invalidate_o = (~mem_cacheable_i & ~hold_w) ? mem_invalidate_i : 1'b0; 100 | assign mem_uncached_writeback_o = (~mem_cacheable_i & ~hold_w) ? mem_writeback_i : 1'b0; 101 | assign mem_uncached_flush_o = (~mem_cacheable_i & ~hold_w) ? mem_flush_i : 1'b0; 102 | 103 | assign mem_accept_o =(mem_cacheable_i ? mem_cached_accept_i : mem_uncached_accept_i) & !hold_w; 104 | assign mem_data_rd_o = cache_access_q ? mem_cached_data_rd_i : mem_uncached_data_rd_i; 105 | assign mem_ack_o = cache_access_q ? mem_cached_ack_i : mem_uncached_ack_i; 106 | assign mem_error_o = cache_access_q ? mem_cached_error_i : mem_uncached_error_i; 107 | assign mem_resp_tag_o = cache_access_q ? mem_cached_resp_tag_i : mem_uncached_resp_tag_i; 108 | 109 | wire request_w = mem_rd_i | mem_wr_i != 4'b0 | mem_flush_i | mem_invalidate_i | mem_writeback_i; 110 | 111 | reg [4:0] pending_r; 112 | reg [4:0] pending_q; 113 | always @ * 114 | begin 115 | pending_r = pending_q; 116 | 117 | if ((request_w && mem_accept_o) && !mem_ack_o) 118 | pending_r = pending_r + 5'd1; 119 | else if (!(request_w && mem_accept_o) && mem_ack_o) 120 | pending_r = pending_r - 5'd1; 121 | end 122 | 123 | always @ (posedge clk_i or posedge rst_i) 124 | if (rst_i) 125 | pending_q <= 5'b0; 126 | else 127 | pending_q <= pending_r; 128 | 129 | always @ (posedge clk_i or posedge rst_i) 130 | if (rst_i) 131 | cache_access_q <= 1'b0; 132 | else if (request_w && mem_accept_o) 133 | cache_access_q <= mem_cacheable_i; 134 | 135 | assign hold_w = (|pending_q) && (cache_access_q != mem_cacheable_i); 136 | 137 | assign cache_active_o = (|pending_q) ? cache_access_q : mem_cacheable_i; 138 | 139 | 140 | endmodule 141 | -------------------------------------------------------------------------------- /tb/tb_tcm/axi4_lite.h: -------------------------------------------------------------------------------- 1 | #ifndef AXI4_LITE_H 2 | #define AXI4_LITE_H 3 | 4 | #include 5 | 6 | //---------------------------------------------------------------- 7 | // Interface (master) 8 | //---------------------------------------------------------------- 9 | class axi4_lite_master 10 | { 11 | public: 12 | // Members 13 | sc_uint <1> AWVALID; 14 | sc_uint <32> AWADDR; 15 | sc_uint <1> WVALID; 16 | sc_uint <32> WDATA; 17 | sc_uint <4> WSTRB; 18 | sc_uint <1> BREADY; 19 | sc_uint <1> ARVALID; 20 | sc_uint <32> ARADDR; 21 | sc_uint <1> RREADY; 22 | 23 | // Construction 24 | axi4_lite_master() { init(); } 25 | 26 | void init(void) 27 | { 28 | AWVALID = 0; 29 | AWADDR = 0; 30 | WVALID = 0; 31 | WDATA = 0; 32 | WSTRB = 0; 33 | BREADY = 0; 34 | ARVALID = 0; 35 | ARADDR = 0; 36 | RREADY = 0; 37 | } 38 | 39 | bool operator == (const axi4_lite_master & v) const 40 | { 41 | bool eq = true; 42 | eq &= (AWVALID == v.AWVALID); 43 | eq &= (AWADDR == v.AWADDR); 44 | eq &= (WVALID == v.WVALID); 45 | eq &= (WDATA == v.WDATA); 46 | eq &= (WSTRB == v.WSTRB); 47 | eq &= (BREADY == v.BREADY); 48 | eq &= (ARVALID == v.ARVALID); 49 | eq &= (ARADDR == v.ARADDR); 50 | eq &= (RREADY == v.RREADY); 51 | return eq; 52 | } 53 | 54 | friend void sc_trace(sc_trace_file *tf, const axi4_lite_master & v, const std::string & path) 55 | { 56 | sc_trace(tf,v.AWVALID, path + "/awvalid"); 57 | sc_trace(tf,v.AWADDR, path + "/awaddr"); 58 | sc_trace(tf,v.WVALID, path + "/wvalid"); 59 | sc_trace(tf,v.WDATA, path + "/wdata"); 60 | sc_trace(tf,v.WSTRB, path + "/wstrb"); 61 | sc_trace(tf,v.BREADY, path + "/bready"); 62 | sc_trace(tf,v.ARVALID, path + "/arvalid"); 63 | sc_trace(tf,v.ARADDR, path + "/araddr"); 64 | sc_trace(tf,v.RREADY, path + "/rready"); 65 | } 66 | 67 | friend ostream& operator << (ostream& os, axi4_lite_master const & v) 68 | { 69 | os << hex << "AWVALID: " << v.AWVALID << " "; 70 | os << hex << "AWADDR: " << v.AWADDR << " "; 71 | os << hex << "WVALID: " << v.WVALID << " "; 72 | os << hex << "WDATA: " << v.WDATA << " "; 73 | os << hex << "WSTRB: " << v.WSTRB << " "; 74 | os << hex << "BREADY: " << v.BREADY << " "; 75 | os << hex << "ARVALID: " << v.ARVALID << " "; 76 | os << hex << "ARADDR: " << v.ARADDR << " "; 77 | os << hex << "RREADY: " << v.RREADY << " "; 78 | return os; 79 | } 80 | 81 | friend istream& operator >> ( istream& is, axi4_lite_master & val) 82 | { 83 | // Not implemented 84 | return is; 85 | } 86 | }; 87 | 88 | #define MEMBER_COPY_AXI4_LITE_MASTER(s,d) do { \ 89 | s.AWVALID = d.AWVALID; \ 90 | s.AWADDR = d.AWADDR; \ 91 | s.WVALID = d.WVALID; \ 92 | s.WDATA = d.WDATA; \ 93 | s.WSTRB = d.WSTRB; \ 94 | s.BREADY = d.BREADY; \ 95 | s.ARVALID = d.ARVALID; \ 96 | s.ARADDR = d.ARADDR; \ 97 | s.RREADY = d.RREADY; \ 98 | } while (0) 99 | 100 | //---------------------------------------------------------------- 101 | // Interface (slave) 102 | //---------------------------------------------------------------- 103 | class axi4_lite_slave 104 | { 105 | public: 106 | // Members 107 | sc_uint <1> AWREADY; 108 | sc_uint <1> WREADY; 109 | sc_uint <1> BVALID; 110 | sc_uint <2> BRESP; 111 | sc_uint <1> ARREADY; 112 | sc_uint <1> RVALID; 113 | sc_uint <32> RDATA; 114 | sc_uint <2> RRESP; 115 | 116 | // Construction 117 | axi4_lite_slave() { init(); } 118 | 119 | void init(void) 120 | { 121 | AWREADY = 0; 122 | WREADY = 0; 123 | BVALID = 0; 124 | BRESP = 0; 125 | ARREADY = 0; 126 | RVALID = 0; 127 | RDATA = 0; 128 | RRESP = 0; 129 | } 130 | 131 | bool operator == (const axi4_lite_slave & v) const 132 | { 133 | bool eq = true; 134 | eq &= (AWREADY == v.AWREADY); 135 | eq &= (WREADY == v.WREADY); 136 | eq &= (BVALID == v.BVALID); 137 | eq &= (BRESP == v.BRESP); 138 | eq &= (ARREADY == v.ARREADY); 139 | eq &= (RVALID == v.RVALID); 140 | eq &= (RDATA == v.RDATA); 141 | eq &= (RRESP == v.RRESP); 142 | return eq; 143 | } 144 | 145 | friend void sc_trace(sc_trace_file *tf, const axi4_lite_slave & v, const std::string & path) 146 | { 147 | sc_trace(tf,v.AWREADY, path + "/awready"); 148 | sc_trace(tf,v.WREADY, path + "/wready"); 149 | sc_trace(tf,v.BVALID, path + "/bvalid"); 150 | sc_trace(tf,v.BRESP, path + "/bresp"); 151 | sc_trace(tf,v.ARREADY, path + "/arready"); 152 | sc_trace(tf,v.RVALID, path + "/rvalid"); 153 | sc_trace(tf,v.RDATA, path + "/rdata"); 154 | sc_trace(tf,v.RRESP, path + "/rresp"); 155 | } 156 | 157 | friend ostream& operator << (ostream& os, axi4_lite_slave const & v) 158 | { 159 | os << hex << "AWREADY: " << v.AWREADY << " "; 160 | os << hex << "WREADY: " << v.WREADY << " "; 161 | os << hex << "BVALID: " << v.BVALID << " "; 162 | os << hex << "BRESP: " << v.BRESP << " "; 163 | os << hex << "ARREADY: " << v.ARREADY << " "; 164 | os << hex << "RVALID: " << v.RVALID << " "; 165 | os << hex << "RDATA: " << v.RDATA << " "; 166 | os << hex << "RRESP: " << v.RRESP << " "; 167 | return os; 168 | } 169 | 170 | friend istream& operator >> ( istream& is, axi4_lite_slave & val) 171 | { 172 | // Not implemented 173 | return is; 174 | } 175 | }; 176 | 177 | #define MEMBER_COPY_AXI4_LITE_SLAVE(s,d) do { \ 178 | s.AWREADY = d.AWREADY; \ 179 | s.WREADY = d.WREADY; \ 180 | s.BVALID = d.BVALID; \ 181 | s.BRESP = d.BRESP; \ 182 | s.ARREADY = d.ARREADY; \ 183 | s.RVALID = d.RVALID; \ 184 | s.RDATA = d.RDATA; \ 185 | s.RRESP = d.RRESP; \ 186 | } while (0) 187 | 188 | 189 | #endif 190 | -------------------------------------------------------------------------------- /tb/tb_top/tb_memory.h: -------------------------------------------------------------------------------- 1 | #ifndef TB_MEMORY_H 2 | #define TB_MEMORY_H 3 | 4 | #include 5 | #include 6 | 7 | #define TB_MEM_MAX_REGIONS 10 8 | 9 | //----------------------------------------------------------------- 10 | // tb_mem_region: Memory region entity 11 | //----------------------------------------------------------------- 12 | class tb_mem_region 13 | { 14 | public: 15 | tb_mem_region(uint32_t base, uint32_t size, uint8_t *pMem = NULL) 16 | { 17 | m_base = base; 18 | m_size = size; 19 | m_mem = pMem ? pMem : new uint8_t[size]; 20 | m_trace = false; 21 | } 22 | 23 | uint32_t get_base(void) { return m_base; } 24 | uint32_t get_size(void) { return m_size; } 25 | 26 | bool match(uint32_t addr) 27 | { 28 | return (addr >= m_base) && (addr < (m_base + m_size)); 29 | } 30 | 31 | void write(uint32_t addr, uint8_t data) 32 | { 33 | if (match(addr)) 34 | { 35 | if (m_trace) printf("WRITE: %08x=%02x\n", addr, data); 36 | m_mem[addr - m_base] = data; 37 | } 38 | } 39 | 40 | uint8_t read(uint32_t addr) 41 | { 42 | if (match(addr)) 43 | { 44 | if (m_trace) printf("READ: %08x=%02x\n", addr, m_mem[addr - m_base]); 45 | return m_mem[addr - m_base]; 46 | } 47 | else 48 | return 0; 49 | } 50 | 51 | uint8_t *get_array(void) { return m_mem; } 52 | void trace_access(bool en) { m_trace = en; } 53 | 54 | protected: 55 | uint32_t m_base; 56 | uint32_t m_size; 57 | 58 | uint8_t * m_mem; 59 | 60 | bool m_trace; 61 | }; 62 | 63 | //----------------------------------------------------------------- 64 | // tb_mem_record: Transaction detail 65 | //----------------------------------------------------------------- 66 | class tb_mem_record 67 | { 68 | public: 69 | tb_mem_record(bool write, uint32_t addr, uint8_t data) 70 | { 71 | m_time = sc_time_stamp(); 72 | m_is_write = write; 73 | m_addr = addr; 74 | m_data = data; 75 | } 76 | 77 | public: 78 | sc_time m_time; 79 | bool m_is_write; 80 | uint32_t m_addr; 81 | uint8_t m_data; 82 | }; 83 | 84 | //----------------------------------------------------------------- 85 | // tb_memory: Memory base class 86 | //----------------------------------------------------------------- 87 | class tb_memory 88 | { 89 | public: 90 | tb_memory() 91 | { 92 | for (int i=0;imatch(base) || m_mem[i]->match(base + size - 1)) 108 | return false; 109 | return false; 110 | } 111 | 112 | bool add_region(uint8_t *mem, uint32_t base, uint32_t size) 113 | { 114 | for (int i=0;imatch(base) || m_mem[i]->match(base + size - 1)) 122 | return false; 123 | return false; 124 | } 125 | 126 | bool valid_addr(uint32_t addr) 127 | { 128 | for (int i=0;imatch(addr)) 130 | return true; 131 | 132 | return false; 133 | } 134 | 135 | void trace_access(uint32_t addr, bool en) 136 | { 137 | for (int i=0;imatch(addr)) 139 | m_mem[i]->trace_access(en); 140 | } 141 | 142 | void write(uint32_t addr, uint8_t data) 143 | { 144 | bool found = false; 145 | 146 | if (m_record_accesses) 147 | m_accesses.push(tb_mem_record(true, addr, data)); 148 | 149 | for (int i=0;imatch(addr)) 151 | { 152 | m_mem[i]->write(addr, data); 153 | found = true; 154 | } 155 | 156 | if (!found) 157 | { 158 | printf("ERROR: Write out of range 0x%08x\n", addr); 159 | sc_assert(0); 160 | } 161 | } 162 | 163 | uint8_t read(uint32_t addr) 164 | { 165 | for (int i=0;imatch(addr)) 167 | { 168 | uint8_t data = m_mem[i]->read(addr); 169 | if (m_record_accesses) 170 | m_accesses.push(tb_mem_record(false, addr, data)); 171 | return data; 172 | } 173 | 174 | printf("ERROR: Read out of range 0x%08x\n", addr); 175 | sc_assert(0); 176 | return 0; 177 | } 178 | 179 | uint8_t* get_array(uint32_t addr) 180 | { 181 | for (int i=0;imatch(addr)) 183 | return m_mem[i]->get_array(); 184 | 185 | printf("ERROR: Access out of range 0x%08x\n", addr); 186 | sc_assert(0); 187 | return NULL; 188 | } 189 | 190 | void records_enable(bool enable) { m_record_accesses = enable; } 191 | bool records_available(void) { return m_accesses.size() != 0; } 192 | tb_mem_record records_pop(void) { tb_mem_record v = m_accesses.front(); m_accesses.pop(); return v; } 193 | 194 | protected: 195 | tb_mem_region * m_mem[TB_MEM_MAX_REGIONS]; 196 | bool m_record_accesses; 197 | std::queue m_accesses; 198 | }; 199 | 200 | #endif -------------------------------------------------------------------------------- /tb/tb_tcm/elf_load.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "elf_load.h" 12 | 13 | //-------------------------------------------------------------------- 14 | // Constructor 15 | //-------------------------------------------------------------------- 16 | elf_load::elf_load(const char *filename, mem_api *target) 17 | { 18 | m_filename = std::string(filename); 19 | m_target = target; 20 | m_entry_point = 0; 21 | } 22 | //-------------------------------------------------------------------- 23 | // load: Load ELF to target 24 | //-------------------------------------------------------------------- 25 | bool elf_load::load(void) 26 | { 27 | int fd; 28 | Elf * e; 29 | Elf_Kind ek; 30 | Elf_Scn *scn; 31 | Elf_Data *data; 32 | size_t shstrndx; 33 | 34 | if (elf_version ( EV_CURRENT ) == EV_NONE) 35 | return false; 36 | 37 | if ((fd = open ( m_filename.c_str() , O_RDONLY , 0)) < 0) 38 | return false; 39 | 40 | if ((e = elf_begin ( fd , ELF_C_READ, NULL )) == NULL) 41 | return false; 42 | 43 | ek = elf_kind ( e ); 44 | if (ek != ELF_K_ELF) 45 | return false; 46 | 47 | // Get section name header index 48 | if (elf_getshdrstrndx(e, &shstrndx)!=0) 49 | return false; 50 | 51 | // Get entry point 52 | { 53 | GElf_Ehdr _ehdr; 54 | GElf_Ehdr *ehdr = gelf_getehdr(e, &_ehdr); 55 | m_entry_point = ehdr ? (uint32_t)ehdr->e_entry : 0; 56 | } 57 | 58 | int section_idx = 0; 59 | while ((scn = elf_getscn(e, section_idx)) != NULL) 60 | { 61 | Elf32_Shdr *shdr = elf32_getshdr(scn); 62 | 63 | // 64-bit target 64 | if (!shdr) 65 | { 66 | Elf64_Shdr *shdr64 = elf64_getshdr(scn); 67 | 68 | if ((shdr64->sh_flags & SHF_ALLOC) && (shdr64->sh_size > 0)) 69 | { 70 | data = elf_getdata(scn, NULL); 71 | 72 | printf("Memory: 0x%lx - 0x%lx (Size=%ldKB) [%s]\n", shdr64->sh_addr, shdr64->sh_addr + shdr64->sh_size - 1, shdr64->sh_size / 1024, elf_strptr(e, shstrndx, shdr64->sh_name)); 73 | 74 | if (!m_target->create_memory(shdr64->sh_addr, shdr64->sh_size)) 75 | { 76 | fprintf(stderr, "ERROR: Cannot allocate memory region\n"); 77 | close (fd); 78 | return false; 79 | } 80 | 81 | if (shdr64->sh_type == SHT_PROGBITS) 82 | { 83 | int i; 84 | for (i=0;ish_size;i++) 85 | { 86 | uint32_t load_addr = shdr64->sh_addr + i; 87 | if (m_target->valid_addr(load_addr)) 88 | m_target->write(load_addr, ((uint8_t*)data->d_buf)[i]); 89 | else 90 | { 91 | fprintf(stderr, "ERROR: Cannot write byte to 0x%08x\n", load_addr); 92 | close (fd); 93 | return false; 94 | } 95 | } 96 | } 97 | } 98 | } 99 | // 32-bit target - section which need allocating 100 | else if ((shdr->sh_flags & SHF_ALLOC) && (shdr->sh_size > 0)) 101 | { 102 | data = elf_getdata(scn, NULL); 103 | 104 | printf("Memory: 0x%x - 0x%x (Size=%dKB) [%s]\n", shdr->sh_addr, shdr->sh_addr + shdr->sh_size - 1, shdr->sh_size / 1024, elf_strptr(e, shstrndx, shdr->sh_name)); 105 | 106 | if (!m_target->create_memory(shdr->sh_addr, shdr->sh_size)) 107 | { 108 | fprintf(stderr, "ERROR: Cannot allocate memory region\n"); 109 | close (fd); 110 | return false; 111 | } 112 | 113 | if (shdr->sh_type == SHT_PROGBITS) 114 | { 115 | int i; 116 | for (i=0;ish_size;i++) 117 | { 118 | uint32_t load_addr = shdr->sh_addr + i; 119 | if (m_target->valid_addr(load_addr)) 120 | m_target->write(load_addr, ((uint8_t*)data->d_buf)[i]); 121 | else 122 | { 123 | fprintf(stderr, "ERROR: Cannot write byte to 0x%08x\n", load_addr); 124 | close (fd); 125 | return false; 126 | } 127 | } 128 | } 129 | } 130 | 131 | section_idx++; 132 | } 133 | 134 | elf_end ( e ); 135 | close ( fd ); 136 | 137 | return true; 138 | } 139 | //-------------------------------------------------------------------- 140 | // get_symbol: Get symbol from ELF 141 | //-------------------------------------------------------------------- 142 | bool elf_load::get_symbol(const char *symname, uint32_t &value) 143 | { 144 | bfd *ibfd; 145 | asymbol **symtab; 146 | long nsize, nsyms, i; 147 | symbol_info syminfo; 148 | char **matching; 149 | 150 | bfd_init(); 151 | 152 | ibfd = bfd_openr(m_filename.c_str(), NULL); 153 | if (ibfd == NULL) 154 | { 155 | printf("ERROR: get_symbol: bfd_openr error\n"); 156 | return false; 157 | } 158 | 159 | if (!bfd_check_format_matches(ibfd, bfd_object, &matching)) 160 | { 161 | printf("ERROR: get_symbol: format_matches\n"); 162 | return false; 163 | } 164 | 165 | nsize = bfd_get_symtab_upper_bound (ibfd); 166 | symtab = (asymbol **)malloc(nsize); 167 | nsyms = bfd_canonicalize_symtab(ibfd, symtab); 168 | 169 | bool found = false; 170 | 171 | for (i = 0; i < nsyms; i++) 172 | { 173 | if (strcmp(symtab[i]->name, symname) == 0) 174 | { 175 | bfd_symbol_info(symtab[i], &syminfo); 176 | value = syminfo.value; 177 | found = true; 178 | break; 179 | } 180 | } 181 | 182 | bfd_close(ibfd); 183 | 184 | return found; 185 | } 186 | -------------------------------------------------------------------------------- /tb/tb_top/elf_load.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "elf_load.h" 12 | 13 | //-------------------------------------------------------------------- 14 | // Constructor 15 | //-------------------------------------------------------------------- 16 | elf_load::elf_load(const char *filename, mem_api *target) 17 | { 18 | m_filename = std::string(filename); 19 | m_target = target; 20 | m_entry_point = 0; 21 | } 22 | //-------------------------------------------------------------------- 23 | // load: Load ELF to target 24 | //-------------------------------------------------------------------- 25 | bool elf_load::load(void) 26 | { 27 | int fd; 28 | Elf * e; 29 | Elf_Kind ek; 30 | Elf_Scn *scn; 31 | Elf_Data *data; 32 | size_t shstrndx; 33 | 34 | if (elf_version ( EV_CURRENT ) == EV_NONE) 35 | return false; 36 | 37 | if ((fd = open ( m_filename.c_str() , O_RDONLY , 0)) < 0) 38 | return false; 39 | 40 | if ((e = elf_begin ( fd , ELF_C_READ, NULL )) == NULL) 41 | return false; 42 | 43 | ek = elf_kind ( e ); 44 | if (ek != ELF_K_ELF) 45 | return false; 46 | 47 | // Get section name header index 48 | if (elf_getshdrstrndx(e, &shstrndx)!=0) 49 | return false; 50 | 51 | // Get entry point 52 | { 53 | GElf_Ehdr _ehdr; 54 | GElf_Ehdr *ehdr = gelf_getehdr(e, &_ehdr); 55 | m_entry_point = ehdr ? (uint32_t)ehdr->e_entry : 0; 56 | } 57 | 58 | int section_idx = 0; 59 | while ((scn = elf_getscn(e, section_idx)) != NULL) 60 | { 61 | Elf32_Shdr *shdr = elf32_getshdr(scn); 62 | 63 | // 64-bit target 64 | if (!shdr) 65 | { 66 | Elf64_Shdr *shdr64 = elf64_getshdr(scn); 67 | 68 | if ((shdr64->sh_flags & SHF_ALLOC) && (shdr64->sh_size > 0)) 69 | { 70 | data = elf_getdata(scn, NULL); 71 | 72 | printf("Memory: 0x%lx - 0x%lx (Size=%ldKB) [%s]\n", shdr64->sh_addr, shdr64->sh_addr + shdr64->sh_size - 1, shdr64->sh_size / 1024, elf_strptr(e, shstrndx, shdr64->sh_name)); 73 | 74 | if (!m_target->create_memory(shdr64->sh_addr, shdr64->sh_size)) 75 | { 76 | fprintf(stderr, "ERROR: Cannot allocate memory region\n"); 77 | close (fd); 78 | return false; 79 | } 80 | 81 | if (shdr64->sh_type == SHT_PROGBITS) 82 | { 83 | int i; 84 | for (i=0;ish_size;i++) 85 | { 86 | uint32_t load_addr = shdr64->sh_addr + i; 87 | if (m_target->valid_addr(load_addr)) 88 | m_target->write(load_addr, ((uint8_t*)data->d_buf)[i]); 89 | else 90 | { 91 | fprintf(stderr, "ERROR: Cannot write byte to 0x%08x\n", load_addr); 92 | close (fd); 93 | return false; 94 | } 95 | } 96 | } 97 | } 98 | } 99 | // 32-bit target - section which need allocating 100 | else if ((shdr->sh_flags & SHF_ALLOC) && (shdr->sh_size > 0)) 101 | { 102 | data = elf_getdata(scn, NULL); 103 | 104 | printf("Memory: 0x%x - 0x%x (Size=%dKB) [%s]\n", shdr->sh_addr, shdr->sh_addr + shdr->sh_size - 1, shdr->sh_size / 1024, elf_strptr(e, shstrndx, shdr->sh_name)); 105 | 106 | if (!m_target->create_memory(shdr->sh_addr, shdr->sh_size)) 107 | { 108 | fprintf(stderr, "ERROR: Cannot allocate memory region\n"); 109 | close (fd); 110 | return false; 111 | } 112 | 113 | if (shdr->sh_type == SHT_PROGBITS) 114 | { 115 | int i; 116 | for (i=0;ish_size;i++) 117 | { 118 | uint32_t load_addr = shdr->sh_addr + i; 119 | if (m_target->valid_addr(load_addr)) 120 | m_target->write(load_addr, ((uint8_t*)data->d_buf)[i]); 121 | else 122 | { 123 | fprintf(stderr, "ERROR: Cannot write byte to 0x%08x\n", load_addr); 124 | close (fd); 125 | return false; 126 | } 127 | } 128 | } 129 | } 130 | 131 | section_idx++; 132 | } 133 | 134 | elf_end ( e ); 135 | close ( fd ); 136 | 137 | return true; 138 | } 139 | //-------------------------------------------------------------------- 140 | // get_symbol: Get symbol from ELF 141 | //-------------------------------------------------------------------- 142 | bool elf_load::get_symbol(const char *symname, uint32_t &value) 143 | { 144 | bfd *ibfd; 145 | asymbol **symtab; 146 | long nsize, nsyms, i; 147 | symbol_info syminfo; 148 | char **matching; 149 | 150 | bfd_init(); 151 | 152 | ibfd = bfd_openr(m_filename.c_str(), NULL); 153 | if (ibfd == NULL) 154 | { 155 | printf("ERROR: get_symbol: bfd_openr error\n"); 156 | return false; 157 | } 158 | 159 | if (!bfd_check_format_matches(ibfd, bfd_object, &matching)) 160 | { 161 | printf("ERROR: get_symbol: format_matches\n"); 162 | return false; 163 | } 164 | 165 | nsize = bfd_get_symtab_upper_bound (ibfd); 166 | symtab = (asymbol **)malloc(nsize); 167 | nsyms = bfd_canonicalize_symtab(ibfd, symtab); 168 | 169 | bool found = false; 170 | 171 | for (i = 0; i < nsyms; i++) 172 | { 173 | if (strcmp(symtab[i]->name, symname) == 0) 174 | { 175 | bfd_symbol_info(symtab[i], &syminfo); 176 | value = syminfo.value; 177 | found = true; 178 | break; 179 | } 180 | } 181 | 182 | bfd_close(ibfd); 183 | 184 | return found; 185 | } 186 | -------------------------------------------------------------------------------- /src/tcm/dport_mux.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module dport_mux 27 | //----------------------------------------------------------------- 28 | // Params 29 | //----------------------------------------------------------------- 30 | #( 31 | parameter TCM_MEM_BASE = 0 32 | ) 33 | //----------------------------------------------------------------- 34 | // Ports 35 | //----------------------------------------------------------------- 36 | ( 37 | // Inputs 38 | input clk_i 39 | ,input rst_i 40 | ,input [ 31:0] mem_addr_i 41 | ,input [ 31:0] mem_data_wr_i 42 | ,input mem_rd_i 43 | ,input [ 3:0] mem_wr_i 44 | ,input mem_cacheable_i 45 | ,input [ 10:0] mem_req_tag_i 46 | ,input mem_invalidate_i 47 | ,input mem_writeback_i 48 | ,input mem_flush_i 49 | ,input [ 31:0] mem_tcm_data_rd_i 50 | ,input mem_tcm_accept_i 51 | ,input mem_tcm_ack_i 52 | ,input mem_tcm_error_i 53 | ,input [ 10:0] mem_tcm_resp_tag_i 54 | ,input [ 31:0] mem_ext_data_rd_i 55 | ,input mem_ext_accept_i 56 | ,input mem_ext_ack_i 57 | ,input mem_ext_error_i 58 | ,input [ 10:0] mem_ext_resp_tag_i 59 | 60 | // Outputs 61 | ,output [ 31:0] mem_data_rd_o 62 | ,output mem_accept_o 63 | ,output mem_ack_o 64 | ,output mem_error_o 65 | ,output [ 10:0] mem_resp_tag_o 66 | ,output [ 31:0] mem_tcm_addr_o 67 | ,output [ 31:0] mem_tcm_data_wr_o 68 | ,output mem_tcm_rd_o 69 | ,output [ 3:0] mem_tcm_wr_o 70 | ,output mem_tcm_cacheable_o 71 | ,output [ 10:0] mem_tcm_req_tag_o 72 | ,output mem_tcm_invalidate_o 73 | ,output mem_tcm_writeback_o 74 | ,output mem_tcm_flush_o 75 | ,output [ 31:0] mem_ext_addr_o 76 | ,output [ 31:0] mem_ext_data_wr_o 77 | ,output mem_ext_rd_o 78 | ,output [ 3:0] mem_ext_wr_o 79 | ,output mem_ext_cacheable_o 80 | ,output [ 10:0] mem_ext_req_tag_o 81 | ,output mem_ext_invalidate_o 82 | ,output mem_ext_writeback_o 83 | ,output mem_ext_flush_o 84 | ); 85 | 86 | 87 | 88 | //----------------------------------------------------------------- 89 | // Dcache_if mux 90 | //----------------------------------------------------------------- 91 | wire hold_w; 92 | 93 | /* verilator lint_off UNSIGNED */ 94 | wire tcm_access_w = (mem_addr_i >= TCM_MEM_BASE && mem_addr_i < (TCM_MEM_BASE + 32'd65536)); 95 | /* verilator lint_on UNSIGNED */ 96 | 97 | reg tcm_access_q; 98 | reg [4:0] pending_q; 99 | 100 | assign mem_tcm_addr_o = mem_addr_i; 101 | assign mem_tcm_data_wr_o = mem_data_wr_i; 102 | assign mem_tcm_rd_o = (tcm_access_w & ~hold_w) ? mem_rd_i : 1'b0; 103 | assign mem_tcm_wr_o = (tcm_access_w & ~hold_w) ? mem_wr_i : 4'b0; 104 | assign mem_tcm_cacheable_o = mem_cacheable_i; 105 | assign mem_tcm_req_tag_o = mem_req_tag_i; 106 | assign mem_tcm_invalidate_o = (tcm_access_w & ~hold_w) ? mem_invalidate_i : 1'b0; 107 | assign mem_tcm_writeback_o = (tcm_access_w & ~hold_w) ? mem_writeback_i : 1'b0; 108 | assign mem_tcm_flush_o = (tcm_access_w & ~hold_w) ? mem_flush_i : 1'b0; 109 | 110 | assign mem_ext_addr_o = mem_addr_i; 111 | assign mem_ext_data_wr_o = mem_data_wr_i; 112 | assign mem_ext_rd_o = (~tcm_access_w & ~hold_w) ? mem_rd_i : 1'b0; 113 | assign mem_ext_wr_o = (~tcm_access_w & ~hold_w) ? mem_wr_i : 4'b0; 114 | assign mem_ext_cacheable_o = mem_cacheable_i; 115 | assign mem_ext_req_tag_o = mem_req_tag_i; 116 | assign mem_ext_invalidate_o = (~tcm_access_w & ~hold_w) ? mem_invalidate_i : 1'b0; 117 | assign mem_ext_writeback_o = (~tcm_access_w & ~hold_w) ? mem_writeback_i : 1'b0; 118 | assign mem_ext_flush_o = (~tcm_access_w & ~hold_w) ? mem_flush_i : 1'b0; 119 | 120 | assign mem_accept_o =(tcm_access_w ? mem_tcm_accept_i : mem_ext_accept_i) & !hold_w; 121 | assign mem_data_rd_o = tcm_access_q ? mem_tcm_data_rd_i : mem_ext_data_rd_i; 122 | assign mem_ack_o = tcm_access_q ? mem_tcm_ack_i : mem_ext_ack_i; 123 | assign mem_error_o = tcm_access_q ? mem_tcm_error_i : mem_ext_error_i; 124 | assign mem_resp_tag_o = tcm_access_q ? mem_tcm_resp_tag_i : mem_ext_resp_tag_i; 125 | 126 | wire request_w = mem_rd_i || mem_wr_i != 4'b0 || mem_flush_i || mem_invalidate_i || mem_writeback_i; 127 | 128 | reg [4:0] pending_r; 129 | always @ * 130 | begin 131 | pending_r = pending_q; 132 | 133 | if ((request_w && mem_accept_o) && !mem_ack_o) 134 | pending_r = pending_r + 5'd1; 135 | else if (!(request_w && mem_accept_o) && mem_ack_o) 136 | pending_r = pending_r - 5'd1; 137 | end 138 | 139 | always @ (posedge clk_i or posedge rst_i) 140 | if (rst_i) 141 | pending_q <= 5'b0; 142 | else 143 | pending_q <= pending_r; 144 | 145 | always @ (posedge clk_i or posedge rst_i) 146 | if (rst_i) 147 | tcm_access_q <= 1'b0; 148 | else if (request_w && mem_accept_o) 149 | tcm_access_q <= tcm_access_w; 150 | 151 | assign hold_w = (|pending_q) && (tcm_access_q != tcm_access_w); 152 | 153 | 154 | 155 | endmodule 156 | -------------------------------------------------------------------------------- /tb/tb_top/tb_axi4_mem.cpp: -------------------------------------------------------------------------------- 1 | #include "tb_axi4_mem.h" 2 | #include 3 | 4 | //----------------------------------------------------------------- 5 | // process: Handle AXI requests 6 | //----------------------------------------------------------------- 7 | void tb_axi4_mem::process(void) 8 | { 9 | std::queue axi_rd_q; 10 | std::queue axi_wr_q; 11 | 12 | axi4_master axi_wr_req; 13 | 14 | while (1) 15 | { 16 | axi4_master axi_i = axi_in.read(); 17 | axi4_slave axi_o = axi_out.read(); 18 | 19 | // Read command 20 | if (axi_i.ARVALID && axi_o.ARREADY) 21 | { 22 | sc_uint next_addr = axi_i.ARADDR & ~calc_wrap_mask(0); 23 | axi4_master axi_first = axi_i; 24 | 25 | // Unroll burst 26 | for (int i=0;i<((int)(axi_first.ARLEN) + 1);i++) 27 | { 28 | axi4_master item = axi_first; 29 | 30 | item.ARVALID = true; 31 | item.ARADDR = next_addr; 32 | item.WLAST = (i == axi_first.ARLEN); 33 | 34 | axi_rd_q.push(item); 35 | 36 | // Generate next address 37 | next_addr = calc_next_addr(next_addr, axi_first.ARBURST, axi_first.ARLEN); 38 | } 39 | } 40 | 41 | // Write command 42 | if (axi_i.AWVALID && axi_o.AWREADY) 43 | { 44 | // Record command 45 | axi_wr_req = axi_i; 46 | } 47 | 48 | // Write data 49 | if (axi_i.WVALID && axi_o.WREADY) 50 | { 51 | sc_assert(axi_wr_req.AWVALID); 52 | 53 | axi4_master item = axi_wr_req; 54 | 55 | item.AWVALID = true; 56 | item.AWADDR = axi_wr_req.AWADDR; 57 | 58 | item.WVALID = true; 59 | item.WDATA = axi_i.WDATA; 60 | item.WSTRB = axi_i.WSTRB; 61 | item.WLAST = axi_i.WLAST; 62 | 63 | axi_wr_q.push(item); 64 | 65 | // Generate next address 66 | axi_wr_req.AWADDR = calc_next_addr(axi_wr_req.AWADDR, axi_wr_req.AWBURST, axi_wr_req.AWLEN); 67 | 68 | // Last item 69 | if (item.WLAST) 70 | axi_wr_req.AWVALID = false; 71 | } 72 | 73 | if (axi_o.RVALID && axi_i.RREADY) 74 | { 75 | axi_o.RVALID = false; 76 | axi_o.RDATA = 0; 77 | axi_o.RID = 0; 78 | axi_o.RRESP = 0; 79 | axi_o.RLAST = false; 80 | } 81 | 82 | if (!axi_o.RVALID && axi_rd_q.size() > 0 && !delay_cycle()) 83 | { 84 | axi4_master item = axi_rd_q.front(); 85 | axi_rd_q.pop(); 86 | 87 | axi_o.RVALID = true; 88 | axi_o.RDATA = read32((uint32_t)item.ARADDR); 89 | axi_o.RID = item.ARID; 90 | axi_o.RLAST = item.WLAST; 91 | axi_o.RRESP = AXI4_RESP_OKAY; 92 | } 93 | 94 | if (axi_o.BVALID && axi_i.BREADY) 95 | { 96 | axi_o.BVALID = false; 97 | axi_o.BID = 0; 98 | axi_o.BRESP = 0; 99 | } 100 | 101 | if (!axi_o.BVALID && axi_wr_q.size() > 0 && !delay_cycle()) 102 | { 103 | axi4_master item = axi_wr_q.front(); 104 | axi_wr_q.pop(); 105 | 106 | write32((uint32_t)item.AWADDR, (uint32_t)item.WDATA, (uint8_t)item.WSTRB); 107 | 108 | axi_o.BVALID = item.WLAST; 109 | axi_o.BID = item.AWID; 110 | axi_o.BRESP = AXI4_RESP_OKAY; 111 | } 112 | 113 | // Randomize handshaking 114 | axi_o.ARREADY = !delay_cycle() && (axi_rd_q.size() < 128); 115 | axi_o.AWREADY = !delay_cycle() && (axi_wr_q.size() < 128); 116 | axi_o.WREADY = axi_o.AWREADY && !delay_cycle(); 117 | axi_o.AWREADY&= !axi_wr_req.AWVALID; 118 | 119 | axi_out.write(axi_o); 120 | 121 | wait(); 122 | } 123 | } 124 | //----------------------------------------------------------------- 125 | // calc_next_addr: Calculate next addr based on burst type 126 | //----------------------------------------------------------------- 127 | sc_uint tb_axi4_mem::calc_next_addr(sc_uint addr, sc_uint type, sc_uint len) 128 | { 129 | sc_uint mask = calc_wrap_mask(len); 130 | 131 | switch (type) 132 | { 133 | case AXI4_BURST_WRAP: 134 | return (addr & ~mask) | ((addr + (AXI4_DATA_W/8)) & mask); 135 | case AXI4_BURST_INCR: 136 | return addr + (AXI4_DATA_W/8); 137 | case AXI4_BURST_FIXED: 138 | default: 139 | return addr; 140 | } 141 | 142 | return 0; // Invalid 143 | } 144 | //----------------------------------------------------------------- 145 | // calc_wrap_mask: Calculate wrap mask for wrapping bursts 146 | //----------------------------------------------------------------- 147 | sc_uint tb_axi4_mem::calc_wrap_mask(sc_uint len) 148 | { 149 | switch (len) 150 | { 151 | case (1 - 1): 152 | return 0x03; 153 | case (2 - 1): 154 | return 0x07; 155 | case (4 - 1): 156 | return 0x0F; 157 | case (8 - 1): 158 | return 0x1F; 159 | case (16 - 1): 160 | default: 161 | return 0x3F; 162 | } 163 | 164 | return 0; // Invalid 165 | } 166 | //----------------------------------------------------------------- 167 | // write32: Write a 32-bit word to memory 168 | //----------------------------------------------------------------- 169 | void tb_axi4_mem::write32(uint32_t addr, uint32_t data, uint8_t strb) 170 | { 171 | for (int i=0;i<4;i++) 172 | if (strb & (1 << i)) 173 | tb_memory::write(addr + i,data >> (i*8)); 174 | } 175 | //----------------------------------------------------------------- 176 | // read32: Read a 32-bit word from memory 177 | //----------------------------------------------------------------- 178 | uint32_t tb_axi4_mem::read32(uint32_t addr) 179 | { 180 | uint32_t data = 0; 181 | for (int i=0;i<4;i++) 182 | data |= ((uint32_t)tb_memory::read(addr + i)) << (i*8); 183 | return data; 184 | } 185 | //----------------------------------------------------------------- 186 | // write: Byte write 187 | //----------------------------------------------------------------- 188 | void tb_axi4_mem::write(uint32_t addr, uint8_t data) 189 | { 190 | tb_memory::write(addr, data); 191 | } 192 | //----------------------------------------------------------------- 193 | // read: Byte read 194 | //----------------------------------------------------------------- 195 | uint8_t tb_axi4_mem::read(uint32_t addr) 196 | { 197 | return tb_memory::read(addr); 198 | } 199 | -------------------------------------------------------------------------------- /tb/tb_tcm/testbench.h: -------------------------------------------------------------------------------- 1 | #include "testbench_vbase.h" 2 | #include "elf_load.h" 3 | #include 4 | #include 5 | 6 | #include "riscv_tcm_top_rtl.h" 7 | #include "Vriscv_tcm_top.h" 8 | #include "Vriscv_tcm_top__Syms.h" 9 | 10 | #include "verilated.h" 11 | #include "verilated_vcd_sc.h" 12 | 13 | #define MEM_BASE 0x00000000 14 | #define MEM_SIZE (64 * 1024) 15 | 16 | //----------------------------------------------------------------- 17 | // Command line options 18 | //----------------------------------------------------------------- 19 | #define GETOPTS_ARGS "f:c:h" 20 | 21 | static struct option long_options[] = 22 | { 23 | {"elf", required_argument, 0, 'f'}, 24 | {"cycles", required_argument, 0, 'c'}, 25 | {"help", no_argument, 0, 'h'}, 26 | {0, 0, 0, 0} 27 | }; 28 | 29 | static void help_options(void) 30 | { 31 | fprintf (stderr,"Usage:\n"); 32 | fprintf (stderr," --elf | -f FILE File to load\n"); 33 | fprintf (stderr," --cycles | -c NUM Max instructions to execute\n"); 34 | exit(-1); 35 | } 36 | 37 | //----------------------------------------------------------------- 38 | // Module 39 | //----------------------------------------------------------------- 40 | class testbench: public testbench_vbase, public mem_api 41 | { 42 | public: 43 | //----------------------------------------------------------------- 44 | // Instances / Members 45 | //----------------------------------------------------------------- 46 | riscv_tcm_top_rtl *m_dut; 47 | 48 | int m_argc; 49 | char** m_argv; 50 | //----------------------------------------------------------------- 51 | // Signals 52 | //----------------------------------------------------------------- 53 | sc_signal rst_cpu_in; 54 | 55 | sc_signal axi_t_in; 56 | sc_signal axi_t_out; 57 | 58 | sc_signal axi_i_out; 59 | sc_signal axi_i_in; 60 | 61 | sc_signal < sc_uint <32> > intr_in; 62 | 63 | 64 | //----------------------------------------------------------------- 65 | // process: Main loop for CPU execution 66 | //----------------------------------------------------------------- 67 | void process(void) 68 | { 69 | uint64_t cycles = 0; 70 | int64_t max_cycles = (int64_t)-1; 71 | const char * filename = NULL; 72 | int help = 0; 73 | int c; 74 | 75 | int option_index = 0; 76 | while ((c = getopt_long (m_argc, m_argv, GETOPTS_ARGS, long_options, &option_index)) != -1) 77 | { 78 | switch(c) 79 | { 80 | case 'f': 81 | filename = optarg; 82 | break; 83 | case 'c': 84 | max_cycles = (int64_t)strtoull(optarg, NULL, 0); 85 | break; 86 | case '?': 87 | default: 88 | help = 1; 89 | break; 90 | } 91 | } 92 | 93 | if (help || filename == NULL) 94 | { 95 | help_options(); 96 | sc_stop(); 97 | return; 98 | } 99 | 100 | // Force CPU into reset 101 | rst_cpu_in.write(true); 102 | 103 | // Load Firmware 104 | printf("Running: %s\n", filename); 105 | elf_load elf(filename, this); 106 | if (!elf.load()) 107 | { 108 | fprintf (stderr,"Error: Could not open %s\n", filename); 109 | sc_stop(); 110 | } 111 | 112 | // Release CPU reset after TCM memory loaded 113 | wait(); 114 | rst_cpu_in.write(false); 115 | 116 | while (true) 117 | { 118 | cycles += 1; 119 | if (cycles >= max_cycles && max_cycles != -1) 120 | break; 121 | 122 | wait(); 123 | } 124 | 125 | sc_stop(); 126 | } 127 | 128 | void set_argcv(int argc, char* argv[]) { m_argc = argc; m_argv = argv; } 129 | 130 | //----------------------------------------------------------------- 131 | // Construction 132 | //----------------------------------------------------------------- 133 | SC_HAS_PROCESS(testbench); 134 | testbench(sc_module_name name): testbench_vbase(name) 135 | { 136 | m_dut = new riscv_tcm_top_rtl("DUT"); 137 | m_dut->clk_in(clk); 138 | m_dut->rst_in(rst); 139 | m_dut->rst_cpu_in(rst_cpu_in); 140 | m_dut->axi_t_out(axi_t_out); 141 | m_dut->axi_t_in(axi_t_in); 142 | m_dut->axi_i_out(axi_i_out); 143 | m_dut->axi_i_in(axi_i_in); 144 | m_dut->intr_in(intr_in); 145 | 146 | verilator_trace_enable("verilator.vcd", m_dut); 147 | } 148 | //----------------------------------------------------------------- 149 | // Trace 150 | //----------------------------------------------------------------- 151 | void add_trace(sc_trace_file * fp, std::string prefix) 152 | { 153 | if (!waves_enabled()) 154 | return; 155 | 156 | // Add signals to trace file 157 | #define TRACE_SIGNAL(a) sc_trace(fp,a,#a); 158 | TRACE_SIGNAL(clk); 159 | TRACE_SIGNAL(rst); 160 | 161 | m_dut->add_trace(fp, ""); 162 | } 163 | 164 | //----------------------------------------------------------------- 165 | // create_memory: Create memory region 166 | //----------------------------------------------------------------- 167 | bool create_memory(uint32_t base, uint32_t size, uint8_t *mem = NULL) 168 | { 169 | sc_assert(base >= MEM_BASE && ((base + size) < (MEM_BASE + MEM_SIZE))); 170 | return true; 171 | } 172 | //----------------------------------------------------------------- 173 | // valid_addr: Check address range 174 | //----------------------------------------------------------------- 175 | bool valid_addr(uint32_t addr) { return true; } 176 | //----------------------------------------------------------------- 177 | // write: Write byte into memory 178 | //----------------------------------------------------------------- 179 | void write(uint32_t addr, uint8_t data) 180 | { 181 | m_dut->m_rtl->__VlSymsp->TOP__v__u_tcm.write(addr, data); 182 | } 183 | //----------------------------------------------------------------- 184 | // write: Read byte from memory 185 | //----------------------------------------------------------------- 186 | uint8_t read(uint32_t addr) 187 | { 188 | return m_dut->m_rtl->__VlSymsp->TOP__v__u_tcm.read(addr); 189 | } 190 | }; 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # biRISC-V - 32-bit dual issue RISC-V CPU 2 | 3 | Github: [http://github.com/ultraembedded/biriscv](http://github.com/ultraembedded/biriscv) 4 | 5 | ![biRISC-V](docs/biRISC-V.png) 6 | 7 | ## Features 8 | * 32-bit RISC-V ISA CPU core. 9 | * Superscalar (dual-issue) in-order 6 or 7 stage pipeline. 10 | * Support RISC-V’s integer (I), multiplication and division (M), and CSR instructions (Z) extensions (RV32IMZicsr). 11 | * Branch prediction (bimodel/gshare) with configurable depth branch target buffer (BTB) and return address stack (RAS). 12 | * 64-bit instruction fetch, 32-bit data access. 13 | * 2 x integer ALU (arithmetic, shifters and branch units). 14 | * 1 x load store unit, 1 x out-of-pipeline divider. 15 | * Issue and complete up to 2 independent instructions per cycle. 16 | * Supports user, supervisor and machine mode privilege levels. 17 | * Basic MMU support - capable of booting Linux with atomics (RV-A) SW emulation. 18 | * Implements base ISA spec [v2.1](docs/riscv_isa_spec.pdf) and privileged ISA spec [v1.11](docs/riscv_privileged_spec.pdf). 19 | * Verified using [Google's RISCV-DV](https://github.com/google/riscv-dv) random instruction sequences using cosimulation against [C++ ISA model](https://github.com/ultraembedded/exactstep). 20 | * Support for instruction / data cache, AXI bus interfaces or tightly coupled memories. 21 | * Configurable number of pipeline stages, result forwarding options, and branch prediction resources. 22 | * Synthesizable Verilog 2001, Verilator and FPGA friendly. 23 | * Coremark: **4.1 CoreMark/MHz** 24 | * Dhrystone: **1.9 DMIPS/MHz** ('legal compile options' / 337 instructions per iteration) 25 | 26 | *A sequence showing execution of 2 instructions per cycle;* 27 | ![Dual-Issue](docs/dual_issue.png) 28 | 29 | ## Documentation 30 | * [Configuration](docs/configuration.md) 31 | * [Booting Linux](docs/linux.md) 32 | * [Integration](docs/integration.md) 33 | * [Custom Features](docs/custom.md) 34 | 35 | ## Similar Cores 36 | * [SiFive E76](https://www.sifive.com/cores/e76) 37 | * RV32IMAFC 38 | * Dual issue in-order 8 stage pipeline 39 | * 4 ALU units (2 early, 2 late) 40 | * :heavy_multiplication_x: *Commercial closed source core/$$* 41 | * [WD SweRV RISC-V Core EH1](https://github.com/chipsalliance/Cores-SweRV) 42 | * RV32IMC 43 | * Dual issue in-order 9 stage pipeline 44 | * 4 ALU units (2 early, 2 late) 45 | * :heavy_multiplication_x: *System Verilog + auto signal hookup* 46 | * :heavy_multiplication_x: *No data cache option* 47 | * :heavy_multiplication_x: *Not able to boot Linux* 48 | 49 | ## Project Aims 50 | * Boot Linux all the way to a functional userspace environment. :heavy_check_mark: 51 | * Achieve competitive performance for this class of in-order machine (i.e. aim for 80% of WD SweRV CoreMark score). :heavy_check_mark: 52 | * Reasonable PPA / FPGA resource friendly. :heavy_check_mark: 53 | * Fit easily onto cheap hobbyist FPGAs (e.g. Xilinx Artix 7) without using all LUT resources and synthesize > 50MHz. :heavy_check_mark: 54 | * Support various cache and TCM options. :heavy_check_mark: 55 | * Be constructed using readable, maintainable and documented IEEE 1364-2001 Verilog. :heavy_check_mark: 56 | * Simulate in open-source tools such as Verilator and Icarus Verilog. :heavy_check_mark: 57 | * *In later releases, add support for atomic extensions.* 58 | 59 | *Booting the stock Linux 5.0.0-rc8 kernel built for RV32IMA to userspace on a Digilent Arty Artix 7 with biRISC-V (with atomic instructions emulated in the bootloader);* 60 | ![Linux-Boot](docs/linux-boot.png) 61 | 62 | ## Prior Work 63 | Based on my previous work; 64 | * Github: [http://github.com/ultraembedded/riscv](http://github.com/ultraembedded/riscv) 65 | 66 | ## Getting Started 67 | 68 | #### Cloning 69 | 70 | To clone this project and its dependencies; 71 | 72 | ``` 73 | git clone --recursive https://github.com/ultraembedded/biriscv.git 74 | 75 | ``` 76 | 77 | #### Running Helloworld 78 | 79 | To run a simple test image on the core RTL using Icarus Verilog; 80 | 81 | ``` 82 | # Install Icarus Verilog (Debian / Ubuntu / Linux Mint) 83 | sudo apt-get install iverilog 84 | 85 | # [or] Install Icarus Verilog (Redhat / Centos) 86 | #sudo yum install iverilog 87 | 88 | # Run a simple test image (test.elf) 89 | cd tb/tb_core_icarus 90 | make 91 | ``` 92 | 93 | The expected output is; 94 | ``` 95 | Starting bench 96 | VCD info: dumpfile waveform.vcd opened for output. 97 | 98 | Test: 99 | 1. Initialised data 100 | 2. Multiply 101 | 3. Divide 102 | 4. Shift left 103 | 5. Shift right 104 | 6. Shift right arithmetic 105 | 7. Signed comparision 106 | 8. Word access 107 | 9. Byte access 108 | 10. Comparision 109 | ``` 110 | 111 | #### Configuration 112 | 113 | | Param Name | Valid Range | Description | 114 | | ------------------------- |:--------------------:| ----------------------------------------------| 115 | | SUPPORT_SUPER | 1/0 | Enable supervisor / user privilege levels. | 116 | | SUPPORT_MMU | 1/0 | Enable basic memory management unit. | 117 | | SUPPORT_MULDIV | 1/0 | Enable HW multiply / divide (RV-M). | 118 | | SUPPORT_DUAL_ISSUE | 1/0 | Support superscalar operation. | 119 | | SUPPORT_LOAD_BYPASS | 1/0 | Support load result bypass paths. | 120 | | SUPPORT_MUL_BYPASS | 1/0 | Support multiply result bypass paths. | 121 | | SUPPORT_REGFILE_XILINX | 1/0 | Support Xilinx optimised register file. | 122 | | SUPPORT_BRANCH_PREDICTION | 1/0 | Enable branch prediction structures. | 123 | | NUM_BTB_ENTRIES | 2 - | Number of branch target buffer entries. | 124 | | NUM_BTB_ENTRIES_W | 1 - | Set to log2(NUM_BTB_ENTRIES). | 125 | | NUM_BHT_ENTRIES | 2 - | Number of branch history table entries. | 126 | | NUM_BHT_ENTRIES_W | 1 - | Set to log2(NUM_BHT_ENTRIES_W). | 127 | | BHT_ENABLE | 1/0 | Enable branch history table based prediction. | 128 | | GSHARE_ENABLE | 1/0 | Enable GSHARE branch prediction algorithm. | 129 | | RAS_ENABLE | 1/0 | Enable return address stack prediction. | 130 | | NUM_RAS_ENTRIES | 2 - | Number of return stack addresses supported. | 131 | | NUM_RAS_ENTRIES_W | 1 - | Set to log2(NUM_RAS_ENTRIES_W). | 132 | | EXTRA_DECODE_STAGE | 1/0 | Extra decode pipe stage for improved timing. | 133 | | MEM_CACHE_ADDR_MIN | 32'h0 - 32'hffffffff | Lowest cacheable memory address. | 134 | | MEM_CACHE_ADDR_MAX | 32'h0 - 32'hffffffff | Highest cacheable memory address. | 135 | -------------------------------------------------------------------------------- /src/core/biriscv_alu.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.8.1 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | module biriscv_alu 26 | ( 27 | // Inputs 28 | input [ 3:0] alu_op_i 29 | ,input [ 31:0] alu_a_i 30 | ,input [ 31:0] alu_b_i 31 | 32 | // Outputs 33 | ,output [ 31:0] alu_p_o 34 | ); 35 | 36 | //----------------------------------------------------------------- 37 | // Includes 38 | //----------------------------------------------------------------- 39 | `include "biriscv_defs.v" 40 | 41 | //----------------------------------------------------------------- 42 | // Registers 43 | //----------------------------------------------------------------- 44 | reg [31:0] result_r; 45 | 46 | reg [31:16] shift_right_fill_r; 47 | reg [31:0] shift_right_1_r; 48 | reg [31:0] shift_right_2_r; 49 | reg [31:0] shift_right_4_r; 50 | reg [31:0] shift_right_8_r; 51 | 52 | reg [31:0] shift_left_1_r; 53 | reg [31:0] shift_left_2_r; 54 | reg [31:0] shift_left_4_r; 55 | reg [31:0] shift_left_8_r; 56 | 57 | wire [31:0] sub_res_w = alu_a_i - alu_b_i; 58 | 59 | //----------------------------------------------------------------- 60 | // ALU 61 | //----------------------------------------------------------------- 62 | always @ (alu_op_i or alu_a_i or alu_b_i or sub_res_w) 63 | begin 64 | shift_right_fill_r = 16'b0; 65 | shift_right_1_r = 32'b0; 66 | shift_right_2_r = 32'b0; 67 | shift_right_4_r = 32'b0; 68 | shift_right_8_r = 32'b0; 69 | 70 | shift_left_1_r = 32'b0; 71 | shift_left_2_r = 32'b0; 72 | shift_left_4_r = 32'b0; 73 | shift_left_8_r = 32'b0; 74 | 75 | case (alu_op_i) 76 | //---------------------------------------------- 77 | // Shift Left 78 | //---------------------------------------------- 79 | `ALU_SHIFTL : 80 | begin 81 | if (alu_b_i[0] == 1'b1) 82 | shift_left_1_r = {alu_a_i[30:0],1'b0}; 83 | else 84 | shift_left_1_r = alu_a_i; 85 | 86 | if (alu_b_i[1] == 1'b1) 87 | shift_left_2_r = {shift_left_1_r[29:0],2'b00}; 88 | else 89 | shift_left_2_r = shift_left_1_r; 90 | 91 | if (alu_b_i[2] == 1'b1) 92 | shift_left_4_r = {shift_left_2_r[27:0],4'b0000}; 93 | else 94 | shift_left_4_r = shift_left_2_r; 95 | 96 | if (alu_b_i[3] == 1'b1) 97 | shift_left_8_r = {shift_left_4_r[23:0],8'b00000000}; 98 | else 99 | shift_left_8_r = shift_left_4_r; 100 | 101 | if (alu_b_i[4] == 1'b1) 102 | result_r = {shift_left_8_r[15:0],16'b0000000000000000}; 103 | else 104 | result_r = shift_left_8_r; 105 | end 106 | //---------------------------------------------- 107 | // Shift Right 108 | //---------------------------------------------- 109 | `ALU_SHIFTR, `ALU_SHIFTR_ARITH: 110 | begin 111 | // Arithmetic shift? Fill with 1's if MSB set 112 | if (alu_a_i[31] == 1'b1 && alu_op_i == `ALU_SHIFTR_ARITH) 113 | shift_right_fill_r = 16'b1111111111111111; 114 | else 115 | shift_right_fill_r = 16'b0000000000000000; 116 | 117 | if (alu_b_i[0] == 1'b1) 118 | shift_right_1_r = {shift_right_fill_r[31], alu_a_i[31:1]}; 119 | else 120 | shift_right_1_r = alu_a_i; 121 | 122 | if (alu_b_i[1] == 1'b1) 123 | shift_right_2_r = {shift_right_fill_r[31:30], shift_right_1_r[31:2]}; 124 | else 125 | shift_right_2_r = shift_right_1_r; 126 | 127 | if (alu_b_i[2] == 1'b1) 128 | shift_right_4_r = {shift_right_fill_r[31:28], shift_right_2_r[31:4]}; 129 | else 130 | shift_right_4_r = shift_right_2_r; 131 | 132 | if (alu_b_i[3] == 1'b1) 133 | shift_right_8_r = {shift_right_fill_r[31:24], shift_right_4_r[31:8]}; 134 | else 135 | shift_right_8_r = shift_right_4_r; 136 | 137 | if (alu_b_i[4] == 1'b1) 138 | result_r = {shift_right_fill_r[31:16], shift_right_8_r[31:16]}; 139 | else 140 | result_r = shift_right_8_r; 141 | end 142 | //---------------------------------------------- 143 | // Arithmetic 144 | //---------------------------------------------- 145 | `ALU_ADD : 146 | begin 147 | result_r = (alu_a_i + alu_b_i); 148 | end 149 | `ALU_SUB : 150 | begin 151 | result_r = sub_res_w; 152 | end 153 | //---------------------------------------------- 154 | // Logical 155 | //---------------------------------------------- 156 | `ALU_AND : 157 | begin 158 | result_r = (alu_a_i & alu_b_i); 159 | end 160 | `ALU_OR : 161 | begin 162 | result_r = (alu_a_i | alu_b_i); 163 | end 164 | `ALU_XOR : 165 | begin 166 | result_r = (alu_a_i ^ alu_b_i); 167 | end 168 | //---------------------------------------------- 169 | // Comparision 170 | //---------------------------------------------- 171 | `ALU_LESS_THAN : 172 | begin 173 | result_r = (alu_a_i < alu_b_i) ? 32'h1 : 32'h0; 174 | end 175 | `ALU_LESS_THAN_SIGNED : 176 | begin 177 | if (alu_a_i[31] != alu_b_i[31]) 178 | result_r = alu_a_i[31] ? 32'h1 : 32'h0; 179 | else 180 | result_r = sub_res_w[31] ? 32'h1 : 32'h0; 181 | end 182 | default : 183 | begin 184 | result_r = alu_a_i; 185 | end 186 | endcase 187 | end 188 | 189 | assign alu_p_o = result_r; 190 | 191 | endmodule 192 | -------------------------------------------------------------------------------- /src/core/biriscv_divider.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.8.1 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module biriscv_divider 27 | ( 28 | // Inputs 29 | input clk_i 30 | ,input rst_i 31 | ,input opcode_valid_i 32 | ,input [ 31:0] opcode_opcode_i 33 | ,input [ 31:0] opcode_pc_i 34 | ,input opcode_invalid_i 35 | ,input [ 4:0] opcode_rd_idx_i 36 | ,input [ 4:0] opcode_ra_idx_i 37 | ,input [ 4:0] opcode_rb_idx_i 38 | ,input [ 31:0] opcode_ra_operand_i 39 | ,input [ 31:0] opcode_rb_operand_i 40 | 41 | // Outputs 42 | ,output writeback_valid_o 43 | ,output [ 31:0] writeback_value_o 44 | ); 45 | 46 | 47 | 48 | //----------------------------------------------------------------- 49 | // Includes 50 | //----------------------------------------------------------------- 51 | `include "biriscv_defs.v" 52 | 53 | //------------------------------------------------------------- 54 | // Registers / Wires 55 | //------------------------------------------------------------- 56 | reg valid_q; 57 | reg [31:0] wb_result_q; 58 | 59 | //------------------------------------------------------------- 60 | // Divider 61 | //------------------------------------------------------------- 62 | wire inst_div_w = (opcode_opcode_i & `INST_DIV_MASK) == `INST_DIV; 63 | wire inst_divu_w = (opcode_opcode_i & `INST_DIVU_MASK) == `INST_DIVU; 64 | wire inst_rem_w = (opcode_opcode_i & `INST_REM_MASK) == `INST_REM; 65 | wire inst_remu_w = (opcode_opcode_i & `INST_REMU_MASK) == `INST_REMU; 66 | 67 | wire div_rem_inst_w = ((opcode_opcode_i & `INST_DIV_MASK) == `INST_DIV) || 68 | ((opcode_opcode_i & `INST_DIVU_MASK) == `INST_DIVU) || 69 | ((opcode_opcode_i & `INST_REM_MASK) == `INST_REM) || 70 | ((opcode_opcode_i & `INST_REMU_MASK) == `INST_REMU); 71 | 72 | wire signed_operation_w = ((opcode_opcode_i & `INST_DIV_MASK) == `INST_DIV) || ((opcode_opcode_i & `INST_REM_MASK) == `INST_REM); 73 | wire div_operation_w = ((opcode_opcode_i & `INST_DIV_MASK) == `INST_DIV) || ((opcode_opcode_i & `INST_DIVU_MASK) == `INST_DIVU); 74 | 75 | reg [31:0] dividend_q; 76 | reg [62:0] divisor_q; 77 | reg [31:0] quotient_q; 78 | reg [31:0] q_mask_q; 79 | reg div_inst_q; 80 | reg div_busy_q; 81 | reg invert_res_q; 82 | 83 | reg [31:0] last_a_q; 84 | reg [31:0] last_b_q; 85 | reg last_div_q; 86 | reg last_divu_q; 87 | reg last_rem_q; 88 | reg last_remu_q; 89 | 90 | wire div_start_w = opcode_valid_i & div_rem_inst_w; 91 | wire div_complete_w = !(|q_mask_q) & div_busy_q; 92 | 93 | always @(posedge clk_i or posedge rst_i) 94 | if (rst_i) 95 | begin 96 | div_busy_q <= 1'b0; 97 | dividend_q <= 32'b0; 98 | divisor_q <= 63'b0; 99 | invert_res_q <= 1'b0; 100 | quotient_q <= 32'b0; 101 | q_mask_q <= 32'b0; 102 | div_inst_q <= 1'b0; 103 | last_a_q <= 32'b0; 104 | last_b_q <= 32'b0; 105 | last_div_q <= 1'b0; 106 | last_divu_q <= 1'b0; 107 | last_rem_q <= 1'b0; 108 | last_remu_q <= 1'b0; 109 | end 110 | else if (div_start_w) 111 | begin 112 | // Repeat same operation with same inputs... 113 | if (last_a_q == opcode_ra_operand_i && 114 | last_b_q == opcode_rb_operand_i && 115 | last_div_q == inst_div_w && 116 | last_divu_q == inst_divu_w && 117 | last_rem_q == inst_rem_w && 118 | last_remu_q == inst_remu_w) 119 | begin 120 | div_busy_q <= 1'b1; 121 | end 122 | else 123 | begin 124 | last_a_q <= opcode_ra_operand_i; 125 | last_b_q <= opcode_rb_operand_i; 126 | last_div_q <= inst_div_w; 127 | last_divu_q <= inst_divu_w; 128 | last_rem_q <= inst_rem_w; 129 | last_remu_q <= inst_remu_w; 130 | 131 | div_busy_q <= 1'b1; 132 | div_inst_q <= div_operation_w; 133 | 134 | if (signed_operation_w && opcode_ra_operand_i[31]) 135 | dividend_q <= -opcode_ra_operand_i; 136 | else 137 | dividend_q <= opcode_ra_operand_i; 138 | 139 | if (signed_operation_w && opcode_rb_operand_i[31]) 140 | divisor_q <= {-opcode_rb_operand_i, 31'b0}; 141 | else 142 | divisor_q <= {opcode_rb_operand_i, 31'b0}; 143 | 144 | invert_res_q <= (((opcode_opcode_i & `INST_DIV_MASK) == `INST_DIV) && (opcode_ra_operand_i[31] != opcode_rb_operand_i[31]) && |opcode_rb_operand_i) || 145 | (((opcode_opcode_i & `INST_REM_MASK) == `INST_REM) && opcode_ra_operand_i[31]); 146 | 147 | quotient_q <= 32'b0; 148 | q_mask_q <= 32'h80000000; 149 | end 150 | end 151 | else if (div_complete_w) 152 | begin 153 | div_busy_q <= 1'b0; 154 | end 155 | else if (div_busy_q) 156 | begin 157 | if (divisor_q <= {31'b0, dividend_q}) 158 | begin 159 | dividend_q <= dividend_q - divisor_q[31:0]; 160 | quotient_q <= quotient_q | q_mask_q; 161 | end 162 | 163 | divisor_q <= {1'b0, divisor_q[62:1]}; 164 | q_mask_q <= {1'b0, q_mask_q[31:1]}; 165 | end 166 | 167 | reg [31:0] div_result_r; 168 | always @ * 169 | begin 170 | div_result_r = 32'b0; 171 | 172 | if (div_inst_q) 173 | div_result_r = invert_res_q ? -quotient_q : quotient_q; 174 | else 175 | div_result_r = invert_res_q ? -dividend_q : dividend_q; 176 | end 177 | 178 | always @(posedge clk_i or posedge rst_i) 179 | if (rst_i) 180 | valid_q <= 1'b0; 181 | else 182 | valid_q <= div_complete_w; 183 | 184 | always @(posedge clk_i or posedge rst_i) 185 | if (rst_i) 186 | wb_result_q <= 32'b0; 187 | else if (div_complete_w) 188 | wb_result_q <= div_result_r; 189 | 190 | assign writeback_valid_o = valid_q; 191 | assign writeback_value_o = wb_result_q; 192 | 193 | 194 | 195 | endmodule 196 | -------------------------------------------------------------------------------- /tb/tb_top/testbench.h: -------------------------------------------------------------------------------- 1 | #include "testbench_vbase.h" 2 | #include "elf_load.h" 3 | #include 4 | #include 5 | 6 | #include "riscv_top.h" 7 | #include "tb_axi4_mem.h" 8 | 9 | #include "verilated.h" 10 | #include "verilated_vcd_sc.h" 11 | 12 | #define MEM_BASE 0x80000000 13 | 14 | //----------------------------------------------------------------- 15 | // Command line options 16 | //----------------------------------------------------------------- 17 | #define GETOPTS_ARGS "f:c:h" 18 | 19 | static struct option long_options[] = 20 | { 21 | {"elf", required_argument, 0, 'f'}, 22 | {"cycles", required_argument, 0, 'c'}, 23 | {"help", no_argument, 0, 'h'}, 24 | {0, 0, 0, 0} 25 | }; 26 | 27 | static void help_options(void) 28 | { 29 | fprintf (stderr,"Usage:\n"); 30 | fprintf (stderr," --elf | -f FILE File to load\n"); 31 | fprintf (stderr," --cycles | -c NUM Max instructions to execute\n"); 32 | exit(-1); 33 | } 34 | 35 | //----------------------------------------------------------------- 36 | // Module 37 | //----------------------------------------------------------------- 38 | class testbench: public testbench_vbase, public mem_api 39 | { 40 | public: 41 | //----------------------------------------------------------------- 42 | // Instances / Members 43 | //----------------------------------------------------------------- 44 | riscv_top *m_dut; 45 | tb_axi4_mem *m_icache_mem; 46 | tb_axi4_mem *m_dcache_mem; 47 | 48 | int m_argc; 49 | char** m_argv; 50 | 51 | sc_signal mem_i_in; 52 | sc_signal mem_i_out; 53 | 54 | sc_signal mem_d_in; 55 | sc_signal mem_d_out; 56 | 57 | sc_signal < bool > intr_in; 58 | 59 | sc_signal < sc_uint <32> > reset_vector_in; 60 | 61 | //----------------------------------------------------------------- 62 | // process: Main loop for CPU execution 63 | //----------------------------------------------------------------- 64 | void process(void) 65 | { 66 | uint64_t cycles = 0; 67 | int64_t max_cycles = (int64_t)-1; 68 | const char * filename = NULL; 69 | int help = 0; 70 | int c; 71 | 72 | int option_index = 0; 73 | while ((c = getopt_long (m_argc, m_argv, GETOPTS_ARGS, long_options, &option_index)) != -1) 74 | { 75 | switch(c) 76 | { 77 | case 'f': 78 | filename = optarg; 79 | break; 80 | case 'c': 81 | max_cycles = (int64_t)strtoull(optarg, NULL, 0); 82 | break; 83 | case '?': 84 | default: 85 | help = 1; 86 | break; 87 | } 88 | } 89 | 90 | if (help || filename == NULL) 91 | { 92 | help_options(); 93 | sc_stop(); 94 | return; 95 | } 96 | 97 | // Load Firmware 98 | printf("Running: %s\n", filename); 99 | elf_load elf(filename, this); 100 | if (!elf.load()) 101 | { 102 | fprintf (stderr,"Error: Could not open %s\n", filename); 103 | sc_stop(); 104 | } 105 | 106 | // Set reset vector 107 | reset_vector_in.write(MEM_BASE); 108 | 109 | while (true) 110 | { 111 | cycles += 1; 112 | if (cycles >= max_cycles && max_cycles != -1) 113 | break; 114 | 115 | wait(); 116 | } 117 | 118 | sc_stop(); 119 | } 120 | 121 | void set_argcv(int argc, char* argv[]) { m_argc = argc; m_argv = argv; } 122 | 123 | //----------------------------------------------------------------- 124 | // Construction 125 | //----------------------------------------------------------------- 126 | SC_HAS_PROCESS(testbench); 127 | testbench(sc_module_name name): testbench_vbase(name) 128 | { 129 | m_dut = new riscv_top("DUT"); 130 | m_dut->clk_in(clk); 131 | m_dut->rst_in(rst); 132 | m_dut->axi_i_out(mem_i_out); 133 | m_dut->axi_i_in(mem_i_in); 134 | m_dut->axi_d_out(mem_d_out); 135 | m_dut->axi_d_in(mem_d_in); 136 | m_dut->intr_in(intr_in); 137 | m_dut->reset_vector_in(reset_vector_in); 138 | 139 | // Instruction Cache Memory 140 | m_icache_mem = new tb_axi4_mem("ICACHE_MEM"); 141 | m_icache_mem->clk_in(clk); 142 | m_icache_mem->rst_in(rst); 143 | m_icache_mem->axi_in(mem_i_out); 144 | m_icache_mem->axi_out(mem_i_in); 145 | 146 | // Data Cache Memory 147 | m_dcache_mem = new tb_axi4_mem("DCACHE_MEM"); 148 | m_dcache_mem->clk_in(clk); 149 | m_dcache_mem->rst_in(rst); 150 | m_dcache_mem->axi_in(mem_d_out); 151 | m_dcache_mem->axi_out(mem_d_in); 152 | 153 | verilator_trace_enable("verilator.vcd", m_dut); 154 | } 155 | //----------------------------------------------------------------- 156 | // Trace 157 | //----------------------------------------------------------------- 158 | void add_trace(sc_trace_file * fp, std::string prefix) 159 | { 160 | if (!waves_enabled()) 161 | return; 162 | 163 | // Add signals to trace file 164 | #define TRACE_SIGNAL(a) sc_trace(fp,a,#a); 165 | TRACE_SIGNAL(clk); 166 | TRACE_SIGNAL(rst); 167 | 168 | m_dut->add_trace(fp, ""); 169 | } 170 | 171 | //----------------------------------------------------------------- 172 | // create_memory: Create memory region 173 | //----------------------------------------------------------------- 174 | bool create_memory(uint32_t base, uint32_t size, uint8_t *mem = NULL) 175 | { 176 | base = base & ~(32-1); 177 | size = (size + 31) & ~(32-1); 178 | 179 | while (m_icache_mem->valid_addr(base)) 180 | base += 1; 181 | 182 | while (m_icache_mem->valid_addr(base + size - 1)) 183 | size -= 1; 184 | 185 | m_icache_mem->add_region(base, size); 186 | m_dcache_mem->add_region(m_icache_mem->get_array(base), base, size); 187 | 188 | memset(m_icache_mem->get_array(base), 0, size); 189 | return true; 190 | } 191 | //----------------------------------------------------------------- 192 | // valid_addr: Check address range 193 | //----------------------------------------------------------------- 194 | bool valid_addr(uint32_t addr) { return true; } 195 | //----------------------------------------------------------------- 196 | // write: Write byte into memory 197 | //----------------------------------------------------------------- 198 | void write(uint32_t addr, uint8_t data) 199 | { 200 | m_dcache_mem->write(addr, data); 201 | } 202 | //----------------------------------------------------------------- 203 | // write: Read byte from memory 204 | //----------------------------------------------------------------- 205 | uint8_t read(uint32_t addr) 206 | { 207 | return m_dcache_mem->read(addr); 208 | } 209 | }; 210 | -------------------------------------------------------------------------------- /src/dcache/dcache_axi_axi.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------- 2 | // biRISC-V CPU 3 | // V0.6.0 4 | // Ultra-Embedded.com 5 | // Copyright 2019-2020 6 | // 7 | // admin@ultra-embedded.com 8 | // 9 | // License: Apache 2.0 10 | //----------------------------------------------------------------- 11 | // Copyright 2020 Ultra-Embedded.com 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | //----------------------------------------------------------------- 25 | 26 | module dcache_axi_axi 27 | ( 28 | // Inputs 29 | input clk_i 30 | ,input rst_i 31 | ,input inport_valid_i 32 | ,input inport_write_i 33 | ,input [ 31:0] inport_addr_i 34 | ,input [ 3:0] inport_id_i 35 | ,input [ 7:0] inport_len_i 36 | ,input [ 1:0] inport_burst_i 37 | ,input [ 31:0] inport_wdata_i 38 | ,input [ 3:0] inport_wstrb_i 39 | ,input inport_bready_i 40 | ,input inport_rready_i 41 | ,input outport_awready_i 42 | ,input outport_wready_i 43 | ,input outport_bvalid_i 44 | ,input [ 1:0] outport_bresp_i 45 | ,input [ 3:0] outport_bid_i 46 | ,input outport_arready_i 47 | ,input outport_rvalid_i 48 | ,input [ 31:0] outport_rdata_i 49 | ,input [ 1:0] outport_rresp_i 50 | ,input [ 3:0] outport_rid_i 51 | ,input outport_rlast_i 52 | 53 | // Outputs 54 | ,output inport_accept_o 55 | ,output inport_bvalid_o 56 | ,output [ 1:0] inport_bresp_o 57 | ,output [ 3:0] inport_bid_o 58 | ,output inport_rvalid_o 59 | ,output [ 31:0] inport_rdata_o 60 | ,output [ 1:0] inport_rresp_o 61 | ,output [ 3:0] inport_rid_o 62 | ,output inport_rlast_o 63 | ,output outport_awvalid_o 64 | ,output [ 31:0] outport_awaddr_o 65 | ,output [ 3:0] outport_awid_o 66 | ,output [ 7:0] outport_awlen_o 67 | ,output [ 1:0] outport_awburst_o 68 | ,output outport_wvalid_o 69 | ,output [ 31:0] outport_wdata_o 70 | ,output [ 3:0] outport_wstrb_o 71 | ,output outport_wlast_o 72 | ,output outport_bready_o 73 | ,output outport_arvalid_o 74 | ,output [ 31:0] outport_araddr_o 75 | ,output [ 3:0] outport_arid_o 76 | ,output [ 7:0] outport_arlen_o 77 | ,output [ 1:0] outport_arburst_o 78 | ,output outport_rready_o 79 | ); 80 | 81 | 82 | 83 | //------------------------------------------------------------- 84 | // Write Request 85 | //------------------------------------------------------------- 86 | reg awvalid_inhibit_q; 87 | reg wvalid_inhibit_q; 88 | 89 | always @ (posedge clk_i or posedge rst_i) 90 | if (rst_i) 91 | awvalid_inhibit_q <= 1'b0; 92 | else if (outport_awvalid_o && outport_awready_i && outport_wvalid_o && !outport_wready_i) 93 | awvalid_inhibit_q <= 1'b1; 94 | else if (outport_awvalid_o && outport_awready_i && outport_awlen_o != 8'b0) 95 | awvalid_inhibit_q <= 1'b1; 96 | else if (outport_wvalid_o && outport_wready_i && outport_wlast_o) 97 | awvalid_inhibit_q <= 1'b0; 98 | 99 | always @ (posedge clk_i or posedge rst_i) 100 | if (rst_i) 101 | wvalid_inhibit_q <= 1'b0; 102 | else if (outport_wvalid_o && outport_wready_i && outport_awvalid_o && !outport_awready_i) 103 | wvalid_inhibit_q <= 1'b1; 104 | else if (outport_awvalid_o && outport_awready_i) 105 | wvalid_inhibit_q <= 1'b0; 106 | 107 | assign outport_awvalid_o = (inport_valid_i & inport_write_i & ~awvalid_inhibit_q); 108 | assign outport_awaddr_o = inport_addr_i; 109 | assign outport_awid_o = inport_id_i; 110 | assign outport_awlen_o = inport_len_i; 111 | assign outport_awburst_o = inport_burst_i; 112 | 113 | //------------------------------------------------------------- 114 | // Write burst tracking 115 | //------------------------------------------------------------- 116 | reg [7:0] req_cnt_q; 117 | 118 | always @ (posedge clk_i or posedge rst_i) 119 | if (rst_i) 120 | req_cnt_q <= 8'b0; 121 | else if (outport_awvalid_o && outport_awready_i) 122 | begin 123 | // First data not accepted yet 124 | if (!outport_wready_i && !wvalid_inhibit_q) 125 | req_cnt_q <= (outport_awlen_o + 8'd1); 126 | // First data already accepted 127 | else 128 | req_cnt_q <= outport_awlen_o; 129 | end 130 | else if (req_cnt_q != 8'd0 && outport_wvalid_o && outport_wready_i) 131 | req_cnt_q <= req_cnt_q - 8'd1; 132 | 133 | wire wlast_w = (outport_awvalid_o && outport_awlen_o == 8'b0) || (req_cnt_q == 8'd1); 134 | 135 | //------------------------------------------------------------- 136 | // Write data skid buffer 137 | //------------------------------------------------------------- 138 | reg buf_valid_q; 139 | always @ (posedge clk_i or posedge rst_i) 140 | if (rst_i) 141 | buf_valid_q <= 1'b0; 142 | else if (outport_wvalid_o && !outport_wready_i && outport_awvalid_o && outport_awready_i) 143 | buf_valid_q <= 1'b1; 144 | else if (outport_wready_i) 145 | buf_valid_q <= 1'b0; 146 | 147 | reg [36:0] buf_q; 148 | always @ (posedge clk_i or posedge rst_i) 149 | if (rst_i) 150 | buf_q <= 37'b0; 151 | else 152 | buf_q <= {outport_wlast_o, outport_wstrb_o, outport_wdata_o}; 153 | 154 | assign outport_wvalid_o = buf_valid_q ? 1'b1 : (inport_valid_i & inport_write_i & ~wvalid_inhibit_q); 155 | assign outport_wdata_o = buf_valid_q ? buf_q[31:0] : inport_wdata_i; 156 | assign outport_wstrb_o = buf_valid_q ? buf_q[35:32] : inport_wstrb_i; 157 | assign outport_wlast_o = buf_valid_q ? buf_q[36:36] : wlast_w; 158 | 159 | assign inport_bvalid_o = outport_bvalid_i; 160 | assign inport_bresp_o = outport_bresp_i; 161 | assign inport_bid_o = outport_bid_i; 162 | assign outport_bready_o = inport_bready_i; 163 | 164 | //------------------------------------------------------------- 165 | // Read Request 166 | //------------------------------------------------------------- 167 | assign outport_arvalid_o = inport_valid_i & ~inport_write_i; 168 | assign outport_araddr_o = inport_addr_i; 169 | assign outport_arid_o = inport_id_i; 170 | assign outport_arlen_o = inport_len_i; 171 | assign outport_arburst_o = inport_burst_i; 172 | assign outport_rready_o = inport_rready_i; 173 | 174 | assign inport_rvalid_o = outport_rvalid_i; 175 | assign inport_rdata_o = outport_rdata_i; 176 | assign inport_rresp_o = outport_rresp_i; 177 | assign inport_rid_o = outport_rid_i; 178 | assign inport_rlast_o = outport_rlast_i; 179 | 180 | //------------------------------------------------------------- 181 | // Accept logic 182 | //------------------------------------------------------------- 183 | assign inport_accept_o = (outport_awvalid_o && outport_awready_i) || 184 | (outport_wvalid_o && outport_wready_i && !buf_valid_q) || 185 | (outport_arvalid_o && outport_arready_i); 186 | 187 | 188 | endmodule 189 | -------------------------------------------------------------------------------- /tb/tb_tcm/riscv_tcm_top_rtl.cpp: -------------------------------------------------------------------------------- 1 | #include "riscv_tcm_top_rtl.h" 2 | #include "Vriscv_tcm_top.h" 3 | 4 | #if VM_TRACE 5 | #include "verilated.h" 6 | #include "verilated_vcd_c.h" 7 | #endif 8 | 9 | //------------------------------------------------------------- 10 | // Constructor 11 | //------------------------------------------------------------- 12 | riscv_tcm_top_rtl::riscv_tcm_top_rtl(sc_module_name name): sc_module(name) 13 | { 14 | m_rtl = new Vriscv_tcm_top("Vriscv_tcm_top"); 15 | m_rtl->clk_i(m_clk_in); 16 | m_rtl->rst_i(m_rst_in); 17 | m_rtl->rst_cpu_i(m_rst_cpu_in); 18 | m_rtl->axi_i_awready_i(m_axi_i_awready_in); 19 | m_rtl->axi_i_wready_i(m_axi_i_wready_in); 20 | m_rtl->axi_i_bvalid_i(m_axi_i_bvalid_in); 21 | m_rtl->axi_i_bresp_i(m_axi_i_bresp_in); 22 | m_rtl->axi_i_arready_i(m_axi_i_arready_in); 23 | m_rtl->axi_i_rvalid_i(m_axi_i_rvalid_in); 24 | m_rtl->axi_i_rdata_i(m_axi_i_rdata_in); 25 | m_rtl->axi_i_rresp_i(m_axi_i_rresp_in); 26 | m_rtl->axi_t_awvalid_i(m_axi_t_awvalid_in); 27 | m_rtl->axi_t_awaddr_i(m_axi_t_awaddr_in); 28 | m_rtl->axi_t_awid_i(m_axi_t_awid_in); 29 | m_rtl->axi_t_awlen_i(m_axi_t_awlen_in); 30 | m_rtl->axi_t_awburst_i(m_axi_t_awburst_in); 31 | m_rtl->axi_t_wvalid_i(m_axi_t_wvalid_in); 32 | m_rtl->axi_t_wdata_i(m_axi_t_wdata_in); 33 | m_rtl->axi_t_wstrb_i(m_axi_t_wstrb_in); 34 | m_rtl->axi_t_wlast_i(m_axi_t_wlast_in); 35 | m_rtl->axi_t_bready_i(m_axi_t_bready_in); 36 | m_rtl->axi_t_arvalid_i(m_axi_t_arvalid_in); 37 | m_rtl->axi_t_araddr_i(m_axi_t_araddr_in); 38 | m_rtl->axi_t_arid_i(m_axi_t_arid_in); 39 | m_rtl->axi_t_arlen_i(m_axi_t_arlen_in); 40 | m_rtl->axi_t_arburst_i(m_axi_t_arburst_in); 41 | m_rtl->axi_t_rready_i(m_axi_t_rready_in); 42 | m_rtl->intr_i(m_intr_in); 43 | m_rtl->axi_i_awvalid_o(m_axi_i_awvalid_out); 44 | m_rtl->axi_i_awaddr_o(m_axi_i_awaddr_out); 45 | m_rtl->axi_i_wvalid_o(m_axi_i_wvalid_out); 46 | m_rtl->axi_i_wdata_o(m_axi_i_wdata_out); 47 | m_rtl->axi_i_wstrb_o(m_axi_i_wstrb_out); 48 | m_rtl->axi_i_bready_o(m_axi_i_bready_out); 49 | m_rtl->axi_i_arvalid_o(m_axi_i_arvalid_out); 50 | m_rtl->axi_i_araddr_o(m_axi_i_araddr_out); 51 | m_rtl->axi_i_rready_o(m_axi_i_rready_out); 52 | m_rtl->axi_t_awready_o(m_axi_t_awready_out); 53 | m_rtl->axi_t_wready_o(m_axi_t_wready_out); 54 | m_rtl->axi_t_bvalid_o(m_axi_t_bvalid_out); 55 | m_rtl->axi_t_bresp_o(m_axi_t_bresp_out); 56 | m_rtl->axi_t_bid_o(m_axi_t_bid_out); 57 | m_rtl->axi_t_arready_o(m_axi_t_arready_out); 58 | m_rtl->axi_t_rvalid_o(m_axi_t_rvalid_out); 59 | m_rtl->axi_t_rdata_o(m_axi_t_rdata_out); 60 | m_rtl->axi_t_rresp_o(m_axi_t_rresp_out); 61 | m_rtl->axi_t_rid_o(m_axi_t_rid_out); 62 | m_rtl->axi_t_rlast_o(m_axi_t_rlast_out); 63 | 64 | SC_METHOD(async_outputs); 65 | sensitive << clk_in; 66 | sensitive << rst_in; 67 | sensitive << rst_cpu_in; 68 | sensitive << intr_in; 69 | sensitive << axi_i_in; 70 | sensitive << axi_t_in; 71 | sensitive << m_axi_i_awvalid_out; 72 | sensitive << m_axi_i_awaddr_out; 73 | sensitive << m_axi_i_wvalid_out; 74 | sensitive << m_axi_i_wdata_out; 75 | sensitive << m_axi_i_wstrb_out; 76 | sensitive << m_axi_i_bready_out; 77 | sensitive << m_axi_i_arvalid_out; 78 | sensitive << m_axi_i_araddr_out; 79 | sensitive << m_axi_i_rready_out; 80 | sensitive << m_axi_t_awready_out; 81 | sensitive << m_axi_t_wready_out; 82 | sensitive << m_axi_t_bvalid_out; 83 | sensitive << m_axi_t_bresp_out; 84 | sensitive << m_axi_t_bid_out; 85 | sensitive << m_axi_t_arready_out; 86 | sensitive << m_axi_t_rvalid_out; 87 | sensitive << m_axi_t_rdata_out; 88 | sensitive << m_axi_t_rresp_out; 89 | sensitive << m_axi_t_rid_out; 90 | sensitive << m_axi_t_rlast_out; 91 | 92 | #if VM_TRACE 93 | m_vcd = NULL; 94 | m_delay_waves = false; 95 | SC_METHOD(trace_rtl); 96 | sensitive << clk_in; 97 | #endif 98 | } 99 | //------------------------------------------------------------- 100 | // trace_rtl 101 | //------------------------------------------------------------- 102 | void riscv_tcm_top_rtl::trace_rtl(void) 103 | { 104 | #if VM_TRACE 105 | if (m_delay_waves) 106 | { 107 | if (sc_time_stamp() > m_waves_start) 108 | { 109 | cout << "WAVES: Delayed start reached - " << sc_time_stamp() << endl; 110 | m_delay_waves = false; 111 | } 112 | } 113 | else if (m_vcd) 114 | m_vcd->dump((int)(sc_time_stamp().to_double())); 115 | #endif 116 | } 117 | //------------------------------------------------------------- 118 | // trace_enable 119 | //------------------------------------------------------------- 120 | void riscv_tcm_top_rtl::trace_enable(VerilatedVcdC * p) 121 | { 122 | #if VM_TRACE 123 | m_vcd = p; 124 | m_rtl->trace (m_vcd, 99); 125 | #endif 126 | } 127 | void riscv_tcm_top_rtl::trace_enable(VerilatedVcdC *p, sc_core::sc_time start_time) 128 | { 129 | #if VM_TRACE 130 | m_vcd = p; 131 | m_delay_waves = true; 132 | m_waves_start = start_time; 133 | m_rtl->trace (m_vcd, 99); 134 | #endif 135 | } 136 | //------------------------------------------------------------- 137 | // async_outputs 138 | //------------------------------------------------------------- 139 | void riscv_tcm_top_rtl::async_outputs(void) 140 | { 141 | m_clk_in.write(clk_in.read()); 142 | m_rst_in.write(rst_in.read()); 143 | m_rst_cpu_in.write(rst_cpu_in.read()); 144 | m_intr_in.write(intr_in.read()); 145 | 146 | axi4_lite_slave axi_i_i = axi_i_in.read(); 147 | m_axi_i_awready_in.write(axi_i_i.AWREADY); 148 | m_axi_i_wready_in.write(axi_i_i.WREADY); 149 | m_axi_i_bvalid_in.write(axi_i_i.BVALID); 150 | m_axi_i_bresp_in.write(axi_i_i.BRESP); 151 | m_axi_i_arready_in.write(axi_i_i.ARREADY); 152 | m_axi_i_rvalid_in.write(axi_i_i.RVALID); 153 | m_axi_i_rdata_in.write(axi_i_i.RDATA); 154 | m_axi_i_rresp_in.write(axi_i_i.RRESP); 155 | 156 | 157 | axi4_lite_master axi_i_o; 158 | axi_i_o.AWVALID = m_axi_i_awvalid_out.read(); 159 | axi_i_o.AWADDR = m_axi_i_awaddr_out.read(); 160 | axi_i_o.WVALID = m_axi_i_wvalid_out.read(); 161 | axi_i_o.WDATA = m_axi_i_wdata_out.read(); 162 | axi_i_o.WSTRB = m_axi_i_wstrb_out.read(); 163 | axi_i_o.BREADY = m_axi_i_bready_out.read(); 164 | axi_i_o.ARVALID = m_axi_i_arvalid_out.read(); 165 | axi_i_o.ARADDR = m_axi_i_araddr_out.read(); 166 | axi_i_o.RREADY = m_axi_i_rready_out.read(); 167 | axi_i_out.write(axi_i_o); 168 | axi4_master axi_t_i = axi_t_in.read(); 169 | m_axi_t_awvalid_in.write(axi_t_i.AWVALID); 170 | m_axi_t_awaddr_in.write(axi_t_i.AWADDR); 171 | m_axi_t_awid_in.write(axi_t_i.AWID); 172 | m_axi_t_awlen_in.write(axi_t_i.AWLEN); 173 | m_axi_t_awburst_in.write(axi_t_i.AWBURST); 174 | m_axi_t_wvalid_in.write(axi_t_i.WVALID); 175 | m_axi_t_wdata_in.write(axi_t_i.WDATA); 176 | m_axi_t_wstrb_in.write(axi_t_i.WSTRB); 177 | m_axi_t_wlast_in.write(axi_t_i.WLAST); 178 | m_axi_t_bready_in.write(axi_t_i.BREADY); 179 | m_axi_t_arvalid_in.write(axi_t_i.ARVALID); 180 | m_axi_t_araddr_in.write(axi_t_i.ARADDR); 181 | m_axi_t_arid_in.write(axi_t_i.ARID); 182 | m_axi_t_arlen_in.write(axi_t_i.ARLEN); 183 | m_axi_t_arburst_in.write(axi_t_i.ARBURST); 184 | m_axi_t_rready_in.write(axi_t_i.RREADY); 185 | 186 | 187 | axi4_slave axi_t_o; 188 | axi_t_o.AWREADY = m_axi_t_awready_out.read(); 189 | axi_t_o.WREADY = m_axi_t_wready_out.read(); 190 | axi_t_o.BVALID = m_axi_t_bvalid_out.read(); 191 | axi_t_o.BRESP = m_axi_t_bresp_out.read(); 192 | axi_t_o.BID = m_axi_t_bid_out.read(); 193 | axi_t_o.ARREADY = m_axi_t_arready_out.read(); 194 | axi_t_o.RVALID = m_axi_t_rvalid_out.read(); 195 | axi_t_o.RDATA = m_axi_t_rdata_out.read(); 196 | axi_t_o.RRESP = m_axi_t_rresp_out.read(); 197 | axi_t_o.RID = m_axi_t_rid_out.read(); 198 | axi_t_o.RLAST = m_axi_t_rlast_out.read(); 199 | axi_t_out.write(axi_t_o); 200 | 201 | } 202 | -------------------------------------------------------------------------------- /tb/tb_tcm/axi4.h: -------------------------------------------------------------------------------- 1 | #ifndef AXI4_H 2 | #define AXI4_H 3 | 4 | #include 5 | 6 | //---------------------------------------------------------------- 7 | // Interface (master) 8 | //---------------------------------------------------------------- 9 | class axi4_master 10 | { 11 | public: 12 | // Members 13 | sc_uint <1> AWVALID; 14 | sc_uint <32> AWADDR; 15 | sc_uint <4> AWID; 16 | sc_uint <8> AWLEN; 17 | sc_uint <2> AWBURST; 18 | sc_uint <1> WVALID; 19 | sc_uint <32> WDATA; 20 | sc_uint <4> WSTRB; 21 | sc_uint <1> WLAST; 22 | sc_uint <1> BREADY; 23 | sc_uint <1> ARVALID; 24 | sc_uint <32> ARADDR; 25 | sc_uint <4> ARID; 26 | sc_uint <8> ARLEN; 27 | sc_uint <2> ARBURST; 28 | sc_uint <1> RREADY; 29 | 30 | // Construction 31 | axi4_master() { init(); } 32 | 33 | void init(void) 34 | { 35 | AWVALID = 0; 36 | AWADDR = 0; 37 | AWID = 0; 38 | AWLEN = 0; 39 | AWBURST = 0; 40 | WVALID = 0; 41 | WDATA = 0; 42 | WSTRB = 0; 43 | WLAST = 0; 44 | BREADY = 0; 45 | ARVALID = 0; 46 | ARADDR = 0; 47 | ARID = 0; 48 | ARLEN = 0; 49 | ARBURST = 0; 50 | RREADY = 0; 51 | } 52 | 53 | bool operator == (const axi4_master & v) const 54 | { 55 | bool eq = true; 56 | eq &= (AWVALID == v.AWVALID); 57 | eq &= (AWADDR == v.AWADDR); 58 | eq &= (AWID == v.AWID); 59 | eq &= (AWLEN == v.AWLEN); 60 | eq &= (AWBURST == v.AWBURST); 61 | eq &= (WVALID == v.WVALID); 62 | eq &= (WDATA == v.WDATA); 63 | eq &= (WSTRB == v.WSTRB); 64 | eq &= (WLAST == v.WLAST); 65 | eq &= (BREADY == v.BREADY); 66 | eq &= (ARVALID == v.ARVALID); 67 | eq &= (ARADDR == v.ARADDR); 68 | eq &= (ARID == v.ARID); 69 | eq &= (ARLEN == v.ARLEN); 70 | eq &= (ARBURST == v.ARBURST); 71 | eq &= (RREADY == v.RREADY); 72 | return eq; 73 | } 74 | 75 | friend void sc_trace(sc_trace_file *tf, const axi4_master & v, const std::string & path) 76 | { 77 | sc_trace(tf,v.AWVALID, path + "/awvalid"); 78 | sc_trace(tf,v.AWADDR, path + "/awaddr"); 79 | sc_trace(tf,v.AWID, path + "/awid"); 80 | sc_trace(tf,v.AWLEN, path + "/awlen"); 81 | sc_trace(tf,v.AWBURST, path + "/awburst"); 82 | sc_trace(tf,v.WVALID, path + "/wvalid"); 83 | sc_trace(tf,v.WDATA, path + "/wdata"); 84 | sc_trace(tf,v.WSTRB, path + "/wstrb"); 85 | sc_trace(tf,v.WLAST, path + "/wlast"); 86 | sc_trace(tf,v.BREADY, path + "/bready"); 87 | sc_trace(tf,v.ARVALID, path + "/arvalid"); 88 | sc_trace(tf,v.ARADDR, path + "/araddr"); 89 | sc_trace(tf,v.ARID, path + "/arid"); 90 | sc_trace(tf,v.ARLEN, path + "/arlen"); 91 | sc_trace(tf,v.ARBURST, path + "/arburst"); 92 | sc_trace(tf,v.RREADY, path + "/rready"); 93 | } 94 | 95 | friend ostream& operator << (ostream& os, axi4_master const & v) 96 | { 97 | os << hex << "AWVALID: " << v.AWVALID << " "; 98 | os << hex << "AWADDR: " << v.AWADDR << " "; 99 | os << hex << "AWID: " << v.AWID << " "; 100 | os << hex << "AWLEN: " << v.AWLEN << " "; 101 | os << hex << "AWBURST: " << v.AWBURST << " "; 102 | os << hex << "WVALID: " << v.WVALID << " "; 103 | os << hex << "WDATA: " << v.WDATA << " "; 104 | os << hex << "WSTRB: " << v.WSTRB << " "; 105 | os << hex << "WLAST: " << v.WLAST << " "; 106 | os << hex << "BREADY: " << v.BREADY << " "; 107 | os << hex << "ARVALID: " << v.ARVALID << " "; 108 | os << hex << "ARADDR: " << v.ARADDR << " "; 109 | os << hex << "ARID: " << v.ARID << " "; 110 | os << hex << "ARLEN: " << v.ARLEN << " "; 111 | os << hex << "ARBURST: " << v.ARBURST << " "; 112 | os << hex << "RREADY: " << v.RREADY << " "; 113 | return os; 114 | } 115 | 116 | friend istream& operator >> ( istream& is, axi4_master & val) 117 | { 118 | // Not implemented 119 | return is; 120 | } 121 | }; 122 | 123 | #define MEMBER_COPY_AXI4_MASTER(s,d) do { \ 124 | s.AWVALID = d.AWVALID; \ 125 | s.AWADDR = d.AWADDR; \ 126 | s.AWID = d.AWID; \ 127 | s.AWLEN = d.AWLEN; \ 128 | s.AWBURST = d.AWBURST; \ 129 | s.WVALID = d.WVALID; \ 130 | s.WDATA = d.WDATA; \ 131 | s.WSTRB = d.WSTRB; \ 132 | s.WLAST = d.WLAST; \ 133 | s.BREADY = d.BREADY; \ 134 | s.ARVALID = d.ARVALID; \ 135 | s.ARADDR = d.ARADDR; \ 136 | s.ARID = d.ARID; \ 137 | s.ARLEN = d.ARLEN; \ 138 | s.ARBURST = d.ARBURST; \ 139 | s.RREADY = d.RREADY; \ 140 | } while (0) 141 | 142 | //---------------------------------------------------------------- 143 | // Interface (slave) 144 | //---------------------------------------------------------------- 145 | class axi4_slave 146 | { 147 | public: 148 | // Members 149 | sc_uint <1> AWREADY; 150 | sc_uint <1> WREADY; 151 | sc_uint <1> BVALID; 152 | sc_uint <2> BRESP; 153 | sc_uint <4> BID; 154 | sc_uint <1> ARREADY; 155 | sc_uint <1> RVALID; 156 | sc_uint <32> RDATA; 157 | sc_uint <2> RRESP; 158 | sc_uint <4> RID; 159 | sc_uint <1> RLAST; 160 | 161 | // Construction 162 | axi4_slave() { init(); } 163 | 164 | void init(void) 165 | { 166 | AWREADY = 0; 167 | WREADY = 0; 168 | BVALID = 0; 169 | BRESP = 0; 170 | BID = 0; 171 | ARREADY = 0; 172 | RVALID = 0; 173 | RDATA = 0; 174 | RRESP = 0; 175 | RID = 0; 176 | RLAST = 0; 177 | } 178 | 179 | bool operator == (const axi4_slave & v) const 180 | { 181 | bool eq = true; 182 | eq &= (AWREADY == v.AWREADY); 183 | eq &= (WREADY == v.WREADY); 184 | eq &= (BVALID == v.BVALID); 185 | eq &= (BRESP == v.BRESP); 186 | eq &= (BID == v.BID); 187 | eq &= (ARREADY == v.ARREADY); 188 | eq &= (RVALID == v.RVALID); 189 | eq &= (RDATA == v.RDATA); 190 | eq &= (RRESP == v.RRESP); 191 | eq &= (RID == v.RID); 192 | eq &= (RLAST == v.RLAST); 193 | return eq; 194 | } 195 | 196 | friend void sc_trace(sc_trace_file *tf, const axi4_slave & v, const std::string & path) 197 | { 198 | sc_trace(tf,v.AWREADY, path + "/awready"); 199 | sc_trace(tf,v.WREADY, path + "/wready"); 200 | sc_trace(tf,v.BVALID, path + "/bvalid"); 201 | sc_trace(tf,v.BRESP, path + "/bresp"); 202 | sc_trace(tf,v.BID, path + "/bid"); 203 | sc_trace(tf,v.ARREADY, path + "/arready"); 204 | sc_trace(tf,v.RVALID, path + "/rvalid"); 205 | sc_trace(tf,v.RDATA, path + "/rdata"); 206 | sc_trace(tf,v.RRESP, path + "/rresp"); 207 | sc_trace(tf,v.RID, path + "/rid"); 208 | sc_trace(tf,v.RLAST, path + "/rlast"); 209 | } 210 | 211 | friend ostream& operator << (ostream& os, axi4_slave const & v) 212 | { 213 | os << hex << "AWREADY: " << v.AWREADY << " "; 214 | os << hex << "WREADY: " << v.WREADY << " "; 215 | os << hex << "BVALID: " << v.BVALID << " "; 216 | os << hex << "BRESP: " << v.BRESP << " "; 217 | os << hex << "BID: " << v.BID << " "; 218 | os << hex << "ARREADY: " << v.ARREADY << " "; 219 | os << hex << "RVALID: " << v.RVALID << " "; 220 | os << hex << "RDATA: " << v.RDATA << " "; 221 | os << hex << "RRESP: " << v.RRESP << " "; 222 | os << hex << "RID: " << v.RID << " "; 223 | os << hex << "RLAST: " << v.RLAST << " "; 224 | return os; 225 | } 226 | 227 | friend istream& operator >> ( istream& is, axi4_slave & val) 228 | { 229 | // Not implemented 230 | return is; 231 | } 232 | }; 233 | 234 | #define MEMBER_COPY_AXI4_SLAVE(s,d) do { \ 235 | s.AWREADY = d.AWREADY; \ 236 | s.WREADY = d.WREADY; \ 237 | s.BVALID = d.BVALID; \ 238 | s.BRESP = d.BRESP; \ 239 | s.BID = d.BID; \ 240 | s.ARREADY = d.ARREADY; \ 241 | s.RVALID = d.RVALID; \ 242 | s.RDATA = d.RDATA; \ 243 | s.RRESP = d.RRESP; \ 244 | s.RID = d.RID; \ 245 | s.RLAST = d.RLAST; \ 246 | } while (0) 247 | 248 | 249 | #endif 250 | -------------------------------------------------------------------------------- /tb/tb_top/axi4.h: -------------------------------------------------------------------------------- 1 | #ifndef AXI4_H 2 | #define AXI4_H 3 | 4 | #include 5 | 6 | //---------------------------------------------------------------- 7 | // Interface (master) 8 | //---------------------------------------------------------------- 9 | class axi4_master 10 | { 11 | public: 12 | // Members 13 | sc_uint <1> AWVALID; 14 | sc_uint <32> AWADDR; 15 | sc_uint <4> AWID; 16 | sc_uint <8> AWLEN; 17 | sc_uint <2> AWBURST; 18 | sc_uint <1> WVALID; 19 | sc_uint <32> WDATA; 20 | sc_uint <4> WSTRB; 21 | sc_uint <1> WLAST; 22 | sc_uint <1> BREADY; 23 | sc_uint <1> ARVALID; 24 | sc_uint <32> ARADDR; 25 | sc_uint <4> ARID; 26 | sc_uint <8> ARLEN; 27 | sc_uint <2> ARBURST; 28 | sc_uint <1> RREADY; 29 | 30 | // Construction 31 | axi4_master() { init(); } 32 | 33 | void init(void) 34 | { 35 | AWVALID = 0; 36 | AWADDR = 0; 37 | AWID = 0; 38 | AWLEN = 0; 39 | AWBURST = 0; 40 | WVALID = 0; 41 | WDATA = 0; 42 | WSTRB = 0; 43 | WLAST = 0; 44 | BREADY = 0; 45 | ARVALID = 0; 46 | ARADDR = 0; 47 | ARID = 0; 48 | ARLEN = 0; 49 | ARBURST = 0; 50 | RREADY = 0; 51 | } 52 | 53 | bool operator == (const axi4_master & v) const 54 | { 55 | bool eq = true; 56 | eq &= (AWVALID == v.AWVALID); 57 | eq &= (AWADDR == v.AWADDR); 58 | eq &= (AWID == v.AWID); 59 | eq &= (AWLEN == v.AWLEN); 60 | eq &= (AWBURST == v.AWBURST); 61 | eq &= (WVALID == v.WVALID); 62 | eq &= (WDATA == v.WDATA); 63 | eq &= (WSTRB == v.WSTRB); 64 | eq &= (WLAST == v.WLAST); 65 | eq &= (BREADY == v.BREADY); 66 | eq &= (ARVALID == v.ARVALID); 67 | eq &= (ARADDR == v.ARADDR); 68 | eq &= (ARID == v.ARID); 69 | eq &= (ARLEN == v.ARLEN); 70 | eq &= (ARBURST == v.ARBURST); 71 | eq &= (RREADY == v.RREADY); 72 | return eq; 73 | } 74 | 75 | friend void sc_trace(sc_trace_file *tf, const axi4_master & v, const std::string & path) 76 | { 77 | sc_trace(tf,v.AWVALID, path + "/awvalid"); 78 | sc_trace(tf,v.AWADDR, path + "/awaddr"); 79 | sc_trace(tf,v.AWID, path + "/awid"); 80 | sc_trace(tf,v.AWLEN, path + "/awlen"); 81 | sc_trace(tf,v.AWBURST, path + "/awburst"); 82 | sc_trace(tf,v.WVALID, path + "/wvalid"); 83 | sc_trace(tf,v.WDATA, path + "/wdata"); 84 | sc_trace(tf,v.WSTRB, path + "/wstrb"); 85 | sc_trace(tf,v.WLAST, path + "/wlast"); 86 | sc_trace(tf,v.BREADY, path + "/bready"); 87 | sc_trace(tf,v.ARVALID, path + "/arvalid"); 88 | sc_trace(tf,v.ARADDR, path + "/araddr"); 89 | sc_trace(tf,v.ARID, path + "/arid"); 90 | sc_trace(tf,v.ARLEN, path + "/arlen"); 91 | sc_trace(tf,v.ARBURST, path + "/arburst"); 92 | sc_trace(tf,v.RREADY, path + "/rready"); 93 | } 94 | 95 | friend ostream& operator << (ostream& os, axi4_master const & v) 96 | { 97 | os << hex << "AWVALID: " << v.AWVALID << " "; 98 | os << hex << "AWADDR: " << v.AWADDR << " "; 99 | os << hex << "AWID: " << v.AWID << " "; 100 | os << hex << "AWLEN: " << v.AWLEN << " "; 101 | os << hex << "AWBURST: " << v.AWBURST << " "; 102 | os << hex << "WVALID: " << v.WVALID << " "; 103 | os << hex << "WDATA: " << v.WDATA << " "; 104 | os << hex << "WSTRB: " << v.WSTRB << " "; 105 | os << hex << "WLAST: " << v.WLAST << " "; 106 | os << hex << "BREADY: " << v.BREADY << " "; 107 | os << hex << "ARVALID: " << v.ARVALID << " "; 108 | os << hex << "ARADDR: " << v.ARADDR << " "; 109 | os << hex << "ARID: " << v.ARID << " "; 110 | os << hex << "ARLEN: " << v.ARLEN << " "; 111 | os << hex << "ARBURST: " << v.ARBURST << " "; 112 | os << hex << "RREADY: " << v.RREADY << " "; 113 | return os; 114 | } 115 | 116 | friend istream& operator >> ( istream& is, axi4_master & val) 117 | { 118 | // Not implemented 119 | return is; 120 | } 121 | }; 122 | 123 | #define MEMBER_COPY_AXI4_MASTER(s,d) do { \ 124 | s.AWVALID = d.AWVALID; \ 125 | s.AWADDR = d.AWADDR; \ 126 | s.AWID = d.AWID; \ 127 | s.AWLEN = d.AWLEN; \ 128 | s.AWBURST = d.AWBURST; \ 129 | s.WVALID = d.WVALID; \ 130 | s.WDATA = d.WDATA; \ 131 | s.WSTRB = d.WSTRB; \ 132 | s.WLAST = d.WLAST; \ 133 | s.BREADY = d.BREADY; \ 134 | s.ARVALID = d.ARVALID; \ 135 | s.ARADDR = d.ARADDR; \ 136 | s.ARID = d.ARID; \ 137 | s.ARLEN = d.ARLEN; \ 138 | s.ARBURST = d.ARBURST; \ 139 | s.RREADY = d.RREADY; \ 140 | } while (0) 141 | 142 | //---------------------------------------------------------------- 143 | // Interface (slave) 144 | //---------------------------------------------------------------- 145 | class axi4_slave 146 | { 147 | public: 148 | // Members 149 | sc_uint <1> AWREADY; 150 | sc_uint <1> WREADY; 151 | sc_uint <1> BVALID; 152 | sc_uint <2> BRESP; 153 | sc_uint <4> BID; 154 | sc_uint <1> ARREADY; 155 | sc_uint <1> RVALID; 156 | sc_uint <32> RDATA; 157 | sc_uint <2> RRESP; 158 | sc_uint <4> RID; 159 | sc_uint <1> RLAST; 160 | 161 | // Construction 162 | axi4_slave() { init(); } 163 | 164 | void init(void) 165 | { 166 | AWREADY = 0; 167 | WREADY = 0; 168 | BVALID = 0; 169 | BRESP = 0; 170 | BID = 0; 171 | ARREADY = 0; 172 | RVALID = 0; 173 | RDATA = 0; 174 | RRESP = 0; 175 | RID = 0; 176 | RLAST = 0; 177 | } 178 | 179 | bool operator == (const axi4_slave & v) const 180 | { 181 | bool eq = true; 182 | eq &= (AWREADY == v.AWREADY); 183 | eq &= (WREADY == v.WREADY); 184 | eq &= (BVALID == v.BVALID); 185 | eq &= (BRESP == v.BRESP); 186 | eq &= (BID == v.BID); 187 | eq &= (ARREADY == v.ARREADY); 188 | eq &= (RVALID == v.RVALID); 189 | eq &= (RDATA == v.RDATA); 190 | eq &= (RRESP == v.RRESP); 191 | eq &= (RID == v.RID); 192 | eq &= (RLAST == v.RLAST); 193 | return eq; 194 | } 195 | 196 | friend void sc_trace(sc_trace_file *tf, const axi4_slave & v, const std::string & path) 197 | { 198 | sc_trace(tf,v.AWREADY, path + "/awready"); 199 | sc_trace(tf,v.WREADY, path + "/wready"); 200 | sc_trace(tf,v.BVALID, path + "/bvalid"); 201 | sc_trace(tf,v.BRESP, path + "/bresp"); 202 | sc_trace(tf,v.BID, path + "/bid"); 203 | sc_trace(tf,v.ARREADY, path + "/arready"); 204 | sc_trace(tf,v.RVALID, path + "/rvalid"); 205 | sc_trace(tf,v.RDATA, path + "/rdata"); 206 | sc_trace(tf,v.RRESP, path + "/rresp"); 207 | sc_trace(tf,v.RID, path + "/rid"); 208 | sc_trace(tf,v.RLAST, path + "/rlast"); 209 | } 210 | 211 | friend ostream& operator << (ostream& os, axi4_slave const & v) 212 | { 213 | os << hex << "AWREADY: " << v.AWREADY << " "; 214 | os << hex << "WREADY: " << v.WREADY << " "; 215 | os << hex << "BVALID: " << v.BVALID << " "; 216 | os << hex << "BRESP: " << v.BRESP << " "; 217 | os << hex << "BID: " << v.BID << " "; 218 | os << hex << "ARREADY: " << v.ARREADY << " "; 219 | os << hex << "RVALID: " << v.RVALID << " "; 220 | os << hex << "RDATA: " << v.RDATA << " "; 221 | os << hex << "RRESP: " << v.RRESP << " "; 222 | os << hex << "RID: " << v.RID << " "; 223 | os << hex << "RLAST: " << v.RLAST << " "; 224 | return os; 225 | } 226 | 227 | friend istream& operator >> ( istream& is, axi4_slave & val) 228 | { 229 | // Not implemented 230 | return is; 231 | } 232 | }; 233 | 234 | #define MEMBER_COPY_AXI4_SLAVE(s,d) do { \ 235 | s.AWREADY = d.AWREADY; \ 236 | s.WREADY = d.WREADY; \ 237 | s.BVALID = d.BVALID; \ 238 | s.BRESP = d.BRESP; \ 239 | s.BID = d.BID; \ 240 | s.ARREADY = d.ARREADY; \ 241 | s.RVALID = d.RVALID; \ 242 | s.RDATA = d.RDATA; \ 243 | s.RRESP = d.RRESP; \ 244 | s.RID = d.RID; \ 245 | s.RLAST = d.RLAST; \ 246 | } while (0) 247 | 248 | 249 | #endif 250 | -------------------------------------------------------------------------------- /tb/tb_top/riscv_top.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "riscv_top.h" 3 | #include "Vriscv_top.h" 4 | 5 | #if VM_TRACE 6 | #include "verilated.h" 7 | #include "verilated_vcd_c.h" 8 | #endif 9 | 10 | //------------------------------------------------------------- 11 | // Constructor 12 | //------------------------------------------------------------- 13 | riscv_top::riscv_top(sc_module_name name): sc_module(name) 14 | { 15 | m_rtl = new Vriscv_top("Vriscv_top"); 16 | m_rtl->clk_i(m_clk_in); 17 | m_rtl->rst_i(m_rst_in); 18 | m_rtl->axi_i_awready_i(m_axi_i_awready_in); 19 | m_rtl->axi_i_wready_i(m_axi_i_wready_in); 20 | m_rtl->axi_i_bvalid_i(m_axi_i_bvalid_in); 21 | m_rtl->axi_i_bresp_i(m_axi_i_bresp_in); 22 | m_rtl->axi_i_bid_i(m_axi_i_bid_in); 23 | m_rtl->axi_i_arready_i(m_axi_i_arready_in); 24 | m_rtl->axi_i_rvalid_i(m_axi_i_rvalid_in); 25 | m_rtl->axi_i_rdata_i(m_axi_i_rdata_in); 26 | m_rtl->axi_i_rresp_i(m_axi_i_rresp_in); 27 | m_rtl->axi_i_rid_i(m_axi_i_rid_in); 28 | m_rtl->axi_i_rlast_i(m_axi_i_rlast_in); 29 | m_rtl->axi_d_awready_i(m_axi_d_awready_in); 30 | m_rtl->axi_d_wready_i(m_axi_d_wready_in); 31 | m_rtl->axi_d_bvalid_i(m_axi_d_bvalid_in); 32 | m_rtl->axi_d_bresp_i(m_axi_d_bresp_in); 33 | m_rtl->axi_d_bid_i(m_axi_d_bid_in); 34 | m_rtl->axi_d_arready_i(m_axi_d_arready_in); 35 | m_rtl->axi_d_rvalid_i(m_axi_d_rvalid_in); 36 | m_rtl->axi_d_rdata_i(m_axi_d_rdata_in); 37 | m_rtl->axi_d_rresp_i(m_axi_d_rresp_in); 38 | m_rtl->axi_d_rid_i(m_axi_d_rid_in); 39 | m_rtl->axi_d_rlast_i(m_axi_d_rlast_in); 40 | m_rtl->intr_i(m_intr_in); 41 | m_rtl->reset_vector_i(m_reset_vector_in); 42 | m_rtl->axi_i_awvalid_o(m_axi_i_awvalid_out); 43 | m_rtl->axi_i_awaddr_o(m_axi_i_awaddr_out); 44 | m_rtl->axi_i_awid_o(m_axi_i_awid_out); 45 | m_rtl->axi_i_awlen_o(m_axi_i_awlen_out); 46 | m_rtl->axi_i_awburst_o(m_axi_i_awburst_out); 47 | m_rtl->axi_i_wvalid_o(m_axi_i_wvalid_out); 48 | m_rtl->axi_i_wdata_o(m_axi_i_wdata_out); 49 | m_rtl->axi_i_wstrb_o(m_axi_i_wstrb_out); 50 | m_rtl->axi_i_wlast_o(m_axi_i_wlast_out); 51 | m_rtl->axi_i_bready_o(m_axi_i_bready_out); 52 | m_rtl->axi_i_arvalid_o(m_axi_i_arvalid_out); 53 | m_rtl->axi_i_araddr_o(m_axi_i_araddr_out); 54 | m_rtl->axi_i_arid_o(m_axi_i_arid_out); 55 | m_rtl->axi_i_arlen_o(m_axi_i_arlen_out); 56 | m_rtl->axi_i_arburst_o(m_axi_i_arburst_out); 57 | m_rtl->axi_i_rready_o(m_axi_i_rready_out); 58 | m_rtl->axi_d_awvalid_o(m_axi_d_awvalid_out); 59 | m_rtl->axi_d_awaddr_o(m_axi_d_awaddr_out); 60 | m_rtl->axi_d_awid_o(m_axi_d_awid_out); 61 | m_rtl->axi_d_awlen_o(m_axi_d_awlen_out); 62 | m_rtl->axi_d_awburst_o(m_axi_d_awburst_out); 63 | m_rtl->axi_d_wvalid_o(m_axi_d_wvalid_out); 64 | m_rtl->axi_d_wdata_o(m_axi_d_wdata_out); 65 | m_rtl->axi_d_wstrb_o(m_axi_d_wstrb_out); 66 | m_rtl->axi_d_wlast_o(m_axi_d_wlast_out); 67 | m_rtl->axi_d_bready_o(m_axi_d_bready_out); 68 | m_rtl->axi_d_arvalid_o(m_axi_d_arvalid_out); 69 | m_rtl->axi_d_araddr_o(m_axi_d_araddr_out); 70 | m_rtl->axi_d_arid_o(m_axi_d_arid_out); 71 | m_rtl->axi_d_arlen_o(m_axi_d_arlen_out); 72 | m_rtl->axi_d_arburst_o(m_axi_d_arburst_out); 73 | m_rtl->axi_d_rready_o(m_axi_d_rready_out); 74 | 75 | SC_METHOD(async_outputs); 76 | sensitive << clk_in; 77 | sensitive << rst_in; 78 | sensitive << intr_in; 79 | sensitive << reset_vector_in; 80 | sensitive << axi_i_in; 81 | sensitive << axi_d_in; 82 | sensitive << m_axi_i_awvalid_out; 83 | sensitive << m_axi_i_awaddr_out; 84 | sensitive << m_axi_i_awid_out; 85 | sensitive << m_axi_i_awlen_out; 86 | sensitive << m_axi_i_awburst_out; 87 | sensitive << m_axi_i_wvalid_out; 88 | sensitive << m_axi_i_wdata_out; 89 | sensitive << m_axi_i_wstrb_out; 90 | sensitive << m_axi_i_wlast_out; 91 | sensitive << m_axi_i_bready_out; 92 | sensitive << m_axi_i_arvalid_out; 93 | sensitive << m_axi_i_araddr_out; 94 | sensitive << m_axi_i_arid_out; 95 | sensitive << m_axi_i_arlen_out; 96 | sensitive << m_axi_i_arburst_out; 97 | sensitive << m_axi_i_rready_out; 98 | sensitive << m_axi_d_awvalid_out; 99 | sensitive << m_axi_d_awaddr_out; 100 | sensitive << m_axi_d_awid_out; 101 | sensitive << m_axi_d_awlen_out; 102 | sensitive << m_axi_d_awburst_out; 103 | sensitive << m_axi_d_wvalid_out; 104 | sensitive << m_axi_d_wdata_out; 105 | sensitive << m_axi_d_wstrb_out; 106 | sensitive << m_axi_d_wlast_out; 107 | sensitive << m_axi_d_bready_out; 108 | sensitive << m_axi_d_arvalid_out; 109 | sensitive << m_axi_d_araddr_out; 110 | sensitive << m_axi_d_arid_out; 111 | sensitive << m_axi_d_arlen_out; 112 | sensitive << m_axi_d_arburst_out; 113 | sensitive << m_axi_d_rready_out; 114 | 115 | #if VM_TRACE 116 | m_vcd = NULL; 117 | m_delay_waves = false; 118 | #endif 119 | } 120 | //------------------------------------------------------------- 121 | // trace_enable 122 | //------------------------------------------------------------- 123 | void riscv_top::trace_enable(VerilatedVcdC * p) 124 | { 125 | #if VM_TRACE 126 | m_vcd = p; 127 | m_rtl->trace (m_vcd, 99); 128 | #endif 129 | } 130 | void riscv_top::trace_enable(VerilatedVcdC *p, sc_core::sc_time start_time) 131 | { 132 | #if VM_TRACE 133 | m_vcd = p; 134 | m_delay_waves = true; 135 | m_waves_start = start_time; 136 | //m_rtl->trace (m_vcd, 99); 137 | #endif 138 | } 139 | //------------------------------------------------------------- 140 | // async_outputs 141 | //------------------------------------------------------------- 142 | void riscv_top::async_outputs(void) 143 | { 144 | m_clk_in.write(clk_in.read()); 145 | m_rst_in.write(rst_in.read()); 146 | m_intr_in.write(intr_in.read()); 147 | m_reset_vector_in.write(reset_vector_in.read()); 148 | 149 | axi4_slave axi_i_i = axi_i_in.read(); 150 | m_axi_i_awready_in.write(axi_i_i.AWREADY); 151 | m_axi_i_wready_in.write(axi_i_i.WREADY); 152 | m_axi_i_bvalid_in.write(axi_i_i.BVALID); 153 | m_axi_i_bresp_in.write(axi_i_i.BRESP); 154 | m_axi_i_bid_in.write(axi_i_i.BID); 155 | m_axi_i_arready_in.write(axi_i_i.ARREADY); 156 | m_axi_i_rvalid_in.write(axi_i_i.RVALID); 157 | m_axi_i_rdata_in.write(axi_i_i.RDATA); 158 | m_axi_i_rresp_in.write(axi_i_i.RRESP); 159 | m_axi_i_rid_in.write(axi_i_i.RID); 160 | m_axi_i_rlast_in.write(axi_i_i.RLAST); 161 | 162 | 163 | axi4_master axi_i_o; 164 | axi_i_o.AWVALID = m_axi_i_awvalid_out.read(); 165 | axi_i_o.AWADDR = m_axi_i_awaddr_out.read(); 166 | axi_i_o.AWID = m_axi_i_awid_out.read(); 167 | axi_i_o.AWLEN = m_axi_i_awlen_out.read(); 168 | axi_i_o.AWBURST = m_axi_i_awburst_out.read(); 169 | axi_i_o.WVALID = m_axi_i_wvalid_out.read(); 170 | axi_i_o.WDATA = m_axi_i_wdata_out.read(); 171 | axi_i_o.WSTRB = m_axi_i_wstrb_out.read(); 172 | axi_i_o.WLAST = m_axi_i_wlast_out.read(); 173 | axi_i_o.BREADY = m_axi_i_bready_out.read(); 174 | axi_i_o.ARVALID = m_axi_i_arvalid_out.read(); 175 | axi_i_o.ARADDR = m_axi_i_araddr_out.read(); 176 | axi_i_o.ARID = m_axi_i_arid_out.read(); 177 | axi_i_o.ARLEN = m_axi_i_arlen_out.read(); 178 | axi_i_o.ARBURST = m_axi_i_arburst_out.read(); 179 | axi_i_o.RREADY = m_axi_i_rready_out.read(); 180 | axi_i_out.write(axi_i_o); 181 | axi4_slave axi_d_i = axi_d_in.read(); 182 | m_axi_d_awready_in.write(axi_d_i.AWREADY); 183 | m_axi_d_wready_in.write(axi_d_i.WREADY); 184 | m_axi_d_bvalid_in.write(axi_d_i.BVALID); 185 | m_axi_d_bresp_in.write(axi_d_i.BRESP); 186 | m_axi_d_bid_in.write(axi_d_i.BID); 187 | m_axi_d_arready_in.write(axi_d_i.ARREADY); 188 | m_axi_d_rvalid_in.write(axi_d_i.RVALID); 189 | m_axi_d_rdata_in.write(axi_d_i.RDATA); 190 | m_axi_d_rresp_in.write(axi_d_i.RRESP); 191 | m_axi_d_rid_in.write(axi_d_i.RID); 192 | m_axi_d_rlast_in.write(axi_d_i.RLAST); 193 | 194 | 195 | axi4_master axi_d_o; 196 | axi_d_o.AWVALID = m_axi_d_awvalid_out.read(); 197 | axi_d_o.AWADDR = m_axi_d_awaddr_out.read(); 198 | axi_d_o.AWID = m_axi_d_awid_out.read(); 199 | axi_d_o.AWLEN = m_axi_d_awlen_out.read(); 200 | axi_d_o.AWBURST = m_axi_d_awburst_out.read(); 201 | axi_d_o.WVALID = m_axi_d_wvalid_out.read(); 202 | axi_d_o.WDATA = m_axi_d_wdata_out.read(); 203 | axi_d_o.WSTRB = m_axi_d_wstrb_out.read(); 204 | axi_d_o.WLAST = m_axi_d_wlast_out.read(); 205 | axi_d_o.BREADY = m_axi_d_bready_out.read(); 206 | axi_d_o.ARVALID = m_axi_d_arvalid_out.read(); 207 | axi_d_o.ARADDR = m_axi_d_araddr_out.read(); 208 | axi_d_o.ARID = m_axi_d_arid_out.read(); 209 | axi_d_o.ARLEN = m_axi_d_arlen_out.read(); 210 | axi_d_o.ARBURST = m_axi_d_arburst_out.read(); 211 | axi_d_o.RREADY = m_axi_d_rready_out.read(); 212 | axi_d_out.write(axi_d_o); 213 | 214 | } 215 | --------------------------------------------------------------------------------