icicle/rv32_mem.sv
Graham Edgecombe 8024a6075f Move result zero/non-zero test to the execute stage
This reduces the amount of logic required and should speed the processor
up slightly, as the critical path had moved from the execute stage to
the branching logic in the mem/fetch stages.
2017-12-30 14:12:23 +00:00

174 lines
5.6 KiB
Systemverilog

`ifndef RV32_MEM
`define RV32_MEM
`include "rv32_branch.sv"
`define RV32_MEM_WIDTH_WORD 2'b00
`define RV32_MEM_WIDTH_HALF 2'b01
`define RV32_MEM_WIDTH_BYTE 2'b10
module rv32_mem (
input clk,
/* control in (from hazard) */
input stall_in,
input flush_in,
/* control in */
input branch_predicted_taken_in,
input valid_in,
input alu_non_zero_in,
input read_in,
input write_in,
input [1:0] width_in,
input zero_extend_in,
input [1:0] branch_op_in,
input [4:0] rd_in,
input rd_write_in,
/* data in */
input [31:0] result_in,
input [31:0] rs2_value_in,
input [31:0] branch_pc_in,
/* data in (from data memory bus) */
input [31:0] data_read_value_in,
/* control out */
output logic valid_out,
output logic branch_mispredicted_out,
output logic [4:0] rd_out,
output logic rd_write_out,
/* control out (to data memory bus) */
output logic data_read_out,
output logic data_write_out,
output logic [3:0] data_write_mask_out,
/* data out */
output logic [31:0] rd_value_out,
output logic [31:0] branch_pc_out,
/* data out (to data memory bus) */
output logic [31:0] data_address_out,
output logic [31:0] data_write_value_out
);
/* branch unit */
rv32_branch_unit branch_unit (
/* control in */
.predicted_taken_in(branch_predicted_taken_in),
.alu_non_zero_in(alu_non_zero_in),
.op_in(branch_op_in),
/* control out */
.mispredicted_out(branch_mispredicted_out)
);
assign branch_pc_out = branch_pc_in;
/* memory access unit */
logic [31:0] mem_read_value;
assign data_read_out = read_in;
assign data_write_out = write_in;
assign data_address_out = result_in;
always_comb begin
/* write port */
if (write_in) begin
case (width_in)
`RV32_MEM_WIDTH_WORD: begin
data_write_value_out = rs2_value_in;
data_write_mask_out = 4'b1111;
end
`RV32_MEM_WIDTH_HALF: begin
case (result_in[0])
2'b0: begin
data_write_value_out = {16'bx, rs2_value_in[15:0]};
data_write_mask_out = 4'b0011;
end
2'b1: begin
data_write_value_out = {rs2_value_in[15:0], 16'bx};
data_write_mask_out = 4'b1100;
end
endcase
end
`RV32_MEM_WIDTH_BYTE: begin
case (result_in[1:0])
2'b00: begin
data_write_value_out = {24'bx, rs2_value_in[7:0]};
data_write_mask_out = 4'b0001;
end
2'b01: begin
data_write_value_out = {16'bx, rs2_value_in[7:0], 8'bx};
data_write_mask_out = 4'b0010;
end
2'b10: begin
data_write_value_out = {8'bx, rs2_value_in[7:0], 16'bx};
data_write_mask_out = 4'b0100;
end
2'b11: begin
data_write_value_out = {rs2_value_in[7:0], 24'bx};
data_write_mask_out = 4'b1000;
end
endcase
end
default: begin
data_write_value_out = 32'bx;
data_write_mask_out = 4'bx;
end
endcase
end else begin
data_write_value_out = 32'bx;
data_write_mask_out = 4'b0;
end
/* read port */
if (read_in) begin
case (width_in)
`RV32_MEM_WIDTH_WORD: begin
mem_read_value = data_read_value_in;
end
`RV32_MEM_WIDTH_HALF: begin
case (result_in[0])
1'b0: mem_read_value = {{16{zero_extend_in ? 1'b0 : data_read_value_in[15]}}, data_read_value_in[15:0]};
1'b1: mem_read_value = {{16{zero_extend_in ? 1'b0 : data_read_value_in[31]}}, data_read_value_in[31:16]};
endcase
end
`RV32_MEM_WIDTH_BYTE: begin
case (result_in[1:0])
2'b00: mem_read_value = {{24{zero_extend_in ? 1'b0 : data_read_value_in[7]}}, data_read_value_in[7:0]};
2'b01: mem_read_value = {{24{zero_extend_in ? 1'b0 : data_read_value_in[15]}}, data_read_value_in[15:8]};
2'b10: mem_read_value = {{24{zero_extend_in ? 1'b0 : data_read_value_in[23]}}, data_read_value_in[23:16]};
2'b11: mem_read_value = {{24{zero_extend_in ? 1'b0 : data_read_value_in[31]}}, data_read_value_in[31:24]};
endcase
end
default: begin
mem_read_value = 32'bx;
end
endcase
end else begin
mem_read_value = 32'bx;
end
end
always_ff @(posedge clk) begin
if (!stall_in) begin
valid_out <= valid_in;
rd_out <= rd_in;
rd_write_out <= rd_write_in;
if (read_in)
rd_value_out <= mem_read_value;
else
rd_value_out <= result_in;
if (flush_in) begin
valid_out <= 0;
rd_write_out <= 0;
end
end
end
endmodule
`endif