From acf0f7243e7b45dc7db8e51c5c7ae659f7ef2bb3 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sun, 29 Oct 2023 08:12:14 +0100 Subject: [PATCH] feat: implement sb, sh, lb, lh support via masking --- src/control_unit.sv | 11 +++++++---- src/cpu.sv | 24 ++++++++++++++++++++++-- src/cpu_types.sv | 2 ++ src/instruction_decoder.sv | 27 +++++++++++++++------------ src/ram.sv | 16 +++++++++++++--- testbench/tb_control_unit.sv | 10 +++++++++- testbench/tb_cpu_simple.sv | 7 +++++++ 7 files changed, 75 insertions(+), 22 deletions(-) diff --git a/src/control_unit.sv b/src/control_unit.sv index 8dfd524..4484e2c 100755 --- a/src/control_unit.sv +++ b/src/control_unit.sv @@ -3,8 +3,8 @@ import cpu_types::*; module control_unit( input [31:0] instruction, - // TODO: mask for: memory in and out - // don't forget zero extension, sign extension... + output memory_mask_t memory_mask, + output memory_sign_extension, // whether to save alu to memory output memory_we, @@ -47,6 +47,8 @@ module control_unit( wire alu_reg_add_one, alu_reg_negate, alu_reg_signed; wire alu_jump_add_one, alu_jump_negate; + wire alu_override; + assign jump_instruction = conditional_jump; instruction_decoder decoder( @@ -55,8 +57,9 @@ module control_unit( .store_memory(memory_we), .load_memory(load_memory), - .load_memory_size(), - .load_memory_sign_extension(), + + .memory_mask(memory_mask), + .memory_sign_extension(memory_sign_extension), .load_pc(load_pc), .store_pc(store_pc), diff --git a/src/cpu.sv b/src/cpu.sv index 7c4bc77..1f4542d 100755 --- a/src/cpu.sv +++ b/src/cpu.sv @@ -12,6 +12,7 @@ module cpu( output [31:0] memory_address, input [31:0] memory_out, output reg [31:0] memory_write, + output memory_mask_t memory_mask, output reg memory_we ); parameter WIDTH = 32; @@ -38,7 +39,23 @@ module cpu( wire jump_instruction, jump_negate_zero; wire jump_taken; - assign memory_write = reg_rd2; + wire memory_sign_extension; + + 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 + + assign memory_write = mem_sext_maybe(.num(reg_rd2), .mask(memory_mask), .sext(memory_sign_extension)); assign memory_address = alu_out; // alu source 1 @@ -76,7 +93,7 @@ module cpu( case (reg_write_src) RD_ALU : reg_write = alu_out; RD_PC_PLUS : reg_write = pc + 4; - RD_MEMORY : reg_write = memory_out; + RD_MEMORY : reg_write = mem_sext_maybe(.num(memory_out), .mask(memory_mask), .sext(memory_sign_extension)); default : ; endcase end @@ -91,6 +108,9 @@ module cpu( .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), diff --git a/src/cpu_types.sv b/src/cpu_types.sv index 06ba518..5d708a5 100755 --- a/src/cpu_types.sv +++ b/src/cpu_types.sv @@ -3,4 +3,6 @@ package cpu_types; typedef enum bit[0:0] { REG_FILE_RS1, PC } alu_1_source_t; typedef enum bit[0:0] { REG_FILE_RS2, IMMEDIATE } alu_2_source_t; typedef enum bit[1:0] { RD_ALU, RD_PC_PLUS, RD_MEMORY } reg_rd_source_t; + + typedef enum bit[1:0] { MEM_BYTE, MEM_HALFWORD, MEM_WORD } memory_mask_t; endpackage diff --git a/src/instruction_decoder.sv b/src/instruction_decoder.sv index 912c145..da48bfe 100755 --- a/src/instruction_decoder.sv +++ b/src/instruction_decoder.sv @@ -1,3 +1,5 @@ +import cpu_types::* ; + module instruction_decoder( input [31:0] instruction, @@ -7,8 +9,8 @@ module instruction_decoder( // whether to load memory to rd output reg load_memory, - output reg [5:0] load_memory_size, - output reg load_memory_sign_extension, + output memory_mask_t memory_mask, + output reg memory_sign_extension, // put alu_jump to alu if conditional_jump // @@ -64,27 +66,27 @@ module instruction_decoder( // load memory mask/size always_comb begin - load_memory_size = 32; - load_memory_sign_extension = 1'b0; + memory_mask = MEM_WORD; + memory_sign_extension = 1'b0; case (funct3) 3'b000: begin - load_memory_size = 8; // sign extends - load_memory_sign_extension = 1'b1; + memory_mask = MEM_BYTE; // sign extends + memory_sign_extension = 1'b1; end 3'b001: begin - load_memory_size = 16; // sign extends - load_memory_sign_extension = 1'b1; + memory_mask = MEM_HALFWORD; // sign extends + memory_sign_extension = 1'b1; end 3'b010: begin - load_memory_size = 32; // sign extends - load_memory_sign_extension = 1'b1; + memory_mask = MEM_WORD; // sign extends + memory_sign_extension = 1'b1; end 3'b100: begin - load_memory_size = 8; // zero extends + memory_mask = MEM_BYTE; // zero extends end 3'b101: begin - load_memory_size = 16; // zero extends + memory_mask = MEM_HALFWORD; // zero extends end default : ; endcase @@ -93,6 +95,7 @@ module instruction_decoder( // immediate load always_comb begin case (instruction_type) + // beware, slli, srai and srli, are I, but have funct7 I : immediate = {{20{instruction[31]}}, instruction[31:20]}; S : immediate = {{20{instruction[31]}}, instruction[31:25], instruction[11:7]}; SB : immediate = {{20{instruction[31]}}, instruction[7], instruction[30:25], instruction[11:8], 1'b0}; diff --git a/src/ram.sv b/src/ram.sv index 3daf617..64da55c 100755 --- a/src/ram.sv +++ b/src/ram.sv @@ -1,13 +1,23 @@ +import cpu_types::*; + module ram ( input clk, we, input [31:0] a, wd, + input memory_mask_t mask, output [31:0] rd); - reg [31:0] RAM[0:127]; + reg [4095:0] RAM; - assign rd = RAM[a[8:2]]; // word aligned + assign rd = RAM[a[11:0] +:32]; // word aligned always @(posedge clk) - if(we) RAM[a[8:2]] <= wd; + if(we) begin + case(mask) + MEM_BYTE: RAM[a[11:0] +:8] <= wd[7:0]; + MEM_HALFWORD: RAM[a[11:0] +:16] <= wd[15:0]; + MEM_WORD: RAM[{a[11:0]} +:32] <= wd[31:0]; + default: ; + endcase + end endmodule diff --git a/testbench/tb_control_unit.sv b/testbench/tb_control_unit.sv index 876d7e1..7bfed2d 100755 --- a/testbench/tb_control_unit.sv +++ b/testbench/tb_control_unit.sv @@ -27,6 +27,9 @@ module tb_control_unit(); wire [4:0] reg_rd; wire reg_we; + memory_mask_t memory_mask; + wire memory_sign_extension; + control_unit uut( .instruction(instruction), .memory_we(memory_we), @@ -44,7 +47,9 @@ module tb_control_unit(); .reg_rs2(reg_rs2), .reg_rd_src(reg_rd_src), .reg_rd(reg_rd), - .reg_we(reg_we) + .reg_we(reg_we), + .memory_mask(memory_mask), + .memory_sign_extension(memory_sign_extension) ); initial begin @@ -103,6 +108,9 @@ module tb_control_unit(); #5 // lui instruction = {20'hA000A, 5'b00001, 7'b0110111}; + #5 + instruction = 32'b1000000000101111101011110010011; + #5 $finish; end diff --git a/testbench/tb_cpu_simple.sv b/testbench/tb_cpu_simple.sv index 12748fd..71c0cfb 100755 --- a/testbench/tb_cpu_simple.sv +++ b/testbench/tb_cpu_simple.sv @@ -1,9 +1,14 @@ + +import cpu_types::*; + module tb_cpu_simple(); reg clk, rst_n; wire [31:0] memory_address, memory_write, memory_out; wire memory_we; + memory_mask_t memory_mask; + wire [31:0] pc; reg [31:0] instruction; @@ -17,12 +22,14 @@ module tb_cpu_simple(); .memory_address(memory_address), .memory_out(memory_out), .memory_write(memory_write), + .memory_mask(memory_mask), .memory_we(memory_we) ); ram memory_inst( .clk(clk), .a(memory_address), + .mask(memory_mask), .we(memory_we), .wd(memory_write), .rd(memory_out) -- 2.48.1