import cpu_types::*; module cpu( input clk, input rst_n, // program memory input [31:0] instruction, output reg [31:0] pc, // ram output [31:0] memory_address, input [31:0] memory_out, output reg [31:0] memory_write, output [3:0] memory_byte_enable, output reg memory_we, output ebreak ); parameter WIDTH = 32; reg [31:0] pc_next; wire pc_src; reg [31:0] alu_1, alu_2; wire alu_1_src, alu_2_src; wire [2:0] alu_op; wire alu_add_one, alu_negate, alu_signed; wire alu_zero; wire [31:0] alu_out; wire [4:0] reg_a_1, reg_a_2, reg_a_w; wire [31:0] reg_rd1, reg_rd2; reg [31:0] reg_write; wire [1:0] reg_write_src; wire reg_we; wire [31:0] immediate; wire jump_instruction, jump_negate_zero; wire jump_taken; wire memory_sign_extension; memory_mask_t memory_mask; function bit[31:0] mem_sext_maybe; input [31:0] num; input memory_mask_t mask; input sext; begin case(mask) MEM_BYTE: return {{(32 - 8){sext & num[7]}}, num[7:0]}; MEM_HALFWORD: return {{(32 - 16){sext & num[15]}}, num[15:0]}; MEM_WORD: return num[31:0]; // rv32i, no 64 bit regs, no sign extension needed default: return 0; endcase end endfunction function bit[3:0] mask_to_mask_bytes; input memory_mask_t mask; begin case(mask) MEM_BYTE: return 4'b0001; MEM_HALFWORD: return 4'b0011; MEM_WORD: return 4'b1111; default: return 0; endcase end endfunction assign memory_byte_enable = mask_to_mask_bytes(.mask(memory_mask)) << memory_address[1:0]; assign memory_write = reg_rd2 << (8*memory_address[1:0]); assign memory_address = alu_out; // alu source 1 always_comb begin case (alu_1_src) REG_FILE_RS1 : alu_1 = reg_rd1; PC : alu_1 = pc; endcase end // alu source 2 always_comb begin case (alu_2_src) REG_FILE_RS2 : alu_2 = reg_rd2; IMMEDIATE : alu_2 = immediate; endcase end // pc source assign jump_taken = jump_instruction && (alu_zero ^ jump_negate_zero); always_comb begin if (ebreak) pc_next = pc; else case (pc_src) PC_PLUS : begin if (jump_taken) pc_next = pc + immediate; else pc_next = pc + 4; end PC_ALU : pc_next = alu_out; endcase end // register file write source // TODO forwarding pipelined, split to two instead always_comb begin case (reg_write_src) RD_ALU : reg_write = alu_out; RD_PC_PLUS : reg_write = pc + 4; RD_MEMORY : reg_write = mem_sext_maybe(.num(memory_out >> (8*memory_address[1:0])), .mask(memory_mask), .sext(memory_sign_extension)); default : ; endcase end control_unit control_unit_inst( .instruction(instruction), .ebreak(ebreak), .immediate(immediate), .alu_op(alu_op), .alu_add_one(alu_add_one), .alu_negate(alu_negate), .alu_signed(alu_signed), .memory_mask(memory_mask), .memory_sign_extension(memory_sign_extension), .memory_we(memory_we), .jump_instruction(jump_instruction), .jump_negate_zero(jump_negate_zero), .pc_src(pc_src), .alu_src_1(alu_1_src), .alu_src_2(alu_2_src), .reg_rd_src(reg_write_src), .reg_rs1(reg_a_1), .reg_rs2(reg_a_2), .reg_rd(reg_a_w), .reg_we(reg_we) ); alu #(.WIDTH(WIDTH)) alu_inst( .a(alu_1), .b(alu_2), .out(alu_out), .op(alu_op), .b_add_one(alu_add_one), .b_negate(alu_negate), .sign(alu_signed), .zero_flag(alu_zero) ); register_file #(.WIDTH(WIDTH), .ADDRESS_LENGTH(5)) register_file_inst( .clk(clk), .a1(reg_a_1), .a2(reg_a_2), .a3(reg_a_w), .we3(reg_we), .wd3(reg_write), .rd1(reg_rd1), .rd2(reg_rd2) ); program_counter program_counter_inst( .clk(clk), .rst_n(rst_n), .pc(pc[11:0]), .pc_next(pc_next[11:0]) ); // program_memory program_memory_inst( // .addr(pc[11:0]), // .instruction(instruction) // ); // ram memory_inst( // .clk(clk), // .a(memory_address), // .we(memory_we), // .wd(memory_write), // .rd(memory_out) // ); endmodule