From cb0be9e2039569ee7d18657e8f675d1f8369b407 Mon Sep 17 00:00:00 2001 From: Flavian Kaufmann Date: Tue, 21 May 2024 13:50:28 +0200 Subject: restructured project --- Makefile | 194 ++++++------------------ README.md | 48 ++++-- cst/tangnano9k.cst | 38 ----- gentestvec/gentestvec_alu.c | 117 --------------- gentestvec/gentestvec_cpu.c | 6 - gentestvec/gentestvec_register_file.c | 49 ------ include/consts.vh | 129 ---------------- include/log2.vh | 12 -- prog/Makefile | 65 ++++++++ rtl/Makefile | 56 +++++++ rtl/cst/tangnano9k.cst | 38 +++++ rtl/include/consts.vh | 129 ++++++++++++++++ rtl/include/log2.vh | 12 ++ rtl/src/alu.v | 47 ++++++ rtl/src/alu_a_src_mux.v | 25 ++++ rtl/src/alu_b_src_mux.v | 21 +++ rtl/src/alu_op_decode.v | 43 ++++++ rtl/src/alu_result_reg.v | 14 ++ rtl/src/arithmetic_unit.v | 27 ++++ rtl/src/clock_divider.v | 29 ++++ rtl/src/control_unit.v | 207 ++++++++++++++++++++++++++ rtl/src/cpu.v | 172 +++++++++++++++++++++ rtl/src/data_reg.v | 14 ++ rtl/src/immediate_extend.v | 22 +++ rtl/src/instruction_reg.v | 20 +++ rtl/src/io.v | 30 ++++ rtl/src/logic_unit.v | 21 +++ rtl/src/mem_addr_src_mux.v | 20 +++ rtl/src/memory_interface.v | 84 +++++++++++ rtl/src/pc_reg.v | 18 +++ rtl/src/ram.v | 23 +++ rtl/src/register_file.v | 93 ++++++++++++ rtl/src/register_file_reg.v | 22 +++ rtl/src/reset_synchronizer.v | 16 ++ rtl/src/result_mux.v | 22 +++ rtl/src/rom.v | 25 ++++ rtl/src/shift_unit.v | 21 +++ rtl/src/top.v | 38 +++++ sim/gentestvec/Makefile | 33 ++++ sim/gentestvec/src/alu.c | 117 +++++++++++++++ sim/gentestvec/src/cpu.c | 6 + sim/gentestvec/src/register_file.c | 49 ++++++ sim/testbench_alu.v | 84 ----------- sim/testbench_cpu.v | 68 --------- sim/testbench_register_file.v | 111 -------------- sim/testbenches/Makefile | 42 ++++++ sim/testbenches/src/testbench_alu.v | 84 +++++++++++ sim/testbenches/src/testbench_cpu.v | 68 +++++++++ sim/testbenches/src/testbench_register_file.v | 111 ++++++++++++++ src/alu.v | 47 ------ src/alu_a_src_mux.v | 25 ---- src/alu_b_src_mux.v | 21 --- src/alu_op_decode.v | 43 ------ src/alu_result_reg.v | 14 -- src/arithmetic_unit.v | 27 ---- src/clock_divider.v | 29 ---- src/control_unit.v | 207 -------------------------- src/cpu.v | 172 --------------------- src/data_reg.v | 14 -- src/immediate_extend.v | 22 --- src/instruction_reg.v | 20 --- src/io.v | 30 ---- src/logic_unit.v | 21 --- src/mem_addr_src_mux.v | 20 --- src/memory_interface.v | 84 ----------- src/pc_reg.v | 18 --- src/ram.v | 23 --- src/register_file.v | 93 ------------ src/register_file_reg.v | 22 --- src/reset_synchronizer.v | 22 --- src/result_mux.v | 22 --- src/rom.v | 24 --- src/shift_unit.v | 21 --- src/top.v | 38 ----- 74 files changed, 1965 insertions(+), 1854 deletions(-) delete mode 100644 cst/tangnano9k.cst delete mode 100644 gentestvec/gentestvec_alu.c delete mode 100644 gentestvec/gentestvec_cpu.c delete mode 100644 gentestvec/gentestvec_register_file.c delete mode 100644 include/consts.vh delete mode 100644 include/log2.vh create mode 100644 prog/Makefile create mode 100644 rtl/Makefile create mode 100644 rtl/cst/tangnano9k.cst create mode 100644 rtl/include/consts.vh create mode 100644 rtl/include/log2.vh create mode 100644 rtl/src/alu.v create mode 100644 rtl/src/alu_a_src_mux.v create mode 100644 rtl/src/alu_b_src_mux.v create mode 100644 rtl/src/alu_op_decode.v create mode 100644 rtl/src/alu_result_reg.v create mode 100644 rtl/src/arithmetic_unit.v create mode 100644 rtl/src/clock_divider.v create mode 100644 rtl/src/control_unit.v create mode 100644 rtl/src/cpu.v create mode 100644 rtl/src/data_reg.v create mode 100644 rtl/src/immediate_extend.v create mode 100644 rtl/src/instruction_reg.v create mode 100644 rtl/src/io.v create mode 100644 rtl/src/logic_unit.v create mode 100644 rtl/src/mem_addr_src_mux.v create mode 100644 rtl/src/memory_interface.v create mode 100644 rtl/src/pc_reg.v create mode 100644 rtl/src/ram.v create mode 100644 rtl/src/register_file.v create mode 100644 rtl/src/register_file_reg.v create mode 100644 rtl/src/reset_synchronizer.v create mode 100644 rtl/src/result_mux.v create mode 100644 rtl/src/rom.v create mode 100644 rtl/src/shift_unit.v create mode 100644 rtl/src/top.v create mode 100644 sim/gentestvec/Makefile create mode 100644 sim/gentestvec/src/alu.c create mode 100644 sim/gentestvec/src/cpu.c create mode 100644 sim/gentestvec/src/register_file.c delete mode 100644 sim/testbench_alu.v delete mode 100644 sim/testbench_cpu.v delete mode 100644 sim/testbench_register_file.v create mode 100644 sim/testbenches/Makefile create mode 100644 sim/testbenches/src/testbench_alu.v create mode 100644 sim/testbenches/src/testbench_cpu.v create mode 100644 sim/testbenches/src/testbench_register_file.v delete mode 100644 src/alu.v delete mode 100644 src/alu_a_src_mux.v delete mode 100644 src/alu_b_src_mux.v delete mode 100644 src/alu_op_decode.v delete mode 100644 src/alu_result_reg.v delete mode 100644 src/arithmetic_unit.v delete mode 100644 src/clock_divider.v delete mode 100644 src/control_unit.v delete mode 100644 src/cpu.v delete mode 100644 src/data_reg.v delete mode 100644 src/immediate_extend.v delete mode 100644 src/instruction_reg.v delete mode 100644 src/io.v delete mode 100644 src/logic_unit.v delete mode 100644 src/mem_addr_src_mux.v delete mode 100644 src/memory_interface.v delete mode 100644 src/pc_reg.v delete mode 100644 src/ram.v delete mode 100644 src/register_file.v delete mode 100644 src/register_file_reg.v delete mode 100644 src/reset_synchronizer.v delete mode 100644 src/result_mux.v delete mode 100644 src/rom.v delete mode 100644 src/shift_unit.v delete mode 100644 src/top.v diff --git a/Makefile b/Makefile index e5a37b7..3087ffa 100644 --- a/Makefile +++ b/Makefile @@ -1,171 +1,61 @@ -PRJ_NAME = riscv_cpu -TOP_MODULE = top - -# Directories -SRC_DIR = src -SIM_DIR = sim -GENTESTVEC_DIR = gentestvec -CST_DIR = cst BUILD_DIR = build -# Source Files -SRC_FILES = $(wildcard $(SRC_DIR)/*.v) -SIM_FILES = $(wildcard $(SIM_DIR)/testbench_*.v) -GENTESTVEC_FILES = $(wildcard $(GENTESTVEC_DIR)/gentestvec_*.c) -CST_FILES = $(wildcard $(CST_DIR)/*.cst) +# dirs +PROG_DIR = prog +GENTESTVEC_DIR = sim/gentestvec +TESTBENCH_DIR = sim/testbenches +RTL_DIR = rtl -# Output Files -SIM_EXECUTABLES = $(patsubst $(SIM_DIR)/testbench_%.v, $(BUILD_DIR)/testbench_%,$(SIM_FILES)) -GENTESTVEC_EXECUTABLES = $(patsubst $(GENTESTVEC_DIR)/gentestvec_%.c, $(BUILD_DIR)/gentestvec_%,$(GENTESTVEC_FILES)) -TESTVECTOR_FILES = $(patsubst $(BUILD_DIR)/gentestvec_%, $(BUILD_DIR)/testvec_%.txt, $(GENTESTVEC_EXECUTABLES)) -WAVEFORM_FILES = $(patsubst $(BUILD_DIR)/testbench_%, $(BUILD_DIR)/waveform_%.vcd, $(SIM_EXECUTABLES)) +# tools +MAKE = make -BITSTREAM = $(BUILD_DIR)/$(PRJ_NAME).fs +all: simulate -# Programs -CC = clang -CFLAGS = -O3 +# generate rom +rom: + $(MAKE) -C $(PROG_DIR) BUILD_DIR=../$(BUILD_DIR) all -IVERILOG = iverilog -VVP = vvp -GTKWAVE = gtkwave +# print objdump of rom +objdump: + $(MAKE) -C $(PROG_DIR) BUILD_DIR=../$(BUILD_DIR) objdump -YOSYS = yosys -NEXTPNR = nextpnr-himbaechel -GOWIN_PACK = gowin_pack -PROGRAMMER = openFPGALoader +# print size information of rom +size: + $(MAKE) -C $(PROG_DIR) BUILD_DIR=../$(BUILD_DIR) size -FAMILY = GW1N-9C -DEVICE = GW1NR-LV9QN88PC6/I5 -BOARD = tangnano9k -# RISCV Toolchain -RISCV_TOOLCHAIN = riscv64-unknown-elf -RISCV_AS = $(RISCV_TOOLCHAIN)-as -RISCV_CC = $(RISCV_TOOLCHAIN)-gcc -RISCV_LD = $(RISCV_TOOLCHAIN)-ld -RISCV_OBJCOPY = $(RISCV_TOOLCHAIN)-objcopy -RISCV_OBJDUMP = $(RISCV_TOOLCHAIN)-objdump -RISCV_ASFLAGS = -march=rv32i -mabi=ilp32 -RISCV_CFLAGS = -march=rv32i -mabi=ilp32 -RISCV_LDFLAGS = -T prog/link.ld -m elf32lriscv +# generate testvec files +testvec: + $(MAKE) -C $(GENTESTVEC_DIR) BUILD_DIR=../../$(BUILD_DIR) all -PROG_SOURCE_DIR = prog/src -PROG_ASSEMBLY_SOURCES = $(wildcard $(PROG_SOURCE_DIR)/*.s) -PROG_C_SOURCES = $(wildcard $(PROG_SOURCE_DIR)/*.c) -PROG_OBJECT_FILES = $(PROG_ASSEMBLY_SOURCES:$(PROG_SOURCE_DIR)/%.s=$(BUILD_DIR)/%.o) $(PROG_C_SOURCES:$(PROG_SOURCE_DIR)/%.c=$(BUILD_DIR)/%.o) -PROG_ELF_FILE = $(BUILD_DIR)/prog.elf -PROG_BINARY_FILE = $(BUILD_DIR)/prog.bin -PROG_ROM_FILE = $(BUILD_DIR)/rom.hex +# run testbenches (simulate) +simulate: rom testvec + $(MAKE) -C $(TESTBENCH_DIR) BUILD_DIR=../../$(BUILD_DIR) all + +# display waveform of cpu testbench +wave: rom testvec + $(MAKE) -C $(TESTBENCH_DIR) BUILD_DIR=../../$(BUILD_DIR) wave + + + +# generate bitstream +bitstream: rom + $(MAKE) -C $(RTL_DIR) BUILD_DIR=../$(BUILD_DIR) all + +# upload bitstream +upload: rom + $(MAKE) -C $(RTL_DIR) BUILD_DIR=../$(BUILD_DIR) upload + +# flash bitstream +flash: rom + $(MAKE) -C $(RTL_DIR) BUILD_DIR=../$(BUILD_DIR) flash -all: simulate -$(BUILD_DIR)/$(PRJ_NAME).json: $(SRC_FILES) | $(BUILD_DIR) - @echo - @echo "==================================================" - @echo " Synthesizing" - @echo "==================================================" - $(YOSYS) -p "synth_gowin -top $(TOP_MODULE)" -o $(BUILD_DIR)/$(PRJ_NAME).json $(SRC_FILES) - @echo "==================================================" - @echo " Completed Synthesis" - @echo "==================================================" - @echo - -$(BUILD_DIR)/$(PRJ_NAME)_pnr.json: $(BUILD_DIR)/$(PRJ_NAME).json $(CST_FILES) - @echo - @echo "===================================================" - @echo " Routing" - @echo "===================================================" - $(NEXTPNR) --json $(BUILD_DIR)/$(PRJ_NAME).json --write $(BUILD_DIR)/$(PRJ_NAME)_pnr.json --device $(DEVICE) --vopt family=$(FAMILY) --vopt cst=$(CST_FILES) - @echo "===================================================" - @echo " Completed Routing" - @echo "===================================================" - @echo - -$(BITSTREAM): $(BUILD_DIR)/$(PRJ_NAME)_pnr.json - @echo - @echo "===================================================" - @echo " Generating Bitstream" - @echo "===================================================" - $(GOWIN_PACK) -d $(FAMILY) -o $(BITSTREAM) $(BUILD_DIR)/$(PRJ_NAME)_pnr.json - @echo "===================================================" - @echo " Generated Bitstream" - @echo "===================================================" - @echo - -bitstream: $(BITSTREAM) - -upload: $(BITSTREAM) - $(PROGRAMMER) -b $(BOARD) $(BITSTREAM) - -flash: $(BITSTREAM) - $(PROGRAMMER) -b $(BOARD) -f $(BITSTREAM) - -simulate: $(WAVEFORM_FILES) - -# Build the testbench executables -$(BUILD_DIR)/testbench_%: $(SIM_DIR)/testbench_%.v $(SRC_FILES) | $(BUILD_DIR) $(PROG_ROM_FILE) - $(IVERILOG) -o $@ $^ - -# Build the test vector generator executables -$(BUILD_DIR)/gentestvec_%: $(GENTESTVEC_DIR)/gentestvec_%.c | $(BUILD_DIR) - $(CC) $(CFLAGS) -o $@ $< - -# Generate the test vector files -$(BUILD_DIR)/testvec_%.txt: $(BUILD_DIR)/gentestvec_% - $< > $@ - -# Run the simulation and generate the waveform files -$(BUILD_DIR)/waveform_%.vcd: $(BUILD_DIR)/testbench_% $(BUILD_DIR)/testvec_%.txt - @echo - @echo "===================================================" - @echo " Running Testbench ($*)" - @echo "===================================================" - $(VVP) $< +testvec=$(BUILD_DIR)/testvec_$*.txt +waveform=$@ - @echo "===================================================" - @echo " Completed Testbench ($*)" - @echo "===================================================" - @echo - -rom: $(PROG_ROM_FILE) - -# Assemble assembly source files into object files -$(BUILD_DIR)/%.o: $(PROG_SOURCE_DIR)/%.s | $(BUILD_DIR) - $(RISCV_AS) $(RISCV_ASFLAGS) -o $@ $< - -# Compile C source files into object files -$(BUILD_DIR)/%.o: $(PROG_SOURCE_DIR)/%.c | $(BUILD_DIR) - $(RISCV_CC) $(RISCV_CFLAGS) -c -o $@ $< - -# Link the object files to create an ELF file -$(PROG_ELF_FILE): $(PROG_OBJECT_FILES) - $(RISCV_LD) $(RISCV_LDFLAGS) -o $@ $^ - -# Convert the ELF file to a binary file -$(PROG_BINARY_FILE): $(PROG_ELF_FILE) - $(RISCV_OBJCOPY) -O binary $< $@ - -# Convert the binary file to a hex file -$(PROG_ROM_FILE): $(PROG_BINARY_FILE) - xxd -g 4 -c 4 -p $< | awk '{print substr($$0,7,2) substr($$0,5,2) substr($$0,3,2) substr($$0,1,2)}' > $@ - -# Create the build directory -$(BUILD_DIR): - mkdir -p $(BUILD_DIR) - -wave: - $(GTKWAVE) -a debug/cpu.gtkw $(BUILD_DIR)/waveform_cpu.vcd - -objdump: $(PROG_ELF_FILE) - $(RISCV_OBJDUMP) -d -x --disassembler-color=on $(PROG_ELF_FILE) - -# Clean clean: rm -rf $(BUILD_DIR) -.PHONY: all simulate rom bitsream upload flash wave objdump clean - +.PHONY: all clean rom rom_objdump rom_size testvec simulate wave bitstream upload flash \ No newline at end of file diff --git a/README.md b/README.md index 75001f9..7f42392 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,45 @@ The board used in this project is a [Tang Nano 9K](https://wiki.sipeed.com/hardw ## Build * `make all` alias for `make simulate`. -* `make simulate` to run all the testbenches (sim/testbench_*.v). -* `make bitstream` to synthesize, place and route the design and to generate the bitstream. -* `make upload` to upload the bitstream to the FPGA. -* `make flash` to flash the bitsream to the FPGA. -* `make clean` to clean build files. -* `gtkwave build/waveform_*.vcd` to view waveform of corresponding testbench. -* `make rom` to compile source files in prog/src, link and generate rom file. -* `make objdump` to disassemble rom file. -* `make wave` to view waveform of cpu running build/rom.hex. +* `make rom` to build rom. +* `make objdump` to disassemble rom. +* `make size` to display size information of rom. +* `make testvec` to generate testvectors. +* `make simulate` to run testbenches. +* `make wave` to view waveform of cpu testbench in gtkwave. +* `make bitstream` to generate bitstream. +* `make upload` to upload bitstream to fpga. +* `make flash` to flash bitstream to fpga. +* `make clean` to clean build folder. + +## Project Structure + +```(txt) +riscv_cpu + |-> build # build folder + |-> debug + |-> cpu.gtkw # template for gtkwave + |-> prog + |-> include + |-> src + |-> link.ld + |-> Makefile + |-> res # various resources + |-> rtl # rtl sources (verilog files) + |-> cst # constraints file for fpga + |-> include + |-> src + |-> Makefile + |-> sim + |-> gentestvec # generate testvectors for testbenches + |-> src + |-> Makefile + |-> testbenches # testbench sources + |-> src + |-> Makefile + |-> Makefile + |-> README.md +``` ## Tools diff --git a/cst/tangnano9k.cst b/cst/tangnano9k.cst deleted file mode 100644 index e909e36..0000000 --- a/cst/tangnano9k.cst +++ /dev/null @@ -1,38 +0,0 @@ -//Part Number: GW1NR-LV9QN88PC6/I5 - -IO_LOC "clk" 52; -IO_LOC "led[0]" 10; -IO_LOC "led[1]" 11; -IO_LOC "led[2]" 13; -IO_LOC "led[3]" 14; -IO_LOC "led[4]" 15; -IO_LOC "led[5]" 16; -IO_LOC "key" 3; -IO_LOC "rst" 4; - -IO_LOC "LCD_B[0]" 54; -IO_LOC "LCD_B[1]" 53; -IO_LOC "LCD_B[2]" 51; -IO_LOC "LCD_B[3]" 42; -IO_LOC "LCD_B[4]" 41; -IO_LOC "LCD_CLK" 35; -IO_LOC "LCD_DEN" 33; -IO_LOC "LCD_G[0]" 70; -IO_LOC "LCD_G[1]" 69; -IO_LOC "LCD_G[2]" 68; -IO_LOC "LCD_G[3]" 57; -IO_LOC "LCD_G[4]" 56; -IO_LOC "LCD_G[5]" 55; -IO_LOC "LCD_HYNC" 40; -IO_LOC "LCD_R[0]" 75; -IO_LOC "LCD_R[1]" 74; -IO_LOC "LCD_R[2]" 73; -IO_LOC "LCD_R[3]" 72; -IO_LOC "LCD_R[4]" 71; -IO_LOC "LCD_SYNC" 34; -IO_LOC "LCD_XR" 32; -IO_LOC "LCD_XL" 39; - - -// true LVDS pins -IO_LOC "tlvds_p" 25,26; diff --git a/gentestvec/gentestvec_alu.c b/gentestvec/gentestvec_alu.c deleted file mode 100644 index 4a11a74..0000000 --- a/gentestvec/gentestvec_alu.c +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include -#include -#include - -typedef enum { - ADD = 0b0000, - SUB = 0b0001, - SLT = 0b0010, - SLTU = 0b0011, - - AND = 0b0100, - OR = 0b0101, - XOR = 0b0110, - - SLL = 0b1000, - SRL = 0b1001, - SRA = 0b1011, -} OP; - -void test_op(OP op, uint32_t a, uint32_t b) { - uint32_t result; - bool zero; - - switch (op) { - case ADD: - result = a + b; - break; - case SUB: - result = a - b; - break; - case SLT: - result = (int32_t)a < (int32_t)b; - break; - case SLTU: - result = a < b; - break; - - case AND: - result = a & b; - break; - case OR: - result = a | b; - break; - case XOR: - result = a ^ b; - break; - - case SLL: - result = a << b % 32; - break; - case SRL: - result = a >> b % 32; - break; - case SRA: - result = ((int32_t)a) >> b % 32; - break; - } - - zero = result == 0; - - printf("%01X__%08X_%08X__%08X_%01X\n", op & 0x0f, a, b, result, zero); -} - -void test_op_random(OP op, int num) { - for (int i = 0; i < num; ++i) { - uint32_t a = (rand() << 16) | rand(); - uint32_t b = (rand() << 16) | rand(); - test_op(op, a, b); - } -} - -int main(int argc, const char *argv[]) { - srand(time(NULL)); - - test_op_random(ADD, 1000); - test_op(ADD, 0x00000000, 0x00000000); - test_op(ADD, 0xffffffff, 0xffffffff); - test_op(ADD, 0xffffffff, 0x00000001); - test_op_random(SUB, 1000); - test_op(SUB, 0xffffffff, 0xffffffff); - test_op_random(SLT, 1000); - test_op(SLT, 0x8fffffff, 0xffffffff); - test_op(SLT, 0xffffffff, 0x00000001); - test_op(SLT, 0x00000001, 0xffffffff); - test_op_random(SLTU, 1000); - - test_op_random(OR, 1000); - test_op(OR, 0x00000000, 0x00000000); - test_op(OR, 0xffffffff, 0x00000000); - test_op(OR, 0x00000000, 0xffffffff); - test_op(OR, 0xffffffff, 0xffffffff); - test_op_random(AND, 1000); - test_op(AND, 0x00000000, 0x00000000); - test_op(AND, 0xffffffff, 0x00000000); - test_op(AND, 0x00000000, 0xffffffff); - test_op(AND, 0xffffffff, 0xffffffff); - test_op_random(XOR, 1000); - test_op(XOR, 0x00000000, 0x00000000); - test_op(XOR, 0xffffffff, 0x00000000); - test_op(XOR, 0x00000000, 0xffffffff); - test_op(XOR, 0xffffffff, 0xffffffff); - - test_op_random(SLL, 1000); - test_op(SLL, 0x0000000f, 0x00000004); - test_op(SLL, 0xffffffff, 0x0000001c); - test_op(SLL, 0xf0000000, 0x00000002); - test_op(SLL, 0x01234567, 0x00000001); - test_op_random(SRL, 1000); - test_op(SRL, 0xf0000000, 0x0000001c); - test_op(SRL, 0x0000000f, 0x0000004); - test_op_random(SRA, 1000); - test_op(SRA, 0xf0000000, 0x0000001c); - test_op(SRA, 0x0000000f, 0x0000004); - - return 0; -} diff --git a/gentestvec/gentestvec_cpu.c b/gentestvec/gentestvec_cpu.c deleted file mode 100644 index 8500dd9..0000000 --- a/gentestvec/gentestvec_cpu.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -#include -#include -#include - -int main(int argc, const char *argv[]) { return 0; } diff --git a/gentestvec/gentestvec_register_file.c b/gentestvec/gentestvec_register_file.c deleted file mode 100644 index 5a50d9b..0000000 --- a/gentestvec/gentestvec_register_file.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include - -uint32_t registers[32]; - -uint32_t read_reg(uint32_t addr) { return addr == 0 ? 0 : registers[addr]; } - -void write_reg(uint32_t addr, uint32_t data, bool we) { - if (addr != 0 && we) - registers[addr] = data; -} - -void test(uint32_t addr_rs0, uint32_t addr_rs1, uint32_t addr_rd2, - uint32_t data_rd2, bool we) { - - write_reg(addr_rd2, data_rd2, we); - uint32_t data_rs0 = read_reg(addr_rs0); - uint32_t data_rs1 = read_reg(addr_rs1); - printf("%08X_%08X__%08X_%08X__%08X_%08X_%01X\n", addr_rs0, data_rs0, addr_rs1, - data_rs1, addr_rd2, data_rd2, we); -} - -void tests(int num) { - for (int i = 0; i < num; ++i) { - uint32_t addr_rs0 = ((uint32_t)((rand() << 16) | rand())) % 32; - uint32_t addr_rs1 = ((uint32_t)((rand() << 16) | rand())) % 32; - uint32_t addr_rd2 = ((uint32_t)((rand() << 16) | rand())) % 32; - uint32_t data_rd2 = ((uint32_t)((rand() << 16) | rand())); - bool we = ((uint32_t)rand()) % 2; - test(addr_rs0, addr_rs1, addr_rd2, data_rd2, we); - } -} - -int main(int argc, const char *argv[]) { - srand(time(NULL)); - for (int i = 0; i < 32; ++i) - registers[0] = 0; - - for (int i = 0; i < 32; ++i) - test(i, i, 0, 0, false); - - for (int i = 0; i < 32; ++i) - test(i, i, i, 0xffffffff, true); - - tests(10000); - return 0; -} diff --git a/include/consts.vh b/include/consts.vh deleted file mode 100644 index 75ee0bf..0000000 --- a/include/consts.vh +++ /dev/null @@ -1,129 +0,0 @@ -parameter ALU_A_SRC_PC = 3'b000; -parameter ALU_A_SRC_PC_BUF = 3'b001; -parameter ALU_A_SRC_RD1 = 3'b010; -parameter ALU_A_SRC_RD1_BUF = 3'b011; -parameter ALU_A_SRC_0 = 3'b100; - -parameter ALU_B_SRC_RD2_BUF = 2'b00; -parameter ALU_B_SRC_IMM = 2'b01; -parameter ALU_B_SRC_4 = 2'b10; - -parameter RESULT_SRC_ALU_RESULT = 2'b00; -parameter RESULT_SRC_ALU_RESULT_BUF = 2'b01; -parameter RESULT_SRC_DATA_BUF = 2'b10; - -parameter MEM_ADDR_SRC_PC = 1'b0; -parameter MEM_ADDR_SRC_RESULT = 1'b1; - -parameter ARITHMETIC_OP_ADD = 2'b00; -parameter ARITHMETIC_OP_SUB = 2'b01; -parameter ARITHMETIC_OP_SLT = 2'b10; -parameter ARITHMETIC_OP_SLTU = 2'b11; - -parameter LOGIC_OP_AND = 2'b00; -parameter LOGIC_OP_OR = 2'b01; -parameter LOGIC_OP_XOR = 2'b10; - -parameter SHIFT_OP_SLL = 2'b00; -parameter SHIFT_OP_SRL = 2'b01; -parameter SHIFT_OP_SRA = 2'b11; - -parameter ALU_OP_ARITHMETIC = 2'b00; -parameter ALU_OP_LOGIC = 2'b01; -parameter ALU_OP_SHIFT = 2'b10; - -parameter ALU_OP_ADD = { ALU_OP_ARITHMETIC, ARITHMETIC_OP_ADD }; -parameter ALU_OP_SUB = { ALU_OP_ARITHMETIC, ARITHMETIC_OP_SUB }; -parameter ALU_OP_SLT = { ALU_OP_ARITHMETIC, ARITHMETIC_OP_SLT }; -parameter ALU_OP_SLTU = { ALU_OP_ARITHMETIC, ARITHMETIC_OP_SLTU }; -parameter ALU_OP_AND = { ALU_OP_LOGIC, LOGIC_OP_AND }; -parameter ALU_OP_OR = { ALU_OP_LOGIC, LOGIC_OP_OR }; -parameter ALU_OP_XOR = { ALU_OP_LOGIC, LOGIC_OP_XOR }; -parameter ALU_OP_SLL = { ALU_OP_SHIFT, SHIFT_OP_SLL }; -parameter ALU_OP_SRL = { ALU_OP_SHIFT, SHIFT_OP_SRL }; -parameter ALU_OP_SRA = { ALU_OP_SHIFT, SHIFT_OP_SRA }; - -parameter STATE_FETCH = 4'h0; -parameter STATE_DECODE = 4'h1; -parameter STATE_MEM_ADDR = 4'h2; -parameter STATE_MEM_LOAD = 4'h3; -parameter STATE_MEM_STORE = 4'h4; -parameter STATE_MEM_WB = 4'h5; -parameter STATE_EXECUTE_R = 4'h6; -parameter STATE_EXECUTE_I = 4'h7; -parameter STATE_JAL = 4'h8; -parameter STATE_JALR = 4'h9; -parameter STATE_LUI = 4'ha; -parameter STATE_ALU_WB = 4'hb; -parameter STATE_AUIPC = 4'hc; -parameter STATE_BRANCH = 4'hd; - -parameter INSTR_FORMAT_UNKNOWN = 3'b000; -parameter INSTR_FORMAT_R = 3'b001; -parameter INSTR_FORMAT_I = 3'b010; -parameter INSTR_FORMAT_S = 3'b011; -parameter INSTR_FORMAT_B = 3'b100; -parameter INSTR_FORMAT_U = 3'b101; -parameter INSTR_FORMAT_J = 3'b110; - -parameter OPCODE_LUI = 7'b0110111; -parameter OPCODE_AUIPC = 7'b0010111; -parameter OPCODE_JAL = 7'b1101111; -parameter OPCODE_JALR = 7'b1100111; -parameter OPCODE_BRANCH = 7'b1100011; -parameter OPCODE_LOAD = 7'b0000011; -parameter OPCODE_STORE = 7'b0100011; -parameter OPCODE_IMM = 7'b0010011; -parameter OPCODE_REG = 7'b0110011; -parameter OPCODE_SYNC = 7'b0001111; -parameter OPCODE_SYS = 7'b1110011; - -parameter FUNCT3_LS_B = 3'b000; -parameter FUNCT3_LS_H = 3'b001; -parameter FUNCT3_LS_W = 3'b010; -parameter FUNCT3_LS_BU = 3'b100; -parameter FUNCT3_LS_HU = 3'b101; - -parameter FUNCT3_ALU_ADD_SUB = 3'b000; -parameter FUNCT3_ALU_SLT = 3'b010; -parameter FUNCT3_ALU_SLTU = 3'b011; -parameter FUNCT3_ALU_XOR = 3'b100; -parameter FUNCT3_ALU_OR = 3'b110; -parameter FUNCT3_ALU_AND = 3'b111; -parameter FUNCT3_ALU_SLL = 3'b001; -parameter FUNCT3_ALU_SR = 3'b101; - -parameter FUNCT3_BRANCH_BEQ = 3'b000; -parameter FUNCT3_BRANCH_BNE = 3'b001; -parameter FUNCT3_BRANCH_BLT = 3'b100; -parameter FUNCT3_BRANCH_BGE = 3'b101; -parameter FUNCT3_BRANCH_BLTU = 3'b110; -parameter FUNCT3_BRANCH_BGEU = 3'b111; - -parameter FUNCT7_ALU_ADD = 7'b0000000; -parameter FUNCT7_ALU_SUB = 7'b0100000; -parameter FUNCT7_ALU_SRL = 7'b0000000; -parameter FUNCT7_ALU_SRA = 7'b0100000; - -parameter ALU_CTRL_OP = 1'b0; -parameter ALU_CTRL_ADD = 1'b1; - -parameter MEM_WE_ENABLE = 1'b1; -parameter MEM_WE_DISABLE = 1'b0; -parameter RF_WE_ENABLE = 1'b1; -parameter RF_WE_DISABLE = 1'b0; -parameter INSTR_WE_ENABLE = 1'b1; -parameter INSTR_WE_DISABLE = 1'b0; -parameter PC_UPDATE_ENABLE = 1'b1; -parameter PC_UPDATE_DISABLE = 1'b0; -parameter BRANCH_ENABLE = 1'b1; -parameter BRANCH_DISABLE = 1'b0; - -parameter IO_BEGIN = 32'h0000_0000; -parameter IO_END = 32'h0000_FFFF; -parameter ROM_BEGIN = 32'h0001_0000; -parameter ROM_END = 32'h000F_FFFF; -parameter RAM_BEGIN = 32'h0010_0000; -parameter RAM_END = 32'hFF0F_FFFF; - -parameter PC_INITIAL = 32'h0001_0000; diff --git a/include/log2.vh b/include/log2.vh deleted file mode 100644 index 097061d..0000000 --- a/include/log2.vh +++ /dev/null @@ -1,12 +0,0 @@ -function integer log2; - input integer value; - integer temp; - begin - log2 = 0; - temp = value - 1; - while (temp > 0) begin - log2 = log2 + 1; - temp = temp >> 1; - end - end -endfunction diff --git a/prog/Makefile b/prog/Makefile new file mode 100644 index 0000000..a5dfeaa --- /dev/null +++ b/prog/Makefile @@ -0,0 +1,65 @@ +BUILD_DIR ?= build + +# risc-v toolchain +RISCV_TOOLCHAIN = riscv64-unknown-elf +RISCV_AS = $(RISCV_TOOLCHAIN)-as +RISCV_CC = $(RISCV_TOOLCHAIN)-gcc +RISCV_LD = $(RISCV_TOOLCHAIN)-ld +RISCV_OBJCOPY = $(RISCV_TOOLCHAIN)-objcopy +RISCV_OBJDUMP = $(RISCV_TOOLCHAIN)-objdump +RISCV_SIZE = $(RISCV_TOOLCHAIN)-size + +# assembler / compiler / linker flags +RISCV_ASFLAGS = -march=rv32i -mabi=ilp32 +RISCV_CFLAGS = -march=rv32i -mabi=ilp32 +RISCV_LDFLAGS = -T link.ld -m elf32lriscv + +# dirs and files +SOURCE_DIR = src +AS_SOURCES = $(wildcard $(SOURCE_DIR)/*.s) +C_SOURCES = $(wildcard $(SOURCE_DIR)/*.c) +OBJ_FILES = $(AS_SOURCES:$(SOURCE_DIR)/%.s=$(BUILD_DIR)/%.o) $(C_SOURCES:$(SOURCE_DIR)/%.c=$(BUILD_DIR)/%.o) +ELF_FILE = $(BUILD_DIR)/prog.elf +BIN_FILE = $(BUILD_DIR)/prog.bin +ROM_FILE = $(BUILD_DIR)/rom.hex + + +# targets +all: $(ROM_FILE) + +# assemble assembly files to object files +$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.s | $(BUILD_DIR) + $(RISCV_AS) $(RISCV_ASFLAGS) -o $@ $< + +# compile source files to object files +$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c | $(BUILD_DIR) + $(RISCV_CC) $(RISCV_CFLAGS) -c -o $@ $< + +# link object files to elf file +$(ELF_FILE): $(OBJ_FILES) + $(RISCV_LD) $(RISCV_LDFLAGS) -o $@ $^ + +# create binary file from elf file +$(BIN_FILE): $(ELF_FILE) + $(RISCV_OBJCOPY) -O binary $< $@ + +# convert binary file hex file +$(ROM_FILE): $(BIN_FILE) + xxd -g 4 -c 4 -p $< | awk '{print substr($$0,7,2) substr($$0,5,2) substr($$0,3,2) substr($$0,1,2)}' > $@ + +# create build dir +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +# create objdump of elf file and print +objdump: $(ELF_FILE) + $(RISCV_OBJDUMP) -d -x --disassembler-color=on $(ELF_FILE) + +# display size information of elf file +size: $(ELF_FILE) + $(RISCV_SIZE) $(ELF_FILE) + +clean: + rm -rf $(BUILD_DIR) + +.PHONY: all clean objdump size \ No newline at end of file diff --git a/rtl/Makefile b/rtl/Makefile new file mode 100644 index 0000000..901d81f --- /dev/null +++ b/rtl/Makefile @@ -0,0 +1,56 @@ +BUILD_DIR ?= build + +# defines +TOP_MODULE = top +PRJ_NAME = riscv_cpu + +# dirs and files +SRC_DIR = src +SOURCES = $(wildcard $(SRC_DIR)/*.v) +CST_DIR = cst +CST_FILES = $(wildcard $(CST_DIR)/*.cst) +BITSTREAM = $(BUILD_DIR)/$(PRJ_NAME).fs + +# tools +YOSYS = yosys +NEXTPNR = nextpnr-himbaechel +GOWIN_PACK = gowin_pack +PROGRAMMER = openFPGALoader + +# fpga +FAMILY = GW1N-9C +DEVICE = GW1NR-LV9QN88PC6/I5 +BOARD = tangnano9k + + +# targets +all: $(BITSTREAM) + +# synthesize +$(BUILD_DIR)/$(PRJ_NAME).json: $(SOURCES) | $(BUILD_DIR) + @echo "read_verilog -Irtl $(SOURCES)" > $(BUILD_DIR)/synth_gowin.ys + @echo "chparam -set ROM_FILE \"../build/rom.hex\" rom" >> $(BUILD_DIR)/synth_gowin.ys + @echo "synth_gowin -top $(TOP_MODULE)" >> $(BUILD_DIR)/synth_gowin.ys + $(YOSYS) $(BUILD_DIR)/synth_gowin.ys -o $(BUILD_DIR)/$(PRJ_NAME).json + +# place and route +$(BUILD_DIR)/$(PRJ_NAME)_pnr.json: $(BUILD_DIR)/$(PRJ_NAME).json $(CST_FILES) + $(NEXTPNR) --json $(BUILD_DIR)/$(PRJ_NAME).json --write $(BUILD_DIR)/$(PRJ_NAME)_pnr.json --device $(DEVICE) --vopt family=$(FAMILY) --vopt cst=$(CST_FILES) + +# generate bitstream +$(BITSTREAM): $(BUILD_DIR)/$(PRJ_NAME)_pnr.json + $(GOWIN_PACK) -d $(FAMILY) -o $(BITSTREAM) $(BUILD_DIR)/$(PRJ_NAME)_pnr.json + +bitstream: $(BITSTREAM) + +upload: $(BITSTREAM) + $(PROGRAMMER) -b $(BOARD) $(BITSTREAM) + +flash: $(BITSTREAM) + $(PROGRAMMER) -b $(BOARD) -f $(BITSTREAM) + +clean: + rm -rf $(BUILD_DIR) + +.PHONY: all clean bitsream upload flash + diff --git a/rtl/cst/tangnano9k.cst b/rtl/cst/tangnano9k.cst new file mode 100644 index 0000000..e909e36 --- /dev/null +++ b/rtl/cst/tangnano9k.cst @@ -0,0 +1,38 @@ +//Part Number: GW1NR-LV9QN88PC6/I5 + +IO_LOC "clk" 52; +IO_LOC "led[0]" 10; +IO_LOC "led[1]" 11; +IO_LOC "led[2]" 13; +IO_LOC "led[3]" 14; +IO_LOC "led[4]" 15; +IO_LOC "led[5]" 16; +IO_LOC "key" 3; +IO_LOC "rst" 4; + +IO_LOC "LCD_B[0]" 54; +IO_LOC "LCD_B[1]" 53; +IO_LOC "LCD_B[2]" 51; +IO_LOC "LCD_B[3]" 42; +IO_LOC "LCD_B[4]" 41; +IO_LOC "LCD_CLK" 35; +IO_LOC "LCD_DEN" 33; +IO_LOC "LCD_G[0]" 70; +IO_LOC "LCD_G[1]" 69; +IO_LOC "LCD_G[2]" 68; +IO_LOC "LCD_G[3]" 57; +IO_LOC "LCD_G[4]" 56; +IO_LOC "LCD_G[5]" 55; +IO_LOC "LCD_HYNC" 40; +IO_LOC "LCD_R[0]" 75; +IO_LOC "LCD_R[1]" 74; +IO_LOC "LCD_R[2]" 73; +IO_LOC "LCD_R[3]" 72; +IO_LOC "LCD_R[4]" 71; +IO_LOC "LCD_SYNC" 34; +IO_LOC "LCD_XR" 32; +IO_LOC "LCD_XL" 39; + + +// true LVDS pins +IO_LOC "tlvds_p" 25,26; diff --git a/rtl/include/consts.vh b/rtl/include/consts.vh new file mode 100644 index 0000000..75ee0bf --- /dev/null +++ b/rtl/include/consts.vh @@ -0,0 +1,129 @@ +parameter ALU_A_SRC_PC = 3'b000; +parameter ALU_A_SRC_PC_BUF = 3'b001; +parameter ALU_A_SRC_RD1 = 3'b010; +parameter ALU_A_SRC_RD1_BUF = 3'b011; +parameter ALU_A_SRC_0 = 3'b100; + +parameter ALU_B_SRC_RD2_BUF = 2'b00; +parameter ALU_B_SRC_IMM = 2'b01; +parameter ALU_B_SRC_4 = 2'b10; + +parameter RESULT_SRC_ALU_RESULT = 2'b00; +parameter RESULT_SRC_ALU_RESULT_BUF = 2'b01; +parameter RESULT_SRC_DATA_BUF = 2'b10; + +parameter MEM_ADDR_SRC_PC = 1'b0; +parameter MEM_ADDR_SRC_RESULT = 1'b1; + +parameter ARITHMETIC_OP_ADD = 2'b00; +parameter ARITHMETIC_OP_SUB = 2'b01; +parameter ARITHMETIC_OP_SLT = 2'b10; +parameter ARITHMETIC_OP_SLTU = 2'b11; + +parameter LOGIC_OP_AND = 2'b00; +parameter LOGIC_OP_OR = 2'b01; +parameter LOGIC_OP_XOR = 2'b10; + +parameter SHIFT_OP_SLL = 2'b00; +parameter SHIFT_OP_SRL = 2'b01; +parameter SHIFT_OP_SRA = 2'b11; + +parameter ALU_OP_ARITHMETIC = 2'b00; +parameter ALU_OP_LOGIC = 2'b01; +parameter ALU_OP_SHIFT = 2'b10; + +parameter ALU_OP_ADD = { ALU_OP_ARITHMETIC, ARITHMETIC_OP_ADD }; +parameter ALU_OP_SUB = { ALU_OP_ARITHMETIC, ARITHMETIC_OP_SUB }; +parameter ALU_OP_SLT = { ALU_OP_ARITHMETIC, ARITHMETIC_OP_SLT }; +parameter ALU_OP_SLTU = { ALU_OP_ARITHMETIC, ARITHMETIC_OP_SLTU }; +parameter ALU_OP_AND = { ALU_OP_LOGIC, LOGIC_OP_AND }; +parameter ALU_OP_OR = { ALU_OP_LOGIC, LOGIC_OP_OR }; +parameter ALU_OP_XOR = { ALU_OP_LOGIC, LOGIC_OP_XOR }; +parameter ALU_OP_SLL = { ALU_OP_SHIFT, SHIFT_OP_SLL }; +parameter ALU_OP_SRL = { ALU_OP_SHIFT, SHIFT_OP_SRL }; +parameter ALU_OP_SRA = { ALU_OP_SHIFT, SHIFT_OP_SRA }; + +parameter STATE_FETCH = 4'h0; +parameter STATE_DECODE = 4'h1; +parameter STATE_MEM_ADDR = 4'h2; +parameter STATE_MEM_LOAD = 4'h3; +parameter STATE_MEM_STORE = 4'h4; +parameter STATE_MEM_WB = 4'h5; +parameter STATE_EXECUTE_R = 4'h6; +parameter STATE_EXECUTE_I = 4'h7; +parameter STATE_JAL = 4'h8; +parameter STATE_JALR = 4'h9; +parameter STATE_LUI = 4'ha; +parameter STATE_ALU_WB = 4'hb; +parameter STATE_AUIPC = 4'hc; +parameter STATE_BRANCH = 4'hd; + +parameter INSTR_FORMAT_UNKNOWN = 3'b000; +parameter INSTR_FORMAT_R = 3'b001; +parameter INSTR_FORMAT_I = 3'b010; +parameter INSTR_FORMAT_S = 3'b011; +parameter INSTR_FORMAT_B = 3'b100; +parameter INSTR_FORMAT_U = 3'b101; +parameter INSTR_FORMAT_J = 3'b110; + +parameter OPCODE_LUI = 7'b0110111; +parameter OPCODE_AUIPC = 7'b0010111; +parameter OPCODE_JAL = 7'b1101111; +parameter OPCODE_JALR = 7'b1100111; +parameter OPCODE_BRANCH = 7'b1100011; +parameter OPCODE_LOAD = 7'b0000011; +parameter OPCODE_STORE = 7'b0100011; +parameter OPCODE_IMM = 7'b0010011; +parameter OPCODE_REG = 7'b0110011; +parameter OPCODE_SYNC = 7'b0001111; +parameter OPCODE_SYS = 7'b1110011; + +parameter FUNCT3_LS_B = 3'b000; +parameter FUNCT3_LS_H = 3'b001; +parameter FUNCT3_LS_W = 3'b010; +parameter FUNCT3_LS_BU = 3'b100; +parameter FUNCT3_LS_HU = 3'b101; + +parameter FUNCT3_ALU_ADD_SUB = 3'b000; +parameter FUNCT3_ALU_SLT = 3'b010; +parameter FUNCT3_ALU_SLTU = 3'b011; +parameter FUNCT3_ALU_XOR = 3'b100; +parameter FUNCT3_ALU_OR = 3'b110; +parameter FUNCT3_ALU_AND = 3'b111; +parameter FUNCT3_ALU_SLL = 3'b001; +parameter FUNCT3_ALU_SR = 3'b101; + +parameter FUNCT3_BRANCH_BEQ = 3'b000; +parameter FUNCT3_BRANCH_BNE = 3'b001; +parameter FUNCT3_BRANCH_BLT = 3'b100; +parameter FUNCT3_BRANCH_BGE = 3'b101; +parameter FUNCT3_BRANCH_BLTU = 3'b110; +parameter FUNCT3_BRANCH_BGEU = 3'b111; + +parameter FUNCT7_ALU_ADD = 7'b0000000; +parameter FUNCT7_ALU_SUB = 7'b0100000; +parameter FUNCT7_ALU_SRL = 7'b0000000; +parameter FUNCT7_ALU_SRA = 7'b0100000; + +parameter ALU_CTRL_OP = 1'b0; +parameter ALU_CTRL_ADD = 1'b1; + +parameter MEM_WE_ENABLE = 1'b1; +parameter MEM_WE_DISABLE = 1'b0; +parameter RF_WE_ENABLE = 1'b1; +parameter RF_WE_DISABLE = 1'b0; +parameter INSTR_WE_ENABLE = 1'b1; +parameter INSTR_WE_DISABLE = 1'b0; +parameter PC_UPDATE_ENABLE = 1'b1; +parameter PC_UPDATE_DISABLE = 1'b0; +parameter BRANCH_ENABLE = 1'b1; +parameter BRANCH_DISABLE = 1'b0; + +parameter IO_BEGIN = 32'h0000_0000; +parameter IO_END = 32'h0000_FFFF; +parameter ROM_BEGIN = 32'h0001_0000; +parameter ROM_END = 32'h000F_FFFF; +parameter RAM_BEGIN = 32'h0010_0000; +parameter RAM_END = 32'hFF0F_FFFF; + +parameter PC_INITIAL = 32'h0001_0000; diff --git a/rtl/include/log2.vh b/rtl/include/log2.vh new file mode 100644 index 0000000..097061d --- /dev/null +++ b/rtl/include/log2.vh @@ -0,0 +1,12 @@ +function integer log2; + input integer value; + integer temp; + begin + log2 = 0; + temp = value - 1; + while (temp > 0) begin + log2 = log2 + 1; + temp = temp >> 1; + end + end +endfunction diff --git a/rtl/src/alu.v b/rtl/src/alu.v new file mode 100644 index 0000000..8a265ee --- /dev/null +++ b/rtl/src/alu.v @@ -0,0 +1,47 @@ +module alu ( + input [31:0] a, + input [31:0] b, + + input [3:0] op, + + output reg [31:0] result, + output zero +); + +wire [31:0] arithmetic_result, logic_result, shift_result; + +arithmetic_unit au ( + .a(a), + .b(b), + .op(op[1:0]), + .result(arithmetic_result) +); + +logic_unit lu ( + .a(a), + .b(b), + .op(op[1:0]), + .result(logic_result) +); + +shift_unit su ( + .a(a), + .b(b[4:0]), + .op(op[1:0]), + .result(shift_result) +); + +`include "include/consts.vh" + +always @ (*) begin + case (op[3:2]) + ALU_OP_ARITHMETIC: result = arithmetic_result; // ARITHMETIC + ALU_OP_LOGIC: result = logic_result; // LOGIC + ALU_OP_SHIFT: result = shift_result; // SHIFT + default: result = 31'b0; + endcase +end + +assign zero = result == 32'b0; + +endmodule diff --git a/rtl/src/alu_a_src_mux.v b/rtl/src/alu_a_src_mux.v new file mode 100644 index 0000000..fef701b --- /dev/null +++ b/rtl/src/alu_a_src_mux.v @@ -0,0 +1,25 @@ +module alu_a_src_mux ( + input [31:0] src_pc, + input [31:0] src_pc_buf, + input [31:0] src_rd1, + input [31:0] src_rd1_buf, + + input [2:0] alu_a_src, + + output reg [31:0] alu_a +); + +`include "include/consts.vh" + +always @(*) begin + case (alu_a_src) + ALU_A_SRC_PC: alu_a = src_pc; + ALU_A_SRC_PC_BUF: alu_a = src_pc_buf; + ALU_A_SRC_RD1: alu_a = src_rd1; + ALU_A_SRC_RD1_BUF: alu_a = src_rd1_buf; + ALU_A_SRC_0: alu_a = 32'b0; + default: alu_a = 32'b0; + endcase +end + +endmodule diff --git a/rtl/src/alu_b_src_mux.v b/rtl/src/alu_b_src_mux.v new file mode 100644 index 0000000..5932f9e --- /dev/null +++ b/rtl/src/alu_b_src_mux.v @@ -0,0 +1,21 @@ +module alu_b_src_mux ( + input [31:0] src_rd2_buf, + input [31:0] src_imm, + + input [1:0] alu_b_src, + + output reg [31:0] alu_b +); + +`include "include/consts.vh" + +always @(*) begin + case (alu_b_src) + ALU_B_SRC_RD2_BUF: alu_b = src_rd2_buf; + ALU_B_SRC_IMM: alu_b = src_imm; + ALU_B_SRC_4: alu_b = 32'h4; + default: alu_b = 32'b0; + endcase +end + +endmodule diff --git a/rtl/src/alu_op_decode.v b/rtl/src/alu_op_decode.v new file mode 100644 index 0000000..4523255 --- /dev/null +++ b/rtl/src/alu_op_decode.v @@ -0,0 +1,43 @@ +module alu_op_decode ( + input [6:0] opcode, + input [2:0] funct3, + input [6:0] funct7, + + input alu_ctrl, + + output reg [3:0] alu_op +); + +`include "include/consts.vh" + +always @ (*) begin + if (alu_ctrl == ALU_CTRL_ADD) begin + alu_op = ALU_OP_ADD; + end else if (opcode == OPCODE_REG || opcode == OPCODE_IMM) begin + case (funct3) + FUNCT3_ALU_ADD_SUB: alu_op = (opcode == OPCODE_REG && funct7 == FUNCT7_ALU_SUB) ? ALU_OP_SUB : ALU_OP_ADD; + FUNCT3_ALU_SLL: alu_op = ALU_OP_SLL; + FUNCT3_ALU_SLT: alu_op = ALU_OP_SLT; + FUNCT3_ALU_SLTU: alu_op = ALU_OP_SLTU; + FUNCT3_ALU_XOR: alu_op = ALU_OP_XOR; + FUNCT3_ALU_SR: alu_op = funct7 == FUNCT7_ALU_SRL ? ALU_OP_SRL : ALU_OP_SRA; + FUNCT3_ALU_OR: alu_op = ALU_OP_OR; + FUNCT3_ALU_AND: alu_op = ALU_OP_AND; + default: alu_op = ALU_OP_ADD; + endcase + end else if (opcode == OPCODE_BRANCH) begin + case (funct3) + FUNCT3_BRANCH_BEQ: alu_op = ALU_OP_SUB; + FUNCT3_BRANCH_BNE: alu_op = ALU_OP_SUB; + FUNCT3_BRANCH_BLT: alu_op = ALU_OP_SLT; + FUNCT3_BRANCH_BGE: alu_op = ALU_OP_SLT; + FUNCT3_BRANCH_BLTU: alu_op = ALU_OP_SLTU; + FUNCT3_BRANCH_BGEU: alu_op = ALU_OP_SLTU; + default: alu_op = ALU_OP_ADD; + endcase + end else begin + alu_op = ALU_OP_ADD; + end +end + +endmodule diff --git a/rtl/src/alu_result_reg.v b/rtl/src/alu_result_reg.v new file mode 100644 index 0000000..cece9e4 --- /dev/null +++ b/rtl/src/alu_result_reg.v @@ -0,0 +1,14 @@ +module alu_result_reg ( + input clk, + input rstn, + + input [31:0] alu_result_in, + output reg [31:0] alu_result_buf +); + +always @ (posedge clk or negedge rstn) begin + if (!rstn) alu_result_buf <= 32'b0; + else alu_result_buf <= alu_result_in; +end + +endmodule diff --git a/rtl/src/arithmetic_unit.v b/rtl/src/arithmetic_unit.v new file mode 100644 index 0000000..1a2282b --- /dev/null +++ b/rtl/src/arithmetic_unit.v @@ -0,0 +1,27 @@ +module arithmetic_unit ( + input [31:0] a, + input [31:0] b, + + input [1:0] op, + + output reg [31:0] result +); + +`include "include/consts.vh" + +wire signed [31:0] a_signed, b_signed; + +assign a_signed = a; +assign b_signed = b; + +always @ (*) begin + case (op) + ARITHMETIC_OP_ADD: result = a + b; // ADD + ARITHMETIC_OP_SUB: result = a - b; // SUB + ARITHMETIC_OP_SLT: result = { {31{1'b0}}, a_signed < b_signed }; // SLT + ARITHMETIC_OP_SLTU: result = { {31{1'b0}}, a < b }; // SLTU + default: result = 32'b0; + endcase +end + +endmodule diff --git a/rtl/src/clock_divider.v b/rtl/src/clock_divider.v new file mode 100644 index 0000000..a63e943 --- /dev/null +++ b/rtl/src/clock_divider.v @@ -0,0 +1,29 @@ +module clock_divider #( + parameter N = 2 +)( + input clk, + input rstn, + + output reg clk_div +); + +reg [31:0] counter = 0; + +always @(posedge clk or negedge rstn) begin + if (!rstn) begin + counter <= 0; + clk_div <= 0; + end else begin + if (counter == (N-1)/2) begin + clk_div <= ~clk_div; + counter <= counter + 1; + end else if (counter >= (N-1)) begin + clk_div <= ~clk_div; + counter <= 0; + end else begin + counter <= counter + 1; + end + end +end + +endmodule diff --git a/rtl/src/control_unit.v b/rtl/src/control_unit.v new file mode 100644 index 0000000..28f37d9 --- /dev/null +++ b/rtl/src/control_unit.v @@ -0,0 +1,207 @@ +module control_unit ( + input clk, + input rstn, + + input [31:0] instr, + input alu_zero, + + output reg [2:0] imm_src, + output pc_we, + + output reg mem_addr_src, + output reg mem_we, + + output reg instr_we, + + output reg rf_we, + output [4:0] ra1, ra2, wa3, + + output reg [2:0] alu_a_src, + output reg [1:0] alu_b_src, + output [3:0] alu_op, + + output reg [1:0] result_src +); + +`include "include/consts.vh" + +wire [6:0] opcode; +wire [2:0] funct3; +wire [6:0] funct7; + +reg branch; +reg pc_update; +reg alu_ctrl; + +assign opcode = instr[6:0]; +assign funct3 = instr[14:12]; +assign funct7 = instr[31:25]; + +assign ra1 = instr[19:15]; +assign ra2 = instr[24:20]; +assign wa3 = instr[11:7]; + +assign pc_we = ((alu_zero ^ funct3[0] ^ funct3[2]) & branch) | pc_update; + +reg [3:0] state, next_state; + +alu_op_decode alu_op_decode ( + .opcode(opcode), + .alu_ctrl(alu_ctrl), + .funct3(funct3), + .funct7(funct7), + .alu_op(alu_op) +); + +always @ (*) begin + case (opcode) + OPCODE_REG: imm_src = INSTR_FORMAT_R; // ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND + OPCODE_IMM: imm_src = INSTR_FORMAT_I; // ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI + OPCODE_LOAD: imm_src = INSTR_FORMAT_I; // LB, LH, LW, LBU, LHU + OPCODE_JALR: imm_src = INSTR_FORMAT_I; // JALR + OPCODE_STORE: imm_src = INSTR_FORMAT_S; // SB, SH, SW + OPCODE_BRANCH: imm_src = INSTR_FORMAT_B; // BEQ, BNE, BLT, BGE, BLTU, BGEU + OPCODE_LUI: imm_src = INSTR_FORMAT_U; // LUI + OPCODE_AUIPC: imm_src = INSTR_FORMAT_U; // AUIPC + OPCODE_JAL: imm_src = INSTR_FORMAT_J; // JAL + OPCODE_SYNC: imm_src = INSTR_FORMAT_I; // FENCE + OPCODE_SYS: imm_src = INSTR_FORMAT_I; // ECALL, EBREAK + default: imm_src = INSTR_FORMAT_UNKNOWN; + endcase +end + +always @ (posedge clk or negedge rstn) begin + if (!rstn) state <= STATE_FETCH; + else state <= next_state; +end + +always @ (*) begin + case(state) + STATE_FETCH: next_state = STATE_DECODE; + STATE_DECODE: case(opcode) + OPCODE_LOAD: next_state = STATE_MEM_ADDR; + OPCODE_STORE: next_state = STATE_MEM_ADDR; + OPCODE_REG: next_state = STATE_EXECUTE_R; + OPCODE_IMM: next_state = STATE_EXECUTE_I; + OPCODE_JAL: next_state = STATE_JAL; + OPCODE_JALR: next_state = STATE_JALR; + OPCODE_LUI: next_state = STATE_LUI; + OPCODE_AUIPC: next_state = STATE_AUIPC; + OPCODE_BRANCH: next_state = STATE_BRANCH; + default: next_state = STATE_FETCH; + endcase + STATE_MEM_ADDR: case(opcode) + OPCODE_LOAD: next_state = STATE_MEM_LOAD; + OPCODE_STORE: next_state = STATE_MEM_STORE; + default: next_state = STATE_FETCH; + endcase + STATE_MEM_LOAD: next_state = STATE_MEM_WB; + STATE_MEM_WB: next_state = STATE_FETCH; + STATE_MEM_STORE: next_state = STATE_FETCH; + STATE_EXECUTE_R: next_state = STATE_ALU_WB; + STATE_ALU_WB: next_state = STATE_FETCH; + STATE_EXECUTE_I: next_state = STATE_ALU_WB; + STATE_JAL: next_state = STATE_ALU_WB; + STATE_JALR: next_state = STATE_ALU_WB; + STATE_LUI: next_state = STATE_ALU_WB; + STATE_AUIPC: next_state = STATE_ALU_WB; + STATE_BRANCH: next_state = STATE_FETCH; + default: next_state = STATE_FETCH; + endcase +end + + + +always @ (*) begin + mem_addr_src = MEM_ADDR_SRC_RESULT; + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_RD2_BUF; + alu_ctrl = ALU_CTRL_OP; + result_src = RESULT_SRC_ALU_RESULT; + mem_we = MEM_WE_DISABLE; + rf_we = RF_WE_DISABLE; + instr_we = INSTR_WE_DISABLE; + pc_update = PC_UPDATE_DISABLE; + branch = BRANCH_DISABLE; + case(state) + STATE_FETCH: begin + mem_addr_src = MEM_ADDR_SRC_PC; + alu_a_src = ALU_A_SRC_PC; + alu_b_src = ALU_B_SRC_4; + alu_ctrl = ALU_CTRL_ADD; + result_src = RESULT_SRC_ALU_RESULT; + instr_we = INSTR_WE_ENABLE; + pc_update = PC_UPDATE_ENABLE; + end + STATE_DECODE: begin + alu_a_src = (opcode == OPCODE_JALR) ? ALU_A_SRC_RD1 : ALU_A_SRC_PC_BUF; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_ADD; + end + STATE_MEM_ADDR: begin + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_ADD; + end + STATE_MEM_LOAD: begin + mem_addr_src = MEM_ADDR_SRC_RESULT; + result_src = RESULT_SRC_ALU_RESULT_BUF; + end + STATE_MEM_WB: begin + result_src = RESULT_SRC_DATA_BUF; + rf_we = RF_WE_ENABLE; + end + STATE_MEM_STORE: begin + mem_addr_src = MEM_ADDR_SRC_RESULT; + result_src = RESULT_SRC_ALU_RESULT_BUF; + mem_we = MEM_WE_ENABLE; + end + STATE_EXECUTE_R: begin + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_RD2_BUF; + alu_ctrl = ALU_CTRL_OP; + end + STATE_ALU_WB: begin + result_src = RESULT_SRC_ALU_RESULT_BUF; + rf_we = RF_WE_ENABLE; + end + STATE_EXECUTE_I: begin + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_OP; + end + STATE_JAL: begin + alu_a_src = ALU_A_SRC_PC_BUF; + alu_b_src = ALU_B_SRC_4; + alu_ctrl = ALU_CTRL_ADD; + result_src = RESULT_SRC_ALU_RESULT_BUF; + pc_update = PC_UPDATE_ENABLE; + end + STATE_JALR: begin + alu_a_src = ALU_A_SRC_PC_BUF; + alu_b_src = ALU_B_SRC_4; + alu_ctrl = ALU_CTRL_ADD; + result_src = RESULT_SRC_ALU_RESULT_BUF; + pc_update = PC_UPDATE_ENABLE; + end + STATE_LUI: begin + alu_a_src = ALU_A_SRC_0; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_ADD; + end + STATE_AUIPC: begin + alu_a_src = ALU_A_SRC_PC_BUF; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_ADD; + end + STATE_BRANCH: begin + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_RD2_BUF; + alu_ctrl = ALU_CTRL_OP; + result_src = RESULT_SRC_ALU_RESULT_BUF; + branch = BRANCH_ENABLE; + end + endcase +end + +endmodule diff --git a/rtl/src/cpu.v b/rtl/src/cpu.v new file mode 100644 index 0000000..a3b94ff --- /dev/null +++ b/rtl/src/cpu.v @@ -0,0 +1,172 @@ +module cpu ( + input clk, + input rstn, + input [31:0] io_in, + output [31:0] io_out +); + + +wire [31:0] pc, pc_buf; +wire pc_we; + +wire [31:0] mem_addr; +wire mem_addr_src; +wire [31:0] mem_rd; +wire mem_we; + +wire instr_we; +wire [31:0] instr; + +wire [31:0] imm; +wire [2:0] imm_src; + +wire [31:0] data_buf; + +wire rf_we; +wire [4:0] ra1, ra2, wa3; +wire [31:0] rd1, rd2; +wire [31:0] rd1_buf, rd2_buf; + +wire [31:0] alu_a, alu_b; +wire [2:0] alu_a_src; +wire [1:0] alu_b_src; +wire [3:0] alu_op; +wire [31:0] alu_result; +wire alu_zero; +wire [31:0] alu_result_buf; + +wire [1:0] result_src; +wire [31:0] result; + + +control_unit control_unit ( + .clk(clk), + .rstn(rstn), + .instr(instr), + .imm_src(imm_src), + .alu_zero(alu_zero), + .pc_we(pc_we), + .mem_addr_src(mem_addr_src), + .mem_we(mem_we), + .instr_we(instr_we), + .result_src(result_src), + .alu_op(alu_op), + .alu_a_src(alu_a_src), + .alu_b_src(alu_b_src), + .rf_we(rf_we), + .ra1(ra1), + .ra2(ra2), + .wa3(wa3) +); + + +pc_reg pc_reg ( + .clk(clk), + .rstn(rstn), + .we(pc_we), + .pc_in(result), + .pc(pc) +); + +mem_addr_src_mux mem_addr_src_mux ( + .src_pc(pc), + .src_result(result), + .mem_addr_src(mem_addr_src), + .mem_addr(mem_addr) +); + +memory_interface memory_interface ( + .clk(clk), + .rstn(rstn), + .we(mem_we), + .addr(mem_addr), + .rd(mem_rd), + .wd(rd2_buf), + .io_in(io_in), + .io_out(io_out) +); + +instruction_reg instruction_reg ( + .clk(clk), + .rstn(rstn), + .we(instr_we), + .pc_in(pc), + .instr_in(mem_rd), + .pc_buf(pc_buf), + .instr(instr) +); + +data_reg data_reg ( + .clk(clk), + .rstn(rstn), + .data_in(mem_rd), + .data_buf(data_buf) +); + +immediate_extend immediate_extend ( + .instr(instr), + .imm_src(imm_src), + .imm(imm) +); + +register_file register_file ( + .clk(clk), + .rstn(rstn), + .we(rf_we), + .ra1(ra1), + .ra2(ra2), + .wa3(wa3), + .rd1(rd1), + .rd2(rd2), + .wd3(result) +); + +register_file_reg register_file_reg ( + .clk(clk), + .rstn(rstn), + .rd1_in(rd1), + .rd2_in(rd2), + .rd1_buf(rd1_buf), + .rd2_buf(rd2_buf) +); + +alu_a_src_mux alu_a_src_mux( + .src_pc(pc), + .src_pc_buf(pc_buf), + .src_rd1(rd1), + .src_rd1_buf(rd1_buf), + .alu_a_src(alu_a_src), + .alu_a(alu_a) +); + +alu_b_src_mux alu_b_src_mux ( + .src_rd2_buf(rd2_buf), + .src_imm(imm), + .alu_b_src(alu_b_src), + .alu_b(alu_b) +); + +alu alu ( + .a(alu_a), + .b(alu_b), + .op(alu_op), + .result(alu_result), + .zero(alu_zero) +); + +alu_result_reg alu_result_reg ( + .clk(clk), + .rstn(rstn), + .alu_result_in(alu_result), + .alu_result_buf(alu_result_buf) +); + +result_mux result_mux ( + .src_alu_result(alu_result), + .src_alu_result_buf(alu_result_buf), + .src_data_buf(data_buf), + .result_src(result_src), + .result(result) +); + +endmodule diff --git a/rtl/src/data_reg.v b/rtl/src/data_reg.v new file mode 100644 index 0000000..473d50a --- /dev/null +++ b/rtl/src/data_reg.v @@ -0,0 +1,14 @@ +module data_reg ( + input clk, + input rstn, + + input [31:0] data_in, + output reg [31:0] data_buf +); + +always @ (posedge clk or negedge rstn) begin + if (!rstn) data_buf <= 32'b0; + else data_buf <= data_in; +end + +endmodule diff --git a/rtl/src/immediate_extend.v b/rtl/src/immediate_extend.v new file mode 100644 index 0000000..14a9a33 --- /dev/null +++ b/rtl/src/immediate_extend.v @@ -0,0 +1,22 @@ +module immediate_extend ( + input [31:0] instr, + input [2:0] imm_src, + + output reg [31:0] imm +); + +`include "include/consts.vh" + +always @ (*) begin + case (imm_src) + INSTR_FORMAT_I: imm = { {21{instr[31]}}, instr[30:20] }; // I + INSTR_FORMAT_S: imm = { {21{instr[31]}}, instr[30:25], instr[11:7] }; // S + INSTR_FORMAT_B: imm = { {20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0 }; // B + INSTR_FORMAT_U: imm = { instr[31:12], 12'b0 }; // U + INSTR_FORMAT_J: imm = { {12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 }; // J + default: imm = 32'b0; // Unknown + endcase +end + + +endmodule diff --git a/rtl/src/instruction_reg.v b/rtl/src/instruction_reg.v new file mode 100644 index 0000000..d98ab6d --- /dev/null +++ b/rtl/src/instruction_reg.v @@ -0,0 +1,20 @@ +module instruction_reg ( + input clk, + input rstn, + + input we, + input [31:0] pc_in, instr_in, + output reg [31:0] pc_buf, instr +); + +always @ (posedge clk or negedge rstn) begin + if (!rstn) begin + pc_buf <= 32'b0; + instr <= 32'b0; + end else if (we) begin + pc_buf <= pc_in; + instr <= instr_in; + end +end + +endmodule diff --git a/rtl/src/io.v b/rtl/src/io.v new file mode 100644 index 0000000..f53062b --- /dev/null +++ b/rtl/src/io.v @@ -0,0 +1,30 @@ +module io ( + input clk, + input rstn, + + input we, + input [31:0] addr, + input [31:0] wd, + + output reg [31:0] rd, + + input [31:0] io_in, + output reg [31:0] io_out +); + +`include "include/consts.vh" + +always @ (posedge clk or negedge rstn) begin + if (!rstn) begin + io_out <= 32'b0; + end else if (we && addr == 32'h0000_0004) begin + io_out <= wd; + end +end + +always @ (posedge clk) begin + if (addr == 32'h0000_0000) rd <= io_in; + else if (addr == 32'h0000_0004) rd <= io_out; + else rd <= 32'b0; +end +endmodule \ No newline at end of file diff --git a/rtl/src/logic_unit.v b/rtl/src/logic_unit.v new file mode 100644 index 0000000..8d8b31d --- /dev/null +++ b/rtl/src/logic_unit.v @@ -0,0 +1,21 @@ +module logic_unit ( + input [31:0] a, + input [31:0] b, + + input [1:0] op, + + output reg [31:0] result +); + +`include "include/consts.vh" + +always @ (*) begin + case (op) + LOGIC_OP_AND: result = a & b; // AND + LOGIC_OP_OR: result = a | b; // OR + LOGIC_OP_XOR: result = a ^ b; // XOR + default: result = 32'b0; + endcase +end + +endmodule diff --git a/rtl/src/mem_addr_src_mux.v b/rtl/src/mem_addr_src_mux.v new file mode 100644 index 0000000..1f34fe1 --- /dev/null +++ b/rtl/src/mem_addr_src_mux.v @@ -0,0 +1,20 @@ +module mem_addr_src_mux ( + input [31:0] src_pc, + input [31:0] src_result, + + input mem_addr_src, + + output reg [31:0] mem_addr +); + +`include "include/consts.vh" + +always @(*) begin + case (mem_addr_src) + MEM_ADDR_SRC_PC: mem_addr = src_pc; + MEM_ADDR_SRC_RESULT: mem_addr = src_result; + default: mem_addr = 32'b0; + endcase +end + +endmodule diff --git a/rtl/src/memory_interface.v b/rtl/src/memory_interface.v new file mode 100644 index 0000000..09f05cb --- /dev/null +++ b/rtl/src/memory_interface.v @@ -0,0 +1,84 @@ +module memory_interface ( + input clk, + input rstn, + + input we, + input [31:0] addr, + input [31:0] wd, + + output reg [31:0] rd, + + input [31:0] io_in, + output [31:0] io_out +); + +`include "include/consts.vh" + +reg ram_we; +reg io_we; +wire [31:0] ram_rd, rom_rd; +reg [31:0] rel_addr; + +ram #(.N(32), .SIZE(1024)) ram( + .clk(clk), + .rstn(rstn), + .we(ram_we), + .addr(rel_addr), + .data_read(ram_rd), + .data_write(wd) +); + +rom #(.N(32), .SIZE(1024), .ROM_FILE("../../build/rom.hex")) rom( + .clk(clk), + .addr(rel_addr), + .data_read(rom_rd) +); + +io io( + .clk(clk), + .rstn(rstn), + .we(io_we), + .addr(rel_addr), + .rd(io_rd), + .wd(wd), + .io_in(io_in), + .io_out(io_out) +); + + +// 0000 0000 Reserved +// 0000 FFFF +// +// 0001 0000 ROM +// 000F FFFF +// +// 0010 0000 RAM +// FF0F FFFF +// +// FF10 0000 Reserved +// FFFF FFFF + + +always @ (*) begin + rd = 0; + rel_addr = 0; + ram_we = 0; + io_we = 0; + if ( addr >= ROM_BEGIN && addr <= ROM_END) begin + rd = rom_rd; + rel_addr = addr - ROM_BEGIN; + end else if (addr >= RAM_BEGIN && addr <= RAM_END) begin + ram_we = we; + rd = ram_rd; + rel_addr = addr - RAM_BEGIN; + end else if (addr >= IO_BEGIN && addr <= IO_END) begin + io_we = we; + rd = io_rd; + rel_addr = addr - IO_BEGIN; + end else begin + rd = 0; + rel_addr = 0; + end +end + +endmodule diff --git a/rtl/src/pc_reg.v b/rtl/src/pc_reg.v new file mode 100644 index 0000000..d8dfbec --- /dev/null +++ b/rtl/src/pc_reg.v @@ -0,0 +1,18 @@ +module pc_reg ( + input clk, + input rstn, + + input we, + input [31:0] pc_in, + + output reg [31:0] pc +); + +`include "include/consts.vh" + +always @ (posedge clk or negedge rstn) begin + if (!rstn) pc <= PC_INITIAL; + else if (we) pc <= pc_in; +end + +endmodule diff --git a/rtl/src/ram.v b/rtl/src/ram.v new file mode 100644 index 0000000..541096e --- /dev/null +++ b/rtl/src/ram.v @@ -0,0 +1,23 @@ +module ram #( + parameter N = 32, + parameter SIZE = 1024 +)( + input clk, + input rstn, + input we, + input [N-1:0] addr, + input [N-1:0] data_write, + output reg [N-1:0] data_read +); + +`include "include/log2.vh" + +//(* RAM_STYLE="BLOCK" *) +reg [N-1:0] mem [0:SIZE-1]; + +always @(posedge clk) begin + if (we) mem[addr >> 2] <= data_write; + data_read <= mem[addr >> 2]; +end + +endmodule diff --git a/rtl/src/register_file.v b/rtl/src/register_file.v new file mode 100644 index 0000000..dda44e8 --- /dev/null +++ b/rtl/src/register_file.v @@ -0,0 +1,93 @@ +module register_file ( + input clk, + input rstn, + + input we, + input [4:0] ra1, + input [4:0] ra2, + input [4:0] wa3, + + input [31:0] wd3, + + output [31:0] rd1, + output [31:0] rd2 +); + +reg [31:0] regs[31:1]; + +// For debugging purposes: +wire [31:0] reg_x0_zero, + reg_x1_ra, + reg_x2_sp, + reg_x3_gp, + reg_x4_tp, + reg_x5_t0, + reg_x6_t1, + reg_x7_t2, + reg_x8_s0_fp, + reg_x9_s1, + reg_x10_a0, + reg_x11_a1, + reg_x12_a2, + reg_x13_a3, + reg_x14_a4, + reg_x15_a5, + reg_x16_a6, + reg_x17_a7, + reg_x18_s2, + reg_x19_s3, + reg_x20_s4, + reg_x21_s5, + reg_x22_s6, + reg_x23_s7, + reg_x24_s8, + reg_x25_s9, + reg_x26_s10, + reg_x27_s11, + reg_x28_t3, + reg_x29_t4, + reg_x30_t5, + reg_x31_t6; + +assign reg_x0_zero = 32'b0; +assign reg_x1_ra = regs[1]; +assign reg_x2_sp = regs[2]; +assign reg_x3_gp = regs[3]; +assign reg_x4_tp = regs[4]; +assign reg_x5_t0 = regs[5]; +assign reg_x6_t1 = regs[6]; +assign reg_x7_t2 = regs[7]; +assign reg_x8_s0_fp = regs[8]; +assign reg_x9_s1 = regs[9]; +assign reg_x10_a0 = regs[10]; +assign reg_x11_a1 = regs[11]; +assign reg_x12_a2 = regs[12]; +assign reg_x13_a3 = regs[13]; +assign reg_x14_a4 = regs[14]; +assign reg_x15_a5 = regs[15]; +assign reg_x16_a6 = regs[16]; +assign reg_x17_a7 = regs[17]; +assign reg_x18_s2 = regs[18]; +assign reg_x19_s3 = regs[19]; +assign reg_x20_s4 = regs[20]; +assign reg_x21_s5 = regs[21]; +assign reg_x22_s6 = regs[22]; +assign reg_x23_s7 = regs[23]; +assign reg_x24_s8 = regs[24]; +assign reg_x25_s9 = regs[25]; +assign reg_x26_s10 = regs[26]; +assign reg_x27_s11 = regs[27]; +assign reg_x28_t3 = regs[28]; +assign reg_x29_t4 = regs[29]; +assign reg_x30_t5 = regs[30]; +assign reg_x31_t6 = regs[31]; + + +assign rd1 = ra1 == 0 ? 32'b0 : regs[ra1]; +assign rd2 = ra2 == 0 ? 32'b0 : regs[ra2]; + +always @ (posedge clk) begin + if (we && (wa3 != 0)) regs[wa3] <= wd3; +end + +endmodule diff --git a/rtl/src/register_file_reg.v b/rtl/src/register_file_reg.v new file mode 100644 index 0000000..b1bd4fc --- /dev/null +++ b/rtl/src/register_file_reg.v @@ -0,0 +1,22 @@ +module register_file_reg ( + input clk, + input rstn, + + input [31:0] rd1_in, + input [31:0] rd2_in, + + output reg [31:0] rd1_buf, + output reg [31:0] rd2_buf +); + +always @ (posedge clk or negedge rstn) begin + if (!rstn) begin + rd1_buf <= 32'b0; + rd2_buf <= 32'b0; + end else begin + rd1_buf <= rd1_in; + rd2_buf <= rd2_in; + end +end + +endmodule diff --git a/rtl/src/reset_synchronizer.v b/rtl/src/reset_synchronizer.v new file mode 100644 index 0000000..dc7a80a --- /dev/null +++ b/rtl/src/reset_synchronizer.v @@ -0,0 +1,16 @@ +module reset_synchronizer ( + input clk, + input rstn_async, + output rstn +); + +reg [1:0] rstn_sync; + +always @(posedge clk or negedge rstn_async) begin + if (!rstn_async) rstn_sync <= 2'b00; + else rstn_sync <= {rstn_sync[0], 1'b1}; +end + +assign rstn = rstn_sync[1]; + +endmodule \ No newline at end of file diff --git a/rtl/src/result_mux.v b/rtl/src/result_mux.v new file mode 100644 index 0000000..3c94617 --- /dev/null +++ b/rtl/src/result_mux.v @@ -0,0 +1,22 @@ +module result_mux ( + input [31:0] src_alu_result, + input [31:0] src_alu_result_buf, + input [31:0] src_data_buf, + + input [1:0] result_src, + + output reg [31:0] result +); + +`include "include/consts.vh" + +always @(*) begin + case (result_src) + RESULT_SRC_DATA_BUF: result = src_data_buf; + RESULT_SRC_ALU_RESULT_BUF: result = src_alu_result_buf; + RESULT_SRC_ALU_RESULT: result = src_alu_result; + default: result = 32'b0; + endcase +end + +endmodule diff --git a/rtl/src/rom.v b/rtl/src/rom.v new file mode 100644 index 0000000..29de1da --- /dev/null +++ b/rtl/src/rom.v @@ -0,0 +1,25 @@ +module rom #( + parameter N = 32, + parameter SIZE = 1024, + parameter ROM_FILE = "../../build/rom.hex" +)( + input clk, + input [N-1:0] addr, + output reg [N-1:0] data_read +); + +`include "include/log2.vh" + + +//(* RAM_STYLE="BLOCK" *) +reg [N-1:0] mem [0:SIZE-1]; + +initial begin + $readmemh(ROM_FILE, mem, 0, SIZE-1); +end + +always @(negedge clk) begin + data_read <= mem[addr >> 2]; +end + +endmodule diff --git a/rtl/src/shift_unit.v b/rtl/src/shift_unit.v new file mode 100644 index 0000000..ea83e4a --- /dev/null +++ b/rtl/src/shift_unit.v @@ -0,0 +1,21 @@ +module shift_unit ( + input signed [31:0] a, + input [4:0] b, + + input [1:0] op, + + output reg [31:0] result +); + +`include "include/consts.vh" + +always @ (*) begin + case (op) + SHIFT_OP_SLL: result = a << b; // SLL + SHIFT_OP_SRL: result = a >> b; // SRL + SHIFT_OP_SRA: result = a >>> b; // SRA + default: result = 32'b0; + endcase +end + +endmodule diff --git a/rtl/src/top.v b/rtl/src/top.v new file mode 100644 index 0000000..b10fbca --- /dev/null +++ b/rtl/src/top.v @@ -0,0 +1,38 @@ +module top ( + input clk, + input key, + input rst, + output [5:0] led +); + +wire rstn, rstn_async, clk_cpu; +assign rstn_async = rst; + +wire [31:0] io_in; +wire [31:0] io_out; + +reset_synchronizer reset_synchronizer ( + .clk(clk), + .rstn_async(rstn_async), + .rstn(rstn) +); + +clock_divider #(.N(1)) clkdiv ( + .clk(clk), + .rstn(rstn), + .clk_div(clk_cpu) +); + +assign led[0] = ~clk_cpu; +assign led[5:1] = ~io_out[4:0]; +assign io_in[0] = key; + + +cpu cpu ( + .clk(clk_cpu), + .rstn(rstn), + .io_in(io_in), + .io_out(io_out) +); + +endmodule diff --git a/sim/gentestvec/Makefile b/sim/gentestvec/Makefile new file mode 100644 index 0000000..a546b0d --- /dev/null +++ b/sim/gentestvec/Makefile @@ -0,0 +1,33 @@ +BUILD_DIR ?= build + +# tools +CC = clang + +# flags +CFLAGS = -O3 + +# dirs and files +SOURCE_DIR = src +SOURCES = $(wildcard $(SOURCE_DIR)/*.c) +GENTESTVECS = $(patsubst $(SOURCE_DIR)/%.c, $(BUILD_DIR)/gentestvec_%, $(SOURCES)) +TESTVECS = $(patsubst $(BUILD_DIR)/gentestvec_%, $(BUILD_DIR)/testvec_%.txt, $(GENTESTVECS)) + + +# targets +all: $(TESTVECS) + +# build testvec generator executables +$(BUILD_DIR)/gentestvec_%: $(SOURCE_DIR)/%.c | $(BUILD_DIR) + $(CC) $(CFLAGS) -o $@ $< + +# generate testvecs +$(BUILD_DIR)/testvec_%.txt: $(BUILD_DIR)/gentestvec_% + $< > $@ + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +clean: + rm -rf $(BUILD_DIR) + +.PHONY: all clean \ No newline at end of file diff --git a/sim/gentestvec/src/alu.c b/sim/gentestvec/src/alu.c new file mode 100644 index 0000000..4a11a74 --- /dev/null +++ b/sim/gentestvec/src/alu.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include + +typedef enum { + ADD = 0b0000, + SUB = 0b0001, + SLT = 0b0010, + SLTU = 0b0011, + + AND = 0b0100, + OR = 0b0101, + XOR = 0b0110, + + SLL = 0b1000, + SRL = 0b1001, + SRA = 0b1011, +} OP; + +void test_op(OP op, uint32_t a, uint32_t b) { + uint32_t result; + bool zero; + + switch (op) { + case ADD: + result = a + b; + break; + case SUB: + result = a - b; + break; + case SLT: + result = (int32_t)a < (int32_t)b; + break; + case SLTU: + result = a < b; + break; + + case AND: + result = a & b; + break; + case OR: + result = a | b; + break; + case XOR: + result = a ^ b; + break; + + case SLL: + result = a << b % 32; + break; + case SRL: + result = a >> b % 32; + break; + case SRA: + result = ((int32_t)a) >> b % 32; + break; + } + + zero = result == 0; + + printf("%01X__%08X_%08X__%08X_%01X\n", op & 0x0f, a, b, result, zero); +} + +void test_op_random(OP op, int num) { + for (int i = 0; i < num; ++i) { + uint32_t a = (rand() << 16) | rand(); + uint32_t b = (rand() << 16) | rand(); + test_op(op, a, b); + } +} + +int main(int argc, const char *argv[]) { + srand(time(NULL)); + + test_op_random(ADD, 1000); + test_op(ADD, 0x00000000, 0x00000000); + test_op(ADD, 0xffffffff, 0xffffffff); + test_op(ADD, 0xffffffff, 0x00000001); + test_op_random(SUB, 1000); + test_op(SUB, 0xffffffff, 0xffffffff); + test_op_random(SLT, 1000); + test_op(SLT, 0x8fffffff, 0xffffffff); + test_op(SLT, 0xffffffff, 0x00000001); + test_op(SLT, 0x00000001, 0xffffffff); + test_op_random(SLTU, 1000); + + test_op_random(OR, 1000); + test_op(OR, 0x00000000, 0x00000000); + test_op(OR, 0xffffffff, 0x00000000); + test_op(OR, 0x00000000, 0xffffffff); + test_op(OR, 0xffffffff, 0xffffffff); + test_op_random(AND, 1000); + test_op(AND, 0x00000000, 0x00000000); + test_op(AND, 0xffffffff, 0x00000000); + test_op(AND, 0x00000000, 0xffffffff); + test_op(AND, 0xffffffff, 0xffffffff); + test_op_random(XOR, 1000); + test_op(XOR, 0x00000000, 0x00000000); + test_op(XOR, 0xffffffff, 0x00000000); + test_op(XOR, 0x00000000, 0xffffffff); + test_op(XOR, 0xffffffff, 0xffffffff); + + test_op_random(SLL, 1000); + test_op(SLL, 0x0000000f, 0x00000004); + test_op(SLL, 0xffffffff, 0x0000001c); + test_op(SLL, 0xf0000000, 0x00000002); + test_op(SLL, 0x01234567, 0x00000001); + test_op_random(SRL, 1000); + test_op(SRL, 0xf0000000, 0x0000001c); + test_op(SRL, 0x0000000f, 0x0000004); + test_op_random(SRA, 1000); + test_op(SRA, 0xf0000000, 0x0000001c); + test_op(SRA, 0x0000000f, 0x0000004); + + return 0; +} diff --git a/sim/gentestvec/src/cpu.c b/sim/gentestvec/src/cpu.c new file mode 100644 index 0000000..8500dd9 --- /dev/null +++ b/sim/gentestvec/src/cpu.c @@ -0,0 +1,6 @@ +#include +#include +#include +#include + +int main(int argc, const char *argv[]) { return 0; } diff --git a/sim/gentestvec/src/register_file.c b/sim/gentestvec/src/register_file.c new file mode 100644 index 0000000..5a50d9b --- /dev/null +++ b/sim/gentestvec/src/register_file.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +uint32_t registers[32]; + +uint32_t read_reg(uint32_t addr) { return addr == 0 ? 0 : registers[addr]; } + +void write_reg(uint32_t addr, uint32_t data, bool we) { + if (addr != 0 && we) + registers[addr] = data; +} + +void test(uint32_t addr_rs0, uint32_t addr_rs1, uint32_t addr_rd2, + uint32_t data_rd2, bool we) { + + write_reg(addr_rd2, data_rd2, we); + uint32_t data_rs0 = read_reg(addr_rs0); + uint32_t data_rs1 = read_reg(addr_rs1); + printf("%08X_%08X__%08X_%08X__%08X_%08X_%01X\n", addr_rs0, data_rs0, addr_rs1, + data_rs1, addr_rd2, data_rd2, we); +} + +void tests(int num) { + for (int i = 0; i < num; ++i) { + uint32_t addr_rs0 = ((uint32_t)((rand() << 16) | rand())) % 32; + uint32_t addr_rs1 = ((uint32_t)((rand() << 16) | rand())) % 32; + uint32_t addr_rd2 = ((uint32_t)((rand() << 16) | rand())) % 32; + uint32_t data_rd2 = ((uint32_t)((rand() << 16) | rand())); + bool we = ((uint32_t)rand()) % 2; + test(addr_rs0, addr_rs1, addr_rd2, data_rd2, we); + } +} + +int main(int argc, const char *argv[]) { + srand(time(NULL)); + for (int i = 0; i < 32; ++i) + registers[0] = 0; + + for (int i = 0; i < 32; ++i) + test(i, i, 0, 0, false); + + for (int i = 0; i < 32; ++i) + test(i, i, i, 0xffffffff, true); + + tests(10000); + return 0; +} diff --git a/sim/testbench_alu.v b/sim/testbench_alu.v deleted file mode 100644 index f011ed2..0000000 --- a/sim/testbench_alu.v +++ /dev/null @@ -1,84 +0,0 @@ -`timescale 1ns / 1ps - -module testbench_alu(); - - reg reset = 0; - - reg [1023:0] testvec_filename; - reg [1023:0] waveform_filename; - - initial begin - if ($value$plusargs("testvec=%s", testvec_filename)) begin - end else begin - $display("ERROR: testvec not specified"); - $finish; - end - - if ($value$plusargs("waveform=%s", waveform_filename)) begin - end else begin - $display("ERROR: waveform not specified"); - $finish; - end - end - - initial begin - $dumpfile(waveform_filename); - $dumpvars(0,testbench_alu); - end - - reg clk = 0; - always #32 clk = !clk; - - - reg [31:0] a, b, exp_result; - reg [3:0] op; - reg [3:0] exp_flags; - wire [31:0] result; - wire zero, exp_zero; - - assign exp_zero = exp_flags[0]; - - reg [31:0] alu_test_count, alu_error_count; - reg [103:0] alu_testvec [0:20000]; - - initial begin - #5; - $readmemh(testvec_filename, alu_testvec); - alu_test_count = 0; - alu_error_count = 0; - end - - always @ (posedge clk) begin - #16; - {op, a, b, exp_result, exp_flags} = alu_testvec[alu_test_count]; - #32; - if ((result !== exp_result) | (zero !== exp_zero)) begin - $display("ERROR (ALU) time: %5d, test: %d", $time, alu_test_count); - $display(" op: %b, a: %h b: %h", op, a, b); - $display(" result: %h (expected %h)", result, exp_result); - $display(" zero: %b (expected %b)", zero, exp_zero); - alu_error_count = alu_error_count + 1; - end - - alu_test_count = alu_test_count + 1; - - if ((alu_test_count == 10027)) begin - $display("FINISHED (ALU), with %d errors out of %d tests.", alu_error_count, alu_test_count); - #16; - - $finish; - end - end - - - - - alu alu ( - .a(a), - .b(b), - .op(op), - .result(result), - .zero(zero) - ); - -endmodule diff --git a/sim/testbench_cpu.v b/sim/testbench_cpu.v deleted file mode 100644 index ba40dc2..0000000 --- a/sim/testbench_cpu.v +++ /dev/null @@ -1,68 +0,0 @@ -`timescale 1ns / 1ps - -module testbench_register_file(); - -reg clk; -reg rst; - -reg [31:0] io_in; -wire [31:0] io_out; - -cpu cpu ( - .clk(clk), - .rstn(!rst), - .io_in(io_in), - .io_out(io_out) -); - -integer file, r, eof; -reg [100*8:1] line; -reg [31:0] clk_cycle_count; - - -always #5 clk = ~clk; - -reg [1023:0] testvec_filename; -reg [1023:0] waveform_filename; - -initial begin - if ($value$plusargs("testvec=%s", testvec_filename)) begin - end else begin - $display("ERROR: testvec not specified"); - $finish; - end - - if ($value$plusargs("waveform=%s", waveform_filename)) begin - end else begin - $display("ERROR: waveform not specified"); - $finish; - end -end - -initial begin - $dumpfile(waveform_filename); - $dumpvars(0,testbench_register_file); -end - - -initial begin - clk = 0; - rst = 0; - - clk_cycle_count = 0; - - @(negedge clk); - rst = 1; - @(negedge clk); - rst = 0; - - - while (1) begin - @(posedge clk); - clk_cycle_count = clk_cycle_count + 1; - if (clk_cycle_count == 10000) $finish; - end -end - -endmodule - diff --git a/sim/testbench_register_file.v b/sim/testbench_register_file.v deleted file mode 100644 index c1ca542..0000000 --- a/sim/testbench_register_file.v +++ /dev/null @@ -1,111 +0,0 @@ -`timescale 1ns / 1ps - -module testbench_register_file(); - -reg clk; -reg rst; -reg we; -reg [4:0] addr_rs0, addr_rs1, addr_rd2; -reg [31:0] data_rd2; -wire [31:0] data_rs0, data_rs1; - - -register_file uut ( - .clk(clk), - .rstn(!rst), - .we(we), - .ra1(addr_rs0), - .ra2(addr_rs1), - .wa3(addr_rd2), - .rd1(data_rs0), - .rd2(data_rs1), - .wd3(data_rd2) -); - -integer file, r, eof; -reg [100*8:1] line; -reg [31:0] test_count, error_count; - -reg [31:0] expected_data_rs0, expected_data_rs1; - -always #5 clk = ~clk; - -reg [1023:0] testvec_filename; -reg [1023:0] waveform_filename; - -integer i; -initial begin - if ($value$plusargs("testvec=%s", testvec_filename)) begin - end else begin - $display("ERROR: testvec not specified"); - $finish; - end - - if ($value$plusargs("waveform=%s", waveform_filename)) begin - end else begin - $display("ERROR: waveform not specified"); - $finish; - end -end - - initial begin - $dumpfile(waveform_filename); - $dumpvars(0,testbench_register_file); - end - - -initial begin - clk = 0; - rst = 0; - we = 0; - addr_rs0 = 0; - addr_rs1 = 0; - addr_rd2 = 0; - data_rd2 = 0; - - test_count = 0; - error_count = 0; - - rst = 1; - @(posedge clk); - rst = 0; - - for (i = 0; i < 32; i = i + 1) begin - we = 1; - addr_rd2 = i; - data_rd2 = 32'b0; - @(posedge clk); - #1; - end - - file = $fopen(testvec_filename, "r"); - if (file == 0) begin - $display("ERROR: failed to open testvec"); - $finish; - end - - while (!$feof(file)) begin - eof = $fgets(line, file); - eof = $sscanf(line, "%8h_%8h__%8h_%8h__%8h_%8h_%1h", - addr_rs0, expected_data_rs0, - addr_rs1, expected_data_rs1, - addr_rd2, data_rd2, we); - @(posedge clk); - - @(negedge clk); - if (data_rs0 !== expected_data_rs0 || data_rs1 !== expected_data_rs1) begin - $display("ERROR (register_file), test %d: addr_rs0: %08h, addr_rs1: %08h, addr_rd2: %08h, data_rd2: %08h, we: %b", - test_count, addr_rs0, addr_rs1, addr_rd2, data_rd2, we); - $display(" data_rs0: %08h (expected: %08h)", data_rs0, expected_data_rs0); - $display(" data_rs1: %08h (expected: %08h)", data_rs1, expected_data_rs1); - error_count = error_count + 1; - end - test_count = test_count + 1; - end - $display("FINISHED (register_file) with %d errors out of %d tests", error_count, test_count); - $fclose(file); - $finish; -end - -endmodule - diff --git a/sim/testbenches/Makefile b/sim/testbenches/Makefile new file mode 100644 index 0000000..67c8f92 --- /dev/null +++ b/sim/testbenches/Makefile @@ -0,0 +1,42 @@ +BUILD_DIR ?= build +RTL_SOURCES ?= $(wildcard ../../rtl/src/*.v) +TESTVEC_DIR ?= ../../build +INCLUDE = ../../rtl + +TESTVECS ?= $(wildcard $(TESTVEC_DIR)/testvec_*.txt) + +# tools +IVERILOG = iverilog +VVP = vvp +GTKWAVE = gtkwave + +# dirs and files +SOURCE_DIR = src +SOURCES = $(wildcard $(SOURCE_DIR)/*.v) +WAVEFORMS = $(patsubst testvec_%, $(BUILD_DIR)/waveform_%.vcd, $(basename $(notdir $(TESTVECS)))) + + +# targets +all: $(WAVEFORMS) + +# generate testbenches +$(BUILD_DIR)/testbench_%: $(SOURCE_DIR)/testbench_%.v $(RTL_SOURCES) | $(BUILD_DIR) always + $(IVERILOG) -I $(INCLUDE) -o $@ $^ + +# run testbenches +$(BUILD_DIR)/waveform_%.vcd: $(BUILD_DIR)/testbench_% always + $(VVP) $< +testvec=$(shell realpath $(TESTVEC_DIR)/testvec_$*.txt) +waveform=$@ + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +wave: all + $(GTKWAVE) -a ../../debug/cpu.gtkw $(BUILD_DIR)/waveform_cpu.vcd > /dev/null 2>&1 & disown + +# dummy target, s.t. other targets will always be run +always: + +clean: + rm -rf $(BUILD_DIR) + +.PHONY: all clean always \ No newline at end of file diff --git a/sim/testbenches/src/testbench_alu.v b/sim/testbenches/src/testbench_alu.v new file mode 100644 index 0000000..f011ed2 --- /dev/null +++ b/sim/testbenches/src/testbench_alu.v @@ -0,0 +1,84 @@ +`timescale 1ns / 1ps + +module testbench_alu(); + + reg reset = 0; + + reg [1023:0] testvec_filename; + reg [1023:0] waveform_filename; + + initial begin + if ($value$plusargs("testvec=%s", testvec_filename)) begin + end else begin + $display("ERROR: testvec not specified"); + $finish; + end + + if ($value$plusargs("waveform=%s", waveform_filename)) begin + end else begin + $display("ERROR: waveform not specified"); + $finish; + end + end + + initial begin + $dumpfile(waveform_filename); + $dumpvars(0,testbench_alu); + end + + reg clk = 0; + always #32 clk = !clk; + + + reg [31:0] a, b, exp_result; + reg [3:0] op; + reg [3:0] exp_flags; + wire [31:0] result; + wire zero, exp_zero; + + assign exp_zero = exp_flags[0]; + + reg [31:0] alu_test_count, alu_error_count; + reg [103:0] alu_testvec [0:20000]; + + initial begin + #5; + $readmemh(testvec_filename, alu_testvec); + alu_test_count = 0; + alu_error_count = 0; + end + + always @ (posedge clk) begin + #16; + {op, a, b, exp_result, exp_flags} = alu_testvec[alu_test_count]; + #32; + if ((result !== exp_result) | (zero !== exp_zero)) begin + $display("ERROR (ALU) time: %5d, test: %d", $time, alu_test_count); + $display(" op: %b, a: %h b: %h", op, a, b); + $display(" result: %h (expected %h)", result, exp_result); + $display(" zero: %b (expected %b)", zero, exp_zero); + alu_error_count = alu_error_count + 1; + end + + alu_test_count = alu_test_count + 1; + + if ((alu_test_count == 10027)) begin + $display("FINISHED (ALU), with %d errors out of %d tests.", alu_error_count, alu_test_count); + #16; + + $finish; + end + end + + + + + alu alu ( + .a(a), + .b(b), + .op(op), + .result(result), + .zero(zero) + ); + +endmodule diff --git a/sim/testbenches/src/testbench_cpu.v b/sim/testbenches/src/testbench_cpu.v new file mode 100644 index 0000000..ba40dc2 --- /dev/null +++ b/sim/testbenches/src/testbench_cpu.v @@ -0,0 +1,68 @@ +`timescale 1ns / 1ps + +module testbench_register_file(); + +reg clk; +reg rst; + +reg [31:0] io_in; +wire [31:0] io_out; + +cpu cpu ( + .clk(clk), + .rstn(!rst), + .io_in(io_in), + .io_out(io_out) +); + +integer file, r, eof; +reg [100*8:1] line; +reg [31:0] clk_cycle_count; + + +always #5 clk = ~clk; + +reg [1023:0] testvec_filename; +reg [1023:0] waveform_filename; + +initial begin + if ($value$plusargs("testvec=%s", testvec_filename)) begin + end else begin + $display("ERROR: testvec not specified"); + $finish; + end + + if ($value$plusargs("waveform=%s", waveform_filename)) begin + end else begin + $display("ERROR: waveform not specified"); + $finish; + end +end + +initial begin + $dumpfile(waveform_filename); + $dumpvars(0,testbench_register_file); +end + + +initial begin + clk = 0; + rst = 0; + + clk_cycle_count = 0; + + @(negedge clk); + rst = 1; + @(negedge clk); + rst = 0; + + + while (1) begin + @(posedge clk); + clk_cycle_count = clk_cycle_count + 1; + if (clk_cycle_count == 10000) $finish; + end +end + +endmodule + diff --git a/sim/testbenches/src/testbench_register_file.v b/sim/testbenches/src/testbench_register_file.v new file mode 100644 index 0000000..c1ca542 --- /dev/null +++ b/sim/testbenches/src/testbench_register_file.v @@ -0,0 +1,111 @@ +`timescale 1ns / 1ps + +module testbench_register_file(); + +reg clk; +reg rst; +reg we; +reg [4:0] addr_rs0, addr_rs1, addr_rd2; +reg [31:0] data_rd2; +wire [31:0] data_rs0, data_rs1; + + +register_file uut ( + .clk(clk), + .rstn(!rst), + .we(we), + .ra1(addr_rs0), + .ra2(addr_rs1), + .wa3(addr_rd2), + .rd1(data_rs0), + .rd2(data_rs1), + .wd3(data_rd2) +); + +integer file, r, eof; +reg [100*8:1] line; +reg [31:0] test_count, error_count; + +reg [31:0] expected_data_rs0, expected_data_rs1; + +always #5 clk = ~clk; + +reg [1023:0] testvec_filename; +reg [1023:0] waveform_filename; + +integer i; +initial begin + if ($value$plusargs("testvec=%s", testvec_filename)) begin + end else begin + $display("ERROR: testvec not specified"); + $finish; + end + + if ($value$plusargs("waveform=%s", waveform_filename)) begin + end else begin + $display("ERROR: waveform not specified"); + $finish; + end +end + + initial begin + $dumpfile(waveform_filename); + $dumpvars(0,testbench_register_file); + end + + +initial begin + clk = 0; + rst = 0; + we = 0; + addr_rs0 = 0; + addr_rs1 = 0; + addr_rd2 = 0; + data_rd2 = 0; + + test_count = 0; + error_count = 0; + + rst = 1; + @(posedge clk); + rst = 0; + + for (i = 0; i < 32; i = i + 1) begin + we = 1; + addr_rd2 = i; + data_rd2 = 32'b0; + @(posedge clk); + #1; + end + + file = $fopen(testvec_filename, "r"); + if (file == 0) begin + $display("ERROR: failed to open testvec"); + $finish; + end + + while (!$feof(file)) begin + eof = $fgets(line, file); + eof = $sscanf(line, "%8h_%8h__%8h_%8h__%8h_%8h_%1h", + addr_rs0, expected_data_rs0, + addr_rs1, expected_data_rs1, + addr_rd2, data_rd2, we); + @(posedge clk); + + @(negedge clk); + if (data_rs0 !== expected_data_rs0 || data_rs1 !== expected_data_rs1) begin + $display("ERROR (register_file), test %d: addr_rs0: %08h, addr_rs1: %08h, addr_rd2: %08h, data_rd2: %08h, we: %b", + test_count, addr_rs0, addr_rs1, addr_rd2, data_rd2, we); + $display(" data_rs0: %08h (expected: %08h)", data_rs0, expected_data_rs0); + $display(" data_rs1: %08h (expected: %08h)", data_rs1, expected_data_rs1); + error_count = error_count + 1; + end + test_count = test_count + 1; + end + $display("FINISHED (register_file) with %d errors out of %d tests", error_count, test_count); + $fclose(file); + $finish; +end + +endmodule + diff --git a/src/alu.v b/src/alu.v deleted file mode 100644 index 8a265ee..0000000 --- a/src/alu.v +++ /dev/null @@ -1,47 +0,0 @@ -module alu ( - input [31:0] a, - input [31:0] b, - - input [3:0] op, - - output reg [31:0] result, - output zero -); - -wire [31:0] arithmetic_result, logic_result, shift_result; - -arithmetic_unit au ( - .a(a), - .b(b), - .op(op[1:0]), - .result(arithmetic_result) -); - -logic_unit lu ( - .a(a), - .b(b), - .op(op[1:0]), - .result(logic_result) -); - -shift_unit su ( - .a(a), - .b(b[4:0]), - .op(op[1:0]), - .result(shift_result) -); - -`include "include/consts.vh" - -always @ (*) begin - case (op[3:2]) - ALU_OP_ARITHMETIC: result = arithmetic_result; // ARITHMETIC - ALU_OP_LOGIC: result = logic_result; // LOGIC - ALU_OP_SHIFT: result = shift_result; // SHIFT - default: result = 31'b0; - endcase -end - -assign zero = result == 32'b0; - -endmodule diff --git a/src/alu_a_src_mux.v b/src/alu_a_src_mux.v deleted file mode 100644 index fef701b..0000000 --- a/src/alu_a_src_mux.v +++ /dev/null @@ -1,25 +0,0 @@ -module alu_a_src_mux ( - input [31:0] src_pc, - input [31:0] src_pc_buf, - input [31:0] src_rd1, - input [31:0] src_rd1_buf, - - input [2:0] alu_a_src, - - output reg [31:0] alu_a -); - -`include "include/consts.vh" - -always @(*) begin - case (alu_a_src) - ALU_A_SRC_PC: alu_a = src_pc; - ALU_A_SRC_PC_BUF: alu_a = src_pc_buf; - ALU_A_SRC_RD1: alu_a = src_rd1; - ALU_A_SRC_RD1_BUF: alu_a = src_rd1_buf; - ALU_A_SRC_0: alu_a = 32'b0; - default: alu_a = 32'b0; - endcase -end - -endmodule diff --git a/src/alu_b_src_mux.v b/src/alu_b_src_mux.v deleted file mode 100644 index 5932f9e..0000000 --- a/src/alu_b_src_mux.v +++ /dev/null @@ -1,21 +0,0 @@ -module alu_b_src_mux ( - input [31:0] src_rd2_buf, - input [31:0] src_imm, - - input [1:0] alu_b_src, - - output reg [31:0] alu_b -); - -`include "include/consts.vh" - -always @(*) begin - case (alu_b_src) - ALU_B_SRC_RD2_BUF: alu_b = src_rd2_buf; - ALU_B_SRC_IMM: alu_b = src_imm; - ALU_B_SRC_4: alu_b = 32'h4; - default: alu_b = 32'b0; - endcase -end - -endmodule diff --git a/src/alu_op_decode.v b/src/alu_op_decode.v deleted file mode 100644 index 4523255..0000000 --- a/src/alu_op_decode.v +++ /dev/null @@ -1,43 +0,0 @@ -module alu_op_decode ( - input [6:0] opcode, - input [2:0] funct3, - input [6:0] funct7, - - input alu_ctrl, - - output reg [3:0] alu_op -); - -`include "include/consts.vh" - -always @ (*) begin - if (alu_ctrl == ALU_CTRL_ADD) begin - alu_op = ALU_OP_ADD; - end else if (opcode == OPCODE_REG || opcode == OPCODE_IMM) begin - case (funct3) - FUNCT3_ALU_ADD_SUB: alu_op = (opcode == OPCODE_REG && funct7 == FUNCT7_ALU_SUB) ? ALU_OP_SUB : ALU_OP_ADD; - FUNCT3_ALU_SLL: alu_op = ALU_OP_SLL; - FUNCT3_ALU_SLT: alu_op = ALU_OP_SLT; - FUNCT3_ALU_SLTU: alu_op = ALU_OP_SLTU; - FUNCT3_ALU_XOR: alu_op = ALU_OP_XOR; - FUNCT3_ALU_SR: alu_op = funct7 == FUNCT7_ALU_SRL ? ALU_OP_SRL : ALU_OP_SRA; - FUNCT3_ALU_OR: alu_op = ALU_OP_OR; - FUNCT3_ALU_AND: alu_op = ALU_OP_AND; - default: alu_op = ALU_OP_ADD; - endcase - end else if (opcode == OPCODE_BRANCH) begin - case (funct3) - FUNCT3_BRANCH_BEQ: alu_op = ALU_OP_SUB; - FUNCT3_BRANCH_BNE: alu_op = ALU_OP_SUB; - FUNCT3_BRANCH_BLT: alu_op = ALU_OP_SLT; - FUNCT3_BRANCH_BGE: alu_op = ALU_OP_SLT; - FUNCT3_BRANCH_BLTU: alu_op = ALU_OP_SLTU; - FUNCT3_BRANCH_BGEU: alu_op = ALU_OP_SLTU; - default: alu_op = ALU_OP_ADD; - endcase - end else begin - alu_op = ALU_OP_ADD; - end -end - -endmodule diff --git a/src/alu_result_reg.v b/src/alu_result_reg.v deleted file mode 100644 index cece9e4..0000000 --- a/src/alu_result_reg.v +++ /dev/null @@ -1,14 +0,0 @@ -module alu_result_reg ( - input clk, - input rstn, - - input [31:0] alu_result_in, - output reg [31:0] alu_result_buf -); - -always @ (posedge clk or negedge rstn) begin - if (!rstn) alu_result_buf <= 32'b0; - else alu_result_buf <= alu_result_in; -end - -endmodule diff --git a/src/arithmetic_unit.v b/src/arithmetic_unit.v deleted file mode 100644 index 1a2282b..0000000 --- a/src/arithmetic_unit.v +++ /dev/null @@ -1,27 +0,0 @@ -module arithmetic_unit ( - input [31:0] a, - input [31:0] b, - - input [1:0] op, - - output reg [31:0] result -); - -`include "include/consts.vh" - -wire signed [31:0] a_signed, b_signed; - -assign a_signed = a; -assign b_signed = b; - -always @ (*) begin - case (op) - ARITHMETIC_OP_ADD: result = a + b; // ADD - ARITHMETIC_OP_SUB: result = a - b; // SUB - ARITHMETIC_OP_SLT: result = { {31{1'b0}}, a_signed < b_signed }; // SLT - ARITHMETIC_OP_SLTU: result = { {31{1'b0}}, a < b }; // SLTU - default: result = 32'b0; - endcase -end - -endmodule diff --git a/src/clock_divider.v b/src/clock_divider.v deleted file mode 100644 index a63e943..0000000 --- a/src/clock_divider.v +++ /dev/null @@ -1,29 +0,0 @@ -module clock_divider #( - parameter N = 2 -)( - input clk, - input rstn, - - output reg clk_div -); - -reg [31:0] counter = 0; - -always @(posedge clk or negedge rstn) begin - if (!rstn) begin - counter <= 0; - clk_div <= 0; - end else begin - if (counter == (N-1)/2) begin - clk_div <= ~clk_div; - counter <= counter + 1; - end else if (counter >= (N-1)) begin - clk_div <= ~clk_div; - counter <= 0; - end else begin - counter <= counter + 1; - end - end -end - -endmodule diff --git a/src/control_unit.v b/src/control_unit.v deleted file mode 100644 index 28f37d9..0000000 --- a/src/control_unit.v +++ /dev/null @@ -1,207 +0,0 @@ -module control_unit ( - input clk, - input rstn, - - input [31:0] instr, - input alu_zero, - - output reg [2:0] imm_src, - output pc_we, - - output reg mem_addr_src, - output reg mem_we, - - output reg instr_we, - - output reg rf_we, - output [4:0] ra1, ra2, wa3, - - output reg [2:0] alu_a_src, - output reg [1:0] alu_b_src, - output [3:0] alu_op, - - output reg [1:0] result_src -); - -`include "include/consts.vh" - -wire [6:0] opcode; -wire [2:0] funct3; -wire [6:0] funct7; - -reg branch; -reg pc_update; -reg alu_ctrl; - -assign opcode = instr[6:0]; -assign funct3 = instr[14:12]; -assign funct7 = instr[31:25]; - -assign ra1 = instr[19:15]; -assign ra2 = instr[24:20]; -assign wa3 = instr[11:7]; - -assign pc_we = ((alu_zero ^ funct3[0] ^ funct3[2]) & branch) | pc_update; - -reg [3:0] state, next_state; - -alu_op_decode alu_op_decode ( - .opcode(opcode), - .alu_ctrl(alu_ctrl), - .funct3(funct3), - .funct7(funct7), - .alu_op(alu_op) -); - -always @ (*) begin - case (opcode) - OPCODE_REG: imm_src = INSTR_FORMAT_R; // ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND - OPCODE_IMM: imm_src = INSTR_FORMAT_I; // ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI - OPCODE_LOAD: imm_src = INSTR_FORMAT_I; // LB, LH, LW, LBU, LHU - OPCODE_JALR: imm_src = INSTR_FORMAT_I; // JALR - OPCODE_STORE: imm_src = INSTR_FORMAT_S; // SB, SH, SW - OPCODE_BRANCH: imm_src = INSTR_FORMAT_B; // BEQ, BNE, BLT, BGE, BLTU, BGEU - OPCODE_LUI: imm_src = INSTR_FORMAT_U; // LUI - OPCODE_AUIPC: imm_src = INSTR_FORMAT_U; // AUIPC - OPCODE_JAL: imm_src = INSTR_FORMAT_J; // JAL - OPCODE_SYNC: imm_src = INSTR_FORMAT_I; // FENCE - OPCODE_SYS: imm_src = INSTR_FORMAT_I; // ECALL, EBREAK - default: imm_src = INSTR_FORMAT_UNKNOWN; - endcase -end - -always @ (posedge clk or negedge rstn) begin - if (!rstn) state <= STATE_FETCH; - else state <= next_state; -end - -always @ (*) begin - case(state) - STATE_FETCH: next_state = STATE_DECODE; - STATE_DECODE: case(opcode) - OPCODE_LOAD: next_state = STATE_MEM_ADDR; - OPCODE_STORE: next_state = STATE_MEM_ADDR; - OPCODE_REG: next_state = STATE_EXECUTE_R; - OPCODE_IMM: next_state = STATE_EXECUTE_I; - OPCODE_JAL: next_state = STATE_JAL; - OPCODE_JALR: next_state = STATE_JALR; - OPCODE_LUI: next_state = STATE_LUI; - OPCODE_AUIPC: next_state = STATE_AUIPC; - OPCODE_BRANCH: next_state = STATE_BRANCH; - default: next_state = STATE_FETCH; - endcase - STATE_MEM_ADDR: case(opcode) - OPCODE_LOAD: next_state = STATE_MEM_LOAD; - OPCODE_STORE: next_state = STATE_MEM_STORE; - default: next_state = STATE_FETCH; - endcase - STATE_MEM_LOAD: next_state = STATE_MEM_WB; - STATE_MEM_WB: next_state = STATE_FETCH; - STATE_MEM_STORE: next_state = STATE_FETCH; - STATE_EXECUTE_R: next_state = STATE_ALU_WB; - STATE_ALU_WB: next_state = STATE_FETCH; - STATE_EXECUTE_I: next_state = STATE_ALU_WB; - STATE_JAL: next_state = STATE_ALU_WB; - STATE_JALR: next_state = STATE_ALU_WB; - STATE_LUI: next_state = STATE_ALU_WB; - STATE_AUIPC: next_state = STATE_ALU_WB; - STATE_BRANCH: next_state = STATE_FETCH; - default: next_state = STATE_FETCH; - endcase -end - - - -always @ (*) begin - mem_addr_src = MEM_ADDR_SRC_RESULT; - alu_a_src = ALU_A_SRC_RD1_BUF; - alu_b_src = ALU_B_SRC_RD2_BUF; - alu_ctrl = ALU_CTRL_OP; - result_src = RESULT_SRC_ALU_RESULT; - mem_we = MEM_WE_DISABLE; - rf_we = RF_WE_DISABLE; - instr_we = INSTR_WE_DISABLE; - pc_update = PC_UPDATE_DISABLE; - branch = BRANCH_DISABLE; - case(state) - STATE_FETCH: begin - mem_addr_src = MEM_ADDR_SRC_PC; - alu_a_src = ALU_A_SRC_PC; - alu_b_src = ALU_B_SRC_4; - alu_ctrl = ALU_CTRL_ADD; - result_src = RESULT_SRC_ALU_RESULT; - instr_we = INSTR_WE_ENABLE; - pc_update = PC_UPDATE_ENABLE; - end - STATE_DECODE: begin - alu_a_src = (opcode == OPCODE_JALR) ? ALU_A_SRC_RD1 : ALU_A_SRC_PC_BUF; - alu_b_src = ALU_B_SRC_IMM; - alu_ctrl = ALU_CTRL_ADD; - end - STATE_MEM_ADDR: begin - alu_a_src = ALU_A_SRC_RD1_BUF; - alu_b_src = ALU_B_SRC_IMM; - alu_ctrl = ALU_CTRL_ADD; - end - STATE_MEM_LOAD: begin - mem_addr_src = MEM_ADDR_SRC_RESULT; - result_src = RESULT_SRC_ALU_RESULT_BUF; - end - STATE_MEM_WB: begin - result_src = RESULT_SRC_DATA_BUF; - rf_we = RF_WE_ENABLE; - end - STATE_MEM_STORE: begin - mem_addr_src = MEM_ADDR_SRC_RESULT; - result_src = RESULT_SRC_ALU_RESULT_BUF; - mem_we = MEM_WE_ENABLE; - end - STATE_EXECUTE_R: begin - alu_a_src = ALU_A_SRC_RD1_BUF; - alu_b_src = ALU_B_SRC_RD2_BUF; - alu_ctrl = ALU_CTRL_OP; - end - STATE_ALU_WB: begin - result_src = RESULT_SRC_ALU_RESULT_BUF; - rf_we = RF_WE_ENABLE; - end - STATE_EXECUTE_I: begin - alu_a_src = ALU_A_SRC_RD1_BUF; - alu_b_src = ALU_B_SRC_IMM; - alu_ctrl = ALU_CTRL_OP; - end - STATE_JAL: begin - alu_a_src = ALU_A_SRC_PC_BUF; - alu_b_src = ALU_B_SRC_4; - alu_ctrl = ALU_CTRL_ADD; - result_src = RESULT_SRC_ALU_RESULT_BUF; - pc_update = PC_UPDATE_ENABLE; - end - STATE_JALR: begin - alu_a_src = ALU_A_SRC_PC_BUF; - alu_b_src = ALU_B_SRC_4; - alu_ctrl = ALU_CTRL_ADD; - result_src = RESULT_SRC_ALU_RESULT_BUF; - pc_update = PC_UPDATE_ENABLE; - end - STATE_LUI: begin - alu_a_src = ALU_A_SRC_0; - alu_b_src = ALU_B_SRC_IMM; - alu_ctrl = ALU_CTRL_ADD; - end - STATE_AUIPC: begin - alu_a_src = ALU_A_SRC_PC_BUF; - alu_b_src = ALU_B_SRC_IMM; - alu_ctrl = ALU_CTRL_ADD; - end - STATE_BRANCH: begin - alu_a_src = ALU_A_SRC_RD1_BUF; - alu_b_src = ALU_B_SRC_RD2_BUF; - alu_ctrl = ALU_CTRL_OP; - result_src = RESULT_SRC_ALU_RESULT_BUF; - branch = BRANCH_ENABLE; - end - endcase -end - -endmodule diff --git a/src/cpu.v b/src/cpu.v deleted file mode 100644 index a3b94ff..0000000 --- a/src/cpu.v +++ /dev/null @@ -1,172 +0,0 @@ -module cpu ( - input clk, - input rstn, - input [31:0] io_in, - output [31:0] io_out -); - - -wire [31:0] pc, pc_buf; -wire pc_we; - -wire [31:0] mem_addr; -wire mem_addr_src; -wire [31:0] mem_rd; -wire mem_we; - -wire instr_we; -wire [31:0] instr; - -wire [31:0] imm; -wire [2:0] imm_src; - -wire [31:0] data_buf; - -wire rf_we; -wire [4:0] ra1, ra2, wa3; -wire [31:0] rd1, rd2; -wire [31:0] rd1_buf, rd2_buf; - -wire [31:0] alu_a, alu_b; -wire [2:0] alu_a_src; -wire [1:0] alu_b_src; -wire [3:0] alu_op; -wire [31:0] alu_result; -wire alu_zero; -wire [31:0] alu_result_buf; - -wire [1:0] result_src; -wire [31:0] result; - - -control_unit control_unit ( - .clk(clk), - .rstn(rstn), - .instr(instr), - .imm_src(imm_src), - .alu_zero(alu_zero), - .pc_we(pc_we), - .mem_addr_src(mem_addr_src), - .mem_we(mem_we), - .instr_we(instr_we), - .result_src(result_src), - .alu_op(alu_op), - .alu_a_src(alu_a_src), - .alu_b_src(alu_b_src), - .rf_we(rf_we), - .ra1(ra1), - .ra2(ra2), - .wa3(wa3) -); - - -pc_reg pc_reg ( - .clk(clk), - .rstn(rstn), - .we(pc_we), - .pc_in(result), - .pc(pc) -); - -mem_addr_src_mux mem_addr_src_mux ( - .src_pc(pc), - .src_result(result), - .mem_addr_src(mem_addr_src), - .mem_addr(mem_addr) -); - -memory_interface memory_interface ( - .clk(clk), - .rstn(rstn), - .we(mem_we), - .addr(mem_addr), - .rd(mem_rd), - .wd(rd2_buf), - .io_in(io_in), - .io_out(io_out) -); - -instruction_reg instruction_reg ( - .clk(clk), - .rstn(rstn), - .we(instr_we), - .pc_in(pc), - .instr_in(mem_rd), - .pc_buf(pc_buf), - .instr(instr) -); - -data_reg data_reg ( - .clk(clk), - .rstn(rstn), - .data_in(mem_rd), - .data_buf(data_buf) -); - -immediate_extend immediate_extend ( - .instr(instr), - .imm_src(imm_src), - .imm(imm) -); - -register_file register_file ( - .clk(clk), - .rstn(rstn), - .we(rf_we), - .ra1(ra1), - .ra2(ra2), - .wa3(wa3), - .rd1(rd1), - .rd2(rd2), - .wd3(result) -); - -register_file_reg register_file_reg ( - .clk(clk), - .rstn(rstn), - .rd1_in(rd1), - .rd2_in(rd2), - .rd1_buf(rd1_buf), - .rd2_buf(rd2_buf) -); - -alu_a_src_mux alu_a_src_mux( - .src_pc(pc), - .src_pc_buf(pc_buf), - .src_rd1(rd1), - .src_rd1_buf(rd1_buf), - .alu_a_src(alu_a_src), - .alu_a(alu_a) -); - -alu_b_src_mux alu_b_src_mux ( - .src_rd2_buf(rd2_buf), - .src_imm(imm), - .alu_b_src(alu_b_src), - .alu_b(alu_b) -); - -alu alu ( - .a(alu_a), - .b(alu_b), - .op(alu_op), - .result(alu_result), - .zero(alu_zero) -); - -alu_result_reg alu_result_reg ( - .clk(clk), - .rstn(rstn), - .alu_result_in(alu_result), - .alu_result_buf(alu_result_buf) -); - -result_mux result_mux ( - .src_alu_result(alu_result), - .src_alu_result_buf(alu_result_buf), - .src_data_buf(data_buf), - .result_src(result_src), - .result(result) -); - -endmodule diff --git a/src/data_reg.v b/src/data_reg.v deleted file mode 100644 index 473d50a..0000000 --- a/src/data_reg.v +++ /dev/null @@ -1,14 +0,0 @@ -module data_reg ( - input clk, - input rstn, - - input [31:0] data_in, - output reg [31:0] data_buf -); - -always @ (posedge clk or negedge rstn) begin - if (!rstn) data_buf <= 32'b0; - else data_buf <= data_in; -end - -endmodule diff --git a/src/immediate_extend.v b/src/immediate_extend.v deleted file mode 100644 index 14a9a33..0000000 --- a/src/immediate_extend.v +++ /dev/null @@ -1,22 +0,0 @@ -module immediate_extend ( - input [31:0] instr, - input [2:0] imm_src, - - output reg [31:0] imm -); - -`include "include/consts.vh" - -always @ (*) begin - case (imm_src) - INSTR_FORMAT_I: imm = { {21{instr[31]}}, instr[30:20] }; // I - INSTR_FORMAT_S: imm = { {21{instr[31]}}, instr[30:25], instr[11:7] }; // S - INSTR_FORMAT_B: imm = { {20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0 }; // B - INSTR_FORMAT_U: imm = { instr[31:12], 12'b0 }; // U - INSTR_FORMAT_J: imm = { {12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 }; // J - default: imm = 32'b0; // Unknown - endcase -end - - -endmodule diff --git a/src/instruction_reg.v b/src/instruction_reg.v deleted file mode 100644 index d98ab6d..0000000 --- a/src/instruction_reg.v +++ /dev/null @@ -1,20 +0,0 @@ -module instruction_reg ( - input clk, - input rstn, - - input we, - input [31:0] pc_in, instr_in, - output reg [31:0] pc_buf, instr -); - -always @ (posedge clk or negedge rstn) begin - if (!rstn) begin - pc_buf <= 32'b0; - instr <= 32'b0; - end else if (we) begin - pc_buf <= pc_in; - instr <= instr_in; - end -end - -endmodule diff --git a/src/io.v b/src/io.v deleted file mode 100644 index f53062b..0000000 --- a/src/io.v +++ /dev/null @@ -1,30 +0,0 @@ -module io ( - input clk, - input rstn, - - input we, - input [31:0] addr, - input [31:0] wd, - - output reg [31:0] rd, - - input [31:0] io_in, - output reg [31:0] io_out -); - -`include "include/consts.vh" - -always @ (posedge clk or negedge rstn) begin - if (!rstn) begin - io_out <= 32'b0; - end else if (we && addr == 32'h0000_0004) begin - io_out <= wd; - end -end - -always @ (posedge clk) begin - if (addr == 32'h0000_0000) rd <= io_in; - else if (addr == 32'h0000_0004) rd <= io_out; - else rd <= 32'b0; -end -endmodule \ No newline at end of file diff --git a/src/logic_unit.v b/src/logic_unit.v deleted file mode 100644 index 8d8b31d..0000000 --- a/src/logic_unit.v +++ /dev/null @@ -1,21 +0,0 @@ -module logic_unit ( - input [31:0] a, - input [31:0] b, - - input [1:0] op, - - output reg [31:0] result -); - -`include "include/consts.vh" - -always @ (*) begin - case (op) - LOGIC_OP_AND: result = a & b; // AND - LOGIC_OP_OR: result = a | b; // OR - LOGIC_OP_XOR: result = a ^ b; // XOR - default: result = 32'b0; - endcase -end - -endmodule diff --git a/src/mem_addr_src_mux.v b/src/mem_addr_src_mux.v deleted file mode 100644 index 1f34fe1..0000000 --- a/src/mem_addr_src_mux.v +++ /dev/null @@ -1,20 +0,0 @@ -module mem_addr_src_mux ( - input [31:0] src_pc, - input [31:0] src_result, - - input mem_addr_src, - - output reg [31:0] mem_addr -); - -`include "include/consts.vh" - -always @(*) begin - case (mem_addr_src) - MEM_ADDR_SRC_PC: mem_addr = src_pc; - MEM_ADDR_SRC_RESULT: mem_addr = src_result; - default: mem_addr = 32'b0; - endcase -end - -endmodule diff --git a/src/memory_interface.v b/src/memory_interface.v deleted file mode 100644 index 0bc547b..0000000 --- a/src/memory_interface.v +++ /dev/null @@ -1,84 +0,0 @@ -module memory_interface ( - input clk, - input rstn, - - input we, - input [31:0] addr, - input [31:0] wd, - - output reg [31:0] rd, - - input [31:0] io_in, - output [31:0] io_out -); - -`include "include/consts.vh" - -reg ram_we; -reg io_we; -wire [31:0] ram_rd, rom_rd; -reg [31:0] rel_addr; - -ram #(.N(32), .SIZE(1024)) ram( - .clk(clk), - .rstn(rstn), - .we(ram_we), - .addr(rel_addr), - .data_read(ram_rd), - .data_write(wd) -); - -rom #(.N(32), .SIZE(1024)) rom( - .clk(clk), - .addr(rel_addr), - .data_read(rom_rd) -); - -io io( - .clk(clk), - .rstn(rstn), - .we(io_we), - .addr(rel_addr), - .rd(io_rd), - .wd(wd), - .io_in(io_in), - .io_out(io_out) -); - - -// 0000 0000 Reserved -// 0000 FFFF -// -// 0001 0000 ROM -// 000F FFFF -// -// 0010 0000 RAM -// FF0F FFFF -// -// FF10 0000 Reserved -// FFFF FFFF - - -always @ (*) begin - rd = 0; - rel_addr = 0; - ram_we = 0; - io_we = 0; - if ( addr >= ROM_BEGIN && addr <= ROM_END) begin - rd = rom_rd; - rel_addr = addr - ROM_BEGIN; - end else if (addr >= RAM_BEGIN && addr <= RAM_END) begin - ram_we = we; - rd = ram_rd; - rel_addr = addr - RAM_BEGIN; - end else if (addr >= IO_BEGIN && addr <= IO_END) begin - io_we = we; - rd = io_rd; - rel_addr = addr - IO_BEGIN; - end else begin - rd = 0; - rel_addr = 0; - end -end - -endmodule diff --git a/src/pc_reg.v b/src/pc_reg.v deleted file mode 100644 index 11fe9ba..0000000 --- a/src/pc_reg.v +++ /dev/null @@ -1,18 +0,0 @@ -module pc_reg ( - input clk, - input rstn, - - input we, - input [31:0] pc_in, - - output reg [31:0] pc -); - -`include "include/consts.vh" - -always @ (posedge clk or negedge rstn) begin - if (!rstn) pc <= PC_INITIAL; - else if (we) pc <= pc_in; -end - -endmodule diff --git a/src/ram.v b/src/ram.v deleted file mode 100644 index 541096e..0000000 --- a/src/ram.v +++ /dev/null @@ -1,23 +0,0 @@ -module ram #( - parameter N = 32, - parameter SIZE = 1024 -)( - input clk, - input rstn, - input we, - input [N-1:0] addr, - input [N-1:0] data_write, - output reg [N-1:0] data_read -); - -`include "include/log2.vh" - -//(* RAM_STYLE="BLOCK" *) -reg [N-1:0] mem [0:SIZE-1]; - -always @(posedge clk) begin - if (we) mem[addr >> 2] <= data_write; - data_read <= mem[addr >> 2]; -end - -endmodule diff --git a/src/register_file.v b/src/register_file.v deleted file mode 100644 index dda44e8..0000000 --- a/src/register_file.v +++ /dev/null @@ -1,93 +0,0 @@ -module register_file ( - input clk, - input rstn, - - input we, - input [4:0] ra1, - input [4:0] ra2, - input [4:0] wa3, - - input [31:0] wd3, - - output [31:0] rd1, - output [31:0] rd2 -); - -reg [31:0] regs[31:1]; - -// For debugging purposes: -wire [31:0] reg_x0_zero, - reg_x1_ra, - reg_x2_sp, - reg_x3_gp, - reg_x4_tp, - reg_x5_t0, - reg_x6_t1, - reg_x7_t2, - reg_x8_s0_fp, - reg_x9_s1, - reg_x10_a0, - reg_x11_a1, - reg_x12_a2, - reg_x13_a3, - reg_x14_a4, - reg_x15_a5, - reg_x16_a6, - reg_x17_a7, - reg_x18_s2, - reg_x19_s3, - reg_x20_s4, - reg_x21_s5, - reg_x22_s6, - reg_x23_s7, - reg_x24_s8, - reg_x25_s9, - reg_x26_s10, - reg_x27_s11, - reg_x28_t3, - reg_x29_t4, - reg_x30_t5, - reg_x31_t6; - -assign reg_x0_zero = 32'b0; -assign reg_x1_ra = regs[1]; -assign reg_x2_sp = regs[2]; -assign reg_x3_gp = regs[3]; -assign reg_x4_tp = regs[4]; -assign reg_x5_t0 = regs[5]; -assign reg_x6_t1 = regs[6]; -assign reg_x7_t2 = regs[7]; -assign reg_x8_s0_fp = regs[8]; -assign reg_x9_s1 = regs[9]; -assign reg_x10_a0 = regs[10]; -assign reg_x11_a1 = regs[11]; -assign reg_x12_a2 = regs[12]; -assign reg_x13_a3 = regs[13]; -assign reg_x14_a4 = regs[14]; -assign reg_x15_a5 = regs[15]; -assign reg_x16_a6 = regs[16]; -assign reg_x17_a7 = regs[17]; -assign reg_x18_s2 = regs[18]; -assign reg_x19_s3 = regs[19]; -assign reg_x20_s4 = regs[20]; -assign reg_x21_s5 = regs[21]; -assign reg_x22_s6 = regs[22]; -assign reg_x23_s7 = regs[23]; -assign reg_x24_s8 = regs[24]; -assign reg_x25_s9 = regs[25]; -assign reg_x26_s10 = regs[26]; -assign reg_x27_s11 = regs[27]; -assign reg_x28_t3 = regs[28]; -assign reg_x29_t4 = regs[29]; -assign reg_x30_t5 = regs[30]; -assign reg_x31_t6 = regs[31]; - - -assign rd1 = ra1 == 0 ? 32'b0 : regs[ra1]; -assign rd2 = ra2 == 0 ? 32'b0 : regs[ra2]; - -always @ (posedge clk) begin - if (we && (wa3 != 0)) regs[wa3] <= wd3; -end - -endmodule diff --git a/src/register_file_reg.v b/src/register_file_reg.v deleted file mode 100644 index b1bd4fc..0000000 --- a/src/register_file_reg.v +++ /dev/null @@ -1,22 +0,0 @@ -module register_file_reg ( - input clk, - input rstn, - - input [31:0] rd1_in, - input [31:0] rd2_in, - - output reg [31:0] rd1_buf, - output reg [31:0] rd2_buf -); - -always @ (posedge clk or negedge rstn) begin - if (!rstn) begin - rd1_buf <= 32'b0; - rd2_buf <= 32'b0; - end else begin - rd1_buf <= rd1_in; - rd2_buf <= rd2_in; - end -end - -endmodule diff --git a/src/reset_synchronizer.v b/src/reset_synchronizer.v deleted file mode 100644 index b957a4b..0000000 --- a/src/reset_synchronizer.v +++ /dev/null @@ -1,22 +0,0 @@ -module reset_synchronizer ( - input clk, - input rstn_async, - output rstn -); - -reg rstn_meta; -reg rstn_sync_reg; - -always @(posedge clk or negedge rstn_async) begin - if (!rstn_async) begin - rstn_meta <= 1'b0; - rstn_sync_reg <= 1'b0; - end else begin - rstn_meta <= 1'b1; - rstn_sync_reg <= rstn_meta; - end -end - -assign rstn = rstn_sync_reg; - -endmodule \ No newline at end of file diff --git a/src/result_mux.v b/src/result_mux.v deleted file mode 100644 index 3c94617..0000000 --- a/src/result_mux.v +++ /dev/null @@ -1,22 +0,0 @@ -module result_mux ( - input [31:0] src_alu_result, - input [31:0] src_alu_result_buf, - input [31:0] src_data_buf, - - input [1:0] result_src, - - output reg [31:0] result -); - -`include "include/consts.vh" - -always @(*) begin - case (result_src) - RESULT_SRC_DATA_BUF: result = src_data_buf; - RESULT_SRC_ALU_RESULT_BUF: result = src_alu_result_buf; - RESULT_SRC_ALU_RESULT: result = src_alu_result; - default: result = 32'b0; - endcase -end - -endmodule diff --git a/src/rom.v b/src/rom.v deleted file mode 100644 index d93ef07..0000000 --- a/src/rom.v +++ /dev/null @@ -1,24 +0,0 @@ -module rom #( - parameter N = 32, - parameter SIZE = 1024 -)( - input clk, - input [N-1:0] addr, - output reg [N-1:0] data_read -); - -`include "include/log2.vh" - - -//(* RAM_STYLE="BLOCK" *) -reg [N-1:0] mem [0:SIZE-1]; - -initial begin - $readmemh("build/rom.hex", mem, 0, SIZE-1); -end - -always @(negedge clk) begin - data_read <= mem[addr >> 2]; -end - -endmodule diff --git a/src/shift_unit.v b/src/shift_unit.v deleted file mode 100644 index ea83e4a..0000000 --- a/src/shift_unit.v +++ /dev/null @@ -1,21 +0,0 @@ -module shift_unit ( - input signed [31:0] a, - input [4:0] b, - - input [1:0] op, - - output reg [31:0] result -); - -`include "include/consts.vh" - -always @ (*) begin - case (op) - SHIFT_OP_SLL: result = a << b; // SLL - SHIFT_OP_SRL: result = a >> b; // SRL - SHIFT_OP_SRA: result = a >>> b; // SRA - default: result = 32'b0; - endcase -end - -endmodule diff --git a/src/top.v b/src/top.v deleted file mode 100644 index b10fbca..0000000 --- a/src/top.v +++ /dev/null @@ -1,38 +0,0 @@ -module top ( - input clk, - input key, - input rst, - output [5:0] led -); - -wire rstn, rstn_async, clk_cpu; -assign rstn_async = rst; - -wire [31:0] io_in; -wire [31:0] io_out; - -reset_synchronizer reset_synchronizer ( - .clk(clk), - .rstn_async(rstn_async), - .rstn(rstn) -); - -clock_divider #(.N(1)) clkdiv ( - .clk(clk), - .rstn(rstn), - .clk_div(clk_cpu) -); - -assign led[0] = ~clk_cpu; -assign led[5:1] = ~io_out[4:0]; -assign io_in[0] = key; - - -cpu cpu ( - .clk(clk_cpu), - .rstn(rstn), - .io_in(io_in), - .io_out(io_out) -); - -endmodule -- cgit v1.2.3