diff options
author | Flavian Kaufmann <flavian@flaviankaufmann.ch> | 2024-05-21 13:50:28 +0200 |
---|---|---|
committer | Flavian Kaufmann <flavian@flaviankaufmann.ch> | 2024-05-21 13:50:28 +0200 |
commit | cb0be9e2039569ee7d18657e8f675d1f8369b407 (patch) | |
tree | 91fa71b3960d1ad5217759371143efbdd833d475 /rtl | |
parent | 98d0dd96611dc2c0e444eaf9410f8adf2924c6b5 (diff) | |
download | riscv_cpu-cb0be9e2039569ee7d18657e8f675d1f8369b407.tar.gz riscv_cpu-cb0be9e2039569ee7d18657e8f675d1f8369b407.zip |
restructured project
Diffstat (limited to 'rtl')
-rw-r--r-- | rtl/Makefile | 56 | ||||
-rw-r--r-- | rtl/cst/tangnano9k.cst | 38 | ||||
-rw-r--r-- | rtl/include/consts.vh | 129 | ||||
-rw-r--r-- | rtl/include/log2.vh | 12 | ||||
-rw-r--r-- | rtl/src/alu.v | 47 | ||||
-rw-r--r-- | rtl/src/alu_a_src_mux.v | 25 | ||||
-rw-r--r-- | rtl/src/alu_b_src_mux.v | 21 | ||||
-rw-r--r-- | rtl/src/alu_op_decode.v | 43 | ||||
-rw-r--r-- | rtl/src/alu_result_reg.v | 14 | ||||
-rw-r--r-- | rtl/src/arithmetic_unit.v | 27 | ||||
-rw-r--r-- | rtl/src/clock_divider.v | 29 | ||||
-rw-r--r-- | rtl/src/control_unit.v | 207 | ||||
-rw-r--r-- | rtl/src/cpu.v | 172 | ||||
-rw-r--r-- | rtl/src/data_reg.v | 14 | ||||
-rw-r--r-- | rtl/src/immediate_extend.v | 22 | ||||
-rw-r--r-- | rtl/src/instruction_reg.v | 20 | ||||
-rw-r--r-- | rtl/src/io.v | 30 | ||||
-rw-r--r-- | rtl/src/logic_unit.v | 21 | ||||
-rw-r--r-- | rtl/src/mem_addr_src_mux.v | 20 | ||||
-rw-r--r-- | rtl/src/memory_interface.v | 84 | ||||
-rw-r--r-- | rtl/src/pc_reg.v | 18 | ||||
-rw-r--r-- | rtl/src/ram.v | 23 | ||||
-rw-r--r-- | rtl/src/register_file.v | 93 | ||||
-rw-r--r-- | rtl/src/register_file_reg.v | 22 | ||||
-rw-r--r-- | rtl/src/reset_synchronizer.v | 16 | ||||
-rw-r--r-- | rtl/src/result_mux.v | 22 | ||||
-rw-r--r-- | rtl/src/rom.v | 25 | ||||
-rw-r--r-- | rtl/src/shift_unit.v | 21 | ||||
-rw-r--r-- | rtl/src/top.v | 38 |
29 files changed, 1309 insertions, 0 deletions
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 |