From 871e1f4a328b6376ae1a04744decad037fc16fd0 Mon Sep 17 00:00:00 2001 From: Graham Edgecombe Date: Sun, 3 Dec 2017 16:15:43 +0000 Subject: [PATCH] Add LB, LBU, LH, LHU, SB and SH instructions --- rv32.sv | 12 +++++++ rv32_decode.sv | 17 ++++++++++ rv32_execute.sv | 6 ++++ rv32_mem.sv | 85 +++++++++++++++++++++++++++++++++++++++++++++++-- rv32_mem_ops.sv | 8 +++++ 5 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 rv32_mem_ops.sv diff --git a/rv32.sv b/rv32.sv index 314bd72..7f75807 100644 --- a/rv32.sv +++ b/rv32.sv @@ -53,6 +53,8 @@ module rv32 ( .alu_src2_out(decode_alu_src2), .mem_read_en_out(decode_mem_read_en), .mem_write_en_out(decode_mem_write_en), + .mem_width_out(decode_mem_width), + .mem_zero_extend_out(decode_mem_zero_extend), .branch_op_out(decode_branch_op), .branch_pc_src_out(decode_branch_pc_src), .rd_out(decode_rd), @@ -72,6 +74,8 @@ module rv32 ( logic decode_alu_src2; logic decode_mem_read_en; logic decode_mem_write_en; + logic [1:0] decode_mem_width; + logic decode_mem_zero_extend; logic [1:0] decode_branch_op; logic decode_branch_pc_src; logic [4:0] decode_rd; @@ -93,6 +97,8 @@ module rv32 ( .alu_src2_in(decode_alu_src2), .mem_read_en_in(decode_mem_read_en), .mem_write_en_in(decode_mem_write_en), + .mem_width_in(decode_mem_width), + .mem_zero_extend_in(decode_mem_zero_extend), .branch_op_in(decode_branch_op), .branch_pc_src_in(decode_branch_pc_src), .rd_in(decode_rd), @@ -107,6 +113,8 @@ module rv32 ( /* control out */ .mem_read_en_out(execute_mem_read_en), .mem_write_en_out(execute_mem_write_en), + .mem_width_out(execute_mem_width), + .mem_zero_extend_out(execute_mem_zero_extend), .branch_op_out(execute_branch_op), .rd_out(execute_rd), .rd_writeback_out(execute_rd_writeback), @@ -120,6 +128,8 @@ module rv32 ( /* execute -> mem control */ logic execute_mem_read_en; logic execute_mem_write_en; + logic [1:0] execute_mem_width; + logic execute_mem_zero_extend; logic [1:0] execute_branch_op; logic [4:0] execute_rd; logic execute_rd_writeback; @@ -135,6 +145,8 @@ module rv32 ( /* control in */ .read_en_in(execute_mem_read_en), .write_en_in(execute_mem_write_en), + .width_in(execute_mem_width), + .zero_extend_in(execute_mem_zero_extend), .branch_op_in(execute_branch_op), .rd_in(execute_rd), .rd_writeback_in(execute_rd_writeback), diff --git a/rv32_decode.sv b/rv32_decode.sv index 83dec52..3aace7a 100644 --- a/rv32_decode.sv +++ b/rv32_decode.sv @@ -3,6 +3,7 @@ `include "rv32_alu_ops.sv" `include "rv32_branch_ops.sv" +`include "rv32_mem_ops.sv" `include "rv32_opcodes.sv" `include "rv32_regs.sv" @@ -26,6 +27,8 @@ module rv32_decode ( output alu_src2_out, output mem_read_en_out, output mem_write_en_out, + output [1:0] mem_width_out, + output mem_zero_extend_out, output [1:0] branch_op_out, output branch_pc_src_out, output [4:0] rd_out, @@ -83,6 +86,8 @@ module rv32_decode ( rd_writeback_out <= 0; mem_read_en_out <= 0; mem_write_en_out <= 0; + mem_width_out <= 2'bx; + mem_zero_extend_out <= 1'bx; branch_op_out <= RV32_BRANCH_OP_NEVER; branch_pc_src_out <= 1'bx; imm_out <= 32'bx; @@ -200,6 +205,8 @@ module rv32_decode ( alu_src1_out <= RV32_ALU_SRC1_REG; alu_src2_out <= RV32_ALU_SRC2_IMM; mem_read_en_out <= 1; + mem_width_out <= RV32_MEM_WIDTH_BYTE; + mem_zero_extend_out <= 0; rd_writeback_out <= 1; imm_out <= imm_i; end @@ -211,6 +218,8 @@ module rv32_decode ( alu_src1_out <= RV32_ALU_SRC1_REG; alu_src2_out <= RV32_ALU_SRC2_IMM; mem_read_en_out <= 1; + mem_width_out <= RV32_MEM_WIDTH_HALF; + mem_zero_extend_out <= 0; rd_writeback_out <= 1; imm_out <= imm_i; end @@ -222,6 +231,7 @@ module rv32_decode ( alu_src1_out <= RV32_ALU_SRC1_REG; alu_src2_out <= RV32_ALU_SRC2_IMM; mem_read_en_out <= 1; + mem_width_out <= RV32_MEM_WIDTH_WORD; rd_writeback_out <= 1; imm_out <= imm_i; end @@ -233,6 +243,8 @@ module rv32_decode ( alu_src1_out <= RV32_ALU_SRC1_REG; alu_src2_out <= RV32_ALU_SRC2_IMM; mem_read_en_out <= 1; + mem_width_out <= RV32_MEM_WIDTH_BYTE; + mem_zero_extend_out <= 1; rd_writeback_out <= 1; imm_out <= imm_i; end @@ -244,6 +256,8 @@ module rv32_decode ( alu_src1_out <= RV32_ALU_SRC1_REG; alu_src2_out <= RV32_ALU_SRC2_IMM; mem_read_en_out <= 1; + mem_width_out <= RV32_MEM_WIDTH_HALF; + mem_zero_extend_out <= 1; rd_writeback_out <= 1; imm_out <= imm_i; end @@ -255,6 +269,7 @@ module rv32_decode ( alu_src1_out <= RV32_ALU_SRC1_REG; alu_src2_out <= RV32_ALU_SRC2_IMM; mem_write_en_out <= 1; + mem_width_out <= RV32_MEM_WIDTH_BYTE; imm_out <= imm_s; end {RV32_OPCODE_STORE, RV32_FUNCT3_STORE_SH, RV32_FUNCT7_ANY}: begin @@ -265,6 +280,7 @@ module rv32_decode ( alu_src1_out <= RV32_ALU_SRC1_REG; alu_src2_out <= RV32_ALU_SRC2_IMM; mem_write_en_out <= 1; + mem_width_out <= RV32_MEM_WIDTH_HALF; imm_out <= imm_s; end {RV32_OPCODE_STORE, RV32_FUNCT3_STORE_SW, RV32_FUNCT7_ANY}: begin @@ -275,6 +291,7 @@ module rv32_decode ( alu_src1_out <= RV32_ALU_SRC1_REG; alu_src2_out <= RV32_ALU_SRC2_IMM; mem_write_en_out <= 1; + mem_width_out <= RV32_MEM_WIDTH_WORD; imm_out <= imm_s; end {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_ADD_SUB, RV32_FUNCT7_ANY}: begin diff --git a/rv32_execute.sv b/rv32_execute.sv index fd15d4e..cbac248 100644 --- a/rv32_execute.sv +++ b/rv32_execute.sv @@ -14,6 +14,8 @@ module rv32_execute ( input alu_src2_in, input mem_read_en_in, input mem_write_en_in, + input [1:0] mem_width_in, + input mem_zero_extend_in, input [1:0] branch_op_in, input branch_pc_src_in, input [4:0] rd_in, @@ -28,6 +30,8 @@ module rv32_execute ( /* control out */ output mem_read_en_out, output mem_write_en_out, + output [1:0] mem_width_out, + output mem_zero_extend_out, output [1:0] branch_op_out, output [4:0] rd_out, output rd_writeback_out, @@ -74,6 +78,8 @@ module rv32_execute ( always_ff @(posedge clk) begin mem_read_en_out <= mem_read_en_in; mem_write_en_out <= mem_write_en_in; + mem_width_out <= mem_width_in; + mem_zero_extend_out <= mem_zero_extend_in; branch_op_out <= branch_op_in; rd_out <= rd_in; rd_writeback_out <= rd_writeback_in; diff --git a/rv32_mem.sv b/rv32_mem.sv index a9d7d38..80d9883 100644 --- a/rv32_mem.sv +++ b/rv32_mem.sv @@ -2,6 +2,7 @@ `define RV32_MEM `include "rv32_branch.sv" +`include "rv32_mem_ops.sv" module rv32_mem ( input clk, @@ -9,6 +10,8 @@ module rv32_mem ( /* control in */ input read_en_in, input write_en_in, + input [1:0] width_in, + input zero_extend_in, input [1:0] branch_op_in, input [4:0] rd_in, input rd_writeback_in, @@ -45,12 +48,67 @@ module rv32_mem ( assign branch_pc_out = branch_pc_in; logic [31:0] read_value; + logic [31:0] write_value; + logic [3:0] write_mask; + + always_comb begin + case (width_in) + RV32_MEM_WIDTH_WORD: begin + write_value = rs2_value_in; + write_mask = 4'b1111; + end + RV32_MEM_WIDTH_HALF: begin + case (result_in[0]) + 2'b0: begin + write_value = {rs2_value_in[15:0], 16'bx}; + write_mask = 4'b1100; + end + 2'b1: begin + write_value = {16'bx, rs2_value_in[15:0]}; + write_mask = 4'b0011; + end + endcase + end + RV32_MEM_WIDTH_BYTE: begin + case (result_in[1:0]) + 2'b00: begin + write_value = {rs2_value_in[7:0], 24'bx}; + write_mask = 4'b1000; + end + 2'b01: begin + write_value = {8'bx, rs2_value_in[7:0], 16'bx}; + write_mask = 4'b0100; + end + 2'b10: begin + write_value = {16'bx, rs2_value_in[7:0], 8'bx}; + write_mask = 4'b0010; + end + 2'b11: begin + write_value = {24'bx, rs2_value_in[7:0]}; + write_mask = 4'b0001; + end + endcase + end + default: begin + write_value = 32'bx; + write_mask = 4'bx; + end + endcase + end always_ff @(negedge clk) begin read_value <= data_mem[result_in[31:2]]; - if (write_en_in) - data_mem[result_in[31:2]] <= rs2_value_in; + if (write_en_in) begin + if (write_mask[3]) + data_mem[result_in[31:2]][31:24] <= write_value[31:24]; + if (write_mask[2]) + data_mem[result_in[31:2]][23:16] <= write_value[23:16]; + if (write_mask[1]) + data_mem[result_in[31:2]][15:8] <= write_value[15:8]; + if (write_mask[0]) + data_mem[result_in[31:2]][7:0] <= write_value[7:0]; + end end always_ff @(posedge clk) begin @@ -59,7 +117,28 @@ module rv32_mem ( rd_writeback_out <= rd_writeback_in; result_out <= result_in; - read_value_out <= read_value; + case (width_in) + RV32_MEM_WIDTH_WORD: begin + read_value_out <= read_value; + end + RV32_MEM_WIDTH_HALF: begin + case (result_in[0]) + 1'b0: read_value_out <= {{16{zero_extend_in ? 1'b0 : read_value[31]}}, read_value[31:16]}; + 1'b1: read_value_out <= {{16{zero_extend_in ? 1'b0 : read_value[15]}}, read_value[15:0]}; + endcase + end + RV32_MEM_WIDTH_BYTE: begin + case (result_in[1:0]) + 2'b00: read_value_out <= {{24{zero_extend_in ? 1'b0 : read_value[31]}}, read_value[31:24]}; + 2'b01: read_value_out <= {{24{zero_extend_in ? 1'b0 : read_value[23]}}, read_value[23:16]}; + 2'b10: read_value_out <= {{24{zero_extend_in ? 1'b0 : read_value[15]}}, read_value[15:8]}; + 2'b11: read_value_out <= {{24{zero_extend_in ? 1'b0 : read_value[7]}}, read_value[7:0]}; + endcase + end + default: begin + read_value_out <= 32'bx; + end + endcase end endmodule diff --git a/rv32_mem_ops.sv b/rv32_mem_ops.sv new file mode 100644 index 0000000..60f882b --- /dev/null +++ b/rv32_mem_ops.sv @@ -0,0 +1,8 @@ +`ifndef RV32_MEM_OPS +`define RV32_MEM_OPS + +localparam RV32_MEM_WIDTH_WORD = 2'b00; +localparam RV32_MEM_WIDTH_HALF = 2'b01; +localparam RV32_MEM_WIDTH_BYTE = 2'b10; + +`endif