parameterized number of read ports on regfile

This commit is contained in:
Eric Matthews 2020-06-07 14:07:33 -07:00
parent 60a463a39f
commit a287a3bb08
9 changed files with 122 additions and 148 deletions

View file

@ -36,9 +36,7 @@ module decode_and_issue (
input logic [31:0] decode_instruction,
output issue_packet_t issue,
input logic [31:0] rs1_data,
input logic [31:0] rs2_data,
input id_t rs2_id,
input logic [31:0] rs_data [REGFILE_READ_PORTS],
output alu_inputs_t alu_inputs,
output load_store_inputs_t ls_inputs,
@ -56,10 +54,9 @@ module decode_and_issue (
output logic gc_flush_required,
//ID Management
input logic rs1_inuse,
input logic rs2_inuse,
input logic rs1_id_inuse,
input logic rs2_id_inuse,
input logic rs_inuse [REGFILE_READ_PORTS],
input id_t rs_id [REGFILE_READ_PORTS],
input logic rs_id_inuse [REGFILE_READ_PORTS],
output logic instruction_issued,
output logic illegal_instruction,
@ -159,8 +156,8 @@ module decode_and_issue (
issue.instruction <= decode_instruction;
issue.fn3 <= fn3;
issue.opcode <= opcode;
issue.rs1_addr <= rs1_addr;
issue.rs2_addr <= rs2_addr;
issue.rs_addr[RS1] <= rs1_addr;
issue.rs_addr[RS2] <= rs2_addr;
issue.rd_addr <= rd_addr;
issue.id <= decode_id;
issue.uses_rs1 <= uses_rs1;
@ -200,8 +197,8 @@ module decode_and_issue (
//Issue Determination
assign issue_valid = issue.stage_valid & ~gc_issue_hold & ~gc_fetch_flush;
assign rs1_conflict = rs1_inuse & rs1_id_inuse & issue.uses_rs1;
assign rs2_conflict = rs2_inuse & rs2_id_inuse & issue.uses_rs2;
assign rs1_conflict = rs_inuse[RS1] & rs_id_inuse[RS1] & issue.uses_rs1;
assign rs2_conflict = rs_inuse[RS2] & rs_id_inuse[RS2] & issue.uses_rs2;
assign operands_ready = ~rs1_conflict & ~rs2_conflict;
@ -295,13 +292,13 @@ module decode_and_issue (
assign alu_inputs.shifter_path = alu_shifter_path;
assign alu_inputs.slt_path = alu_slt_path;
assign alu_rs1_data = rs1_use_regfile ? rs1_data : pre_alu_rs1_r;
assign alu_rs2_data = rs2_use_regfile ? rs2_data : pre_alu_rs2_r;
assign alu_rs1_data = rs1_use_regfile ? rs_data[RS1] : pre_alu_rs1_r;
assign alu_rs2_data = rs2_use_regfile ? rs_data[RS2] : pre_alu_rs2_r;
assign alu_inputs.in1 = {(rs1_data[XLEN-1] & ~issue.fn3[0]), alu_rs1_data};//(fn3[0] is SLTU_fn3);
assign alu_inputs.in1 = {(rs_data[RS1][XLEN-1] & ~issue.fn3[0]), alu_rs1_data};//(fn3[0] is SLTU_fn3);
assign alu_inputs.in2 = {(alu_rs2_data[XLEN-1] & ~issue.fn3[0]), alu_rs2_data};
assign alu_inputs.shifter_in = rs1_data;
assign alu_inputs.shift_amount = issue.opcode[5] ? rs2_data[4:0] : issue.rs2_addr;
assign alu_inputs.shifter_in = rs_data[RS1];
assign alu_inputs.shift_amount = issue.opcode[5] ? rs_data[RS2][4:0] : issue.rs_addr[RS2];
assign alu_issued = issue_to[ALU_UNIT_WB_ID];
@ -348,10 +345,10 @@ module decode_and_issue (
assign ls_inputs.load = is_load_r;
assign ls_inputs.store = is_store_r;
assign ls_inputs.fn3 = amo_op ? LS_W_fn3 : issue.fn3;
assign ls_inputs.rs1 = rs1_data;
assign ls_inputs.rs2 = rs2_data;
assign ls_inputs.rs1 = rs_data[RS1];
assign ls_inputs.rs2 = rs_data[RS2];
assign ls_inputs.forwarded_store = 0;//rs2_conflict;
assign ls_inputs.store_forward_id = rs2_id;
assign ls_inputs.store_forward_id = rs_id[RS2];
////////////////////////////////////////////////////
//Branch unit inputs
@ -411,8 +408,8 @@ module decode_and_issue (
assign branch_inputs.issue_pc = issue.pc;
assign branch_inputs.issue_pc_valid = issue.stage_valid;
assign branch_inputs.rs1 = rs1_data;
assign branch_inputs.rs2 = rs2_data;
assign branch_inputs.rs1 = rs_data[RS1];
assign branch_inputs.rs2 = rs_data[RS2];
////////////////////////////////////////////////////
@ -453,15 +450,15 @@ module decode_and_issue (
assign gc_inputs.is_fence = is_fence;
assign gc_inputs.is_i_fence = ENABLE_M_MODE & issue_to[GC_UNIT_ID] & is_ifence_r;
assign gc_inputs.rs1 = rs1_data;
assign gc_inputs.rs2 = rs2_data;
assign gc_inputs.rs1 = rs_data[RS1];
assign gc_inputs.rs2 = rs_data[RS2];
assign gc_flush_required = ENABLE_M_MODE && issue_to[GC_UNIT_ID] && potential_flush;
////////////////////////////////////////////////////
//Mul unit inputs
generate if (USE_MUL) begin
assign mul_inputs.rs1 = rs1_data;
assign mul_inputs.rs2 = rs2_data;
assign mul_inputs.rs1 = rs_data[RS1];
assign mul_inputs.rs2 = rs_data[RS2];
assign mul_inputs.op = issue.fn3[1:0];
end endgenerate
@ -482,11 +479,11 @@ module decode_and_issue (
end
end
assign current_op_resuses_rs1_rs2 = (prev_div_rs1_addr == issue.rs1_addr) && (prev_div_rs2_addr == issue.rs2_addr);
assign current_op_resuses_rs1_rs2 = (prev_div_rs1_addr == issue.rs_addr[RS1]) && (prev_div_rs2_addr == issue.rs_addr[RS2]);
assign set_prev_div_result_valid = unit_needed_issue_stage[DIV_UNIT_WB_ID];
//If current div operation overwrites an input register OR any other instruction overwrites the last div operations input registers
assign clear_prev_div_result_valid = issue.uses_rd & ((issue.rd_addr == (unit_needed_issue_stage[DIV_UNIT_WB_ID] ? issue.rs1_addr : prev_div_rs1_addr)) || (issue.rd_addr == (unit_needed_issue_stage[DIV_UNIT_WB_ID] ? issue.rs2_addr : prev_div_rs2_addr)));
assign clear_prev_div_result_valid = issue.uses_rd & ((issue.rd_addr == (unit_needed_issue_stage[DIV_UNIT_WB_ID] ? issue.rs_addr[RS1] : prev_div_rs1_addr)) || (issue.rd_addr == (unit_needed_issue_stage[DIV_UNIT_WB_ID] ? issue.rs_addr[RS2] : prev_div_rs2_addr)));
set_clr_reg_with_rst #(.SET_OVER_CLR(0), .WIDTH(1), .RST_VALUE(0)) prev_div_result_valid_m (
.clk, .rst,
@ -495,8 +492,8 @@ module decode_and_issue (
.result(prev_div_result_valid)
);
assign div_inputs.rs1 = rs1_data;
assign div_inputs.rs2 = rs2_data;
assign div_inputs.rs1 = rs_data[RS1];
assign div_inputs.rs2 = rs_data[RS2];
assign div_inputs.op = issue.fn3[1:0];
assign div_inputs.reuse_result = prev_div_result_valid & current_op_resuses_rs1_rs2;
end endgenerate

View file

@ -48,10 +48,8 @@ module id_management
//Issue stage
input issue_packet_t issue,
input logic instruction_issued,
input id_t rs1_id,
input id_t rs2_id,
output logic rs1_id_inuse,
output logic rs2_id_inuse,
input id_t rs_id[REGFILE_READ_PORTS],
output logic rs_id_inuse[REGFILE_READ_PORTS],
//ID freeing
input logic store_complete,
@ -81,23 +79,19 @@ module id_management
logic decoded_issued_status;
logic issued_status;
logic issued_status_rs1;
logic issued_status_rs2;
logic branch_complete_status;
logic branch_complete_status_rs1;
logic branch_complete_status_rs2;
logic store_complete_status;
logic store_complete_status_rs1;
logic store_complete_status_rs2;
logic system_op_or_exception_complete_status;
logic exception_with_rd_complete_status_rs1;
logic exception_with_rd_complete_status_rs2;
logic [COMMIT_PORTS-1:0] retired_status;
logic [COMMIT_PORTS-1:0] retired_status_rs1;
logic [COMMIT_PORTS-1:0] retired_status_rs2;
logic issued_status_rs [REGFILE_READ_PORTS];
logic branch_complete_status;
logic store_complete_status;
logic system_op_or_exception_complete_status;
logic exception_with_rd_complete_status_rs [REGFILE_READ_PORTS];
logic [COMMIT_PORTS-1:0] retired_status;
logic [COMMIT_PORTS-1:0] retired_status_rs [REGFILE_READ_PORTS];
logic [$clog2(MAX_COMPLETE_COUNT)-1:0] complete_count;
genvar i;
////////////////////////////////////////////////////
//Implementation
@ -171,20 +165,15 @@ module id_management
.read_id(pc_id_i),
.read_data(issued_status)
);
toggle_memory issued_toggle_mem_rs1 (
.clk, .rst,
.toggle(instruction_issued & issue.uses_rd),
.toggle_id(issue.id),
.read_id(rs1_id),
.read_data(issued_status_rs1)
);
toggle_memory issued_toggle_mem_rs2 (
.clk, .rst,
.toggle(instruction_issued & issue.uses_rd),
.toggle_id(issue.id),
.read_id(rs2_id),
.read_data(issued_status_rs2)
);
generate for (i = 0; i < REGFILE_READ_PORTS; i++) begin
toggle_memory issued_toggle_mem_rs (
.clk, .rst,
.toggle(instruction_issued & issue.uses_rd),
.toggle_id(issue.id),
.read_id(rs_id[i]),
.read_data(issued_status_rs[i])
);
end endgenerate
toggle_memory branch_toggle_mem (
.clk, .rst,
@ -209,22 +198,19 @@ module id_management
.read_id(pc_id_i),
.read_data(system_op_or_exception_complete_status)
);
toggle_memory exception_complete_toggle_mem_rs1 (
.clk, .rst,
.toggle(exception_with_rd_complete),
.toggle_id(system_op_or_exception_id),
.read_id(rs1_id),
.read_data(exception_with_rd_complete_status_rs1)
);
toggle_memory xception_complete_toggle_mem_rs2 (
.clk, .rst,
.toggle(exception_with_rd_complete),
.toggle_id(system_op_or_exception_id),
.read_id(rs2_id),
.read_data(exception_with_rd_complete_status_rs2)
);
generate for (i = 0; i < REGFILE_READ_PORTS; i++) begin
toggle_memory exception_complete_toggle_mem_rs (
.clk, .rst,
.toggle(exception_with_rd_complete),
.toggle_id(system_op_or_exception_id),
.read_id(rs_id[i]),
.read_data(exception_with_rd_complete_status_rs[i])
);
end endgenerate
//One memory per commit port
genvar i;
genvar j;
generate for (i = 0; i < COMMIT_PORTS; i++) begin
toggle_memory retired_toggle_mem (
.clk, .rst,
@ -233,20 +219,15 @@ module id_management
.read_id(pc_id_i),
.read_data(retired_status[i])
);
toggle_memory retired_toggle_mem_rs1 (
.clk, .rst,
.toggle(retired[i]),
.toggle_id(ids_retiring[i]),
.read_id(rs1_id),
.read_data(retired_status_rs1[i])
);
toggle_memory retired_toggle_mem_rs2 (
.clk, .rst,
.toggle(retired[i]),
.toggle_id(ids_retiring[i]),
.read_id(rs2_id),
.read_data(retired_status_rs2[i])
);
for (j = 0; j < REGFILE_READ_PORTS; j++) begin
toggle_memory retired_toggle_mem_rs (
.clk, .rst,
.toggle(retired[i]),
.toggle_id(ids_retiring[i]),
.read_id(rs_id[j]),
.read_data(retired_status_rs[j][i])
);
end
end endgenerate
//Computed one cycle in advance using pc_id_i
@ -263,17 +244,15 @@ module id_management
//rs1/rs2 conflicts don't check branch or store memories as the only
//IDs stored in the rs to ID table are instructions that write to the register file
assign rs1_id_inuse = (
issued_status_rs1 ^
exception_with_rd_complete_status_rs1 ^
(^retired_status_rs1)
);
assign rs2_id_inuse = (
issued_status_rs2 ^
exception_with_rd_complete_status_rs2 ^
(^retired_status_rs2)
);
always_comb begin
for (int i = 0; i < REGFILE_READ_PORTS; i++) begin
rs_id_inuse[i] = (
issued_status_rs[i] ^
exception_with_rd_complete_status_rs[i] ^
(^retired_status_rs[i])
);
end
end
always_ff @ (posedge clk) begin
if (rst)

View file

@ -46,10 +46,8 @@ module instruction_metadata
//Issue stage
input issue_packet_t issue,
input logic instruction_issued,
output id_t rs1_id,
output id_t rs2_id,
output logic rs1_inuse,
output logic rs2_inuse,
output id_t rs_id [REGFILE_READ_PORTS],
output logic rs_inuse [REGFILE_READ_PORTS],
//Branch Predictor
input branch_metadata_t branch_metadata_if,
@ -113,16 +111,12 @@ module instruction_metadata
assign branch_metadata_ex = branch_metadata_table[branch_id];
//Issue
logic [4:0] rs1_id_rd_addr;
logic [4:0] rs2_id_rd_addr;
assign rs1_id = rd_to_id_table[issue.rs1_addr];
assign rs2_id = rd_to_id_table[issue.rs2_addr];
assign rs1_id_rd_addr = instruction_table[rs1_id][11:7];
assign rs2_id_rd_addr = instruction_table[rs2_id][11:7];
assign rs1_inuse = (issue.rs1_addr == rs1_id_rd_addr);
assign rs2_inuse = (issue.rs2_addr == rs2_id_rd_addr);
always_comb begin
for (int i = 0; i < REGFILE_READ_PORTS; i++) begin
rs_id[i] = rd_to_id_table[issue.rs_addr[i]];
rs_inuse[i] = (issue.rs_addr[i] == instruction_table[rs_id[i]][11:7]);//11:7 is rd_addr
end
end
//Writeback support
always_comb begin

View file

@ -24,22 +24,24 @@ module register_file
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
#(
parameter NUM_READ_PORTS = 2
)
(
input logic clk,
input logic rst,
//Issue interface
input issue_packet_t issue,
//Writeback
input logic [4:0] rd_addr,
input logic [31:0] new_data,
input logic commit,
output logic [31:0] rs1_data,
output logic [31:0] rs2_data
//Issue
input rs_addr_t [NUM_READ_PORTS-1:0] read_addr,
output logic [31:0] data [NUM_READ_PORTS]
);
logic [31:0] register_file [32];
genvar i;
////////////////////////////////////////////////////
//Implementation
@ -52,8 +54,10 @@ module register_file
if (commit)
register_file[rd_addr] <= new_data;
end
assign rs1_data = register_file[issue.rs1_addr];
assign rs2_data = register_file[issue.rs2_addr];
always_comb begin
foreach(read_addr[i])
data[i] = register_file[read_addr[i]];
end
////////////////////////////////////////////////////
//Assertions

View file

@ -31,9 +31,7 @@ module register_file_and_writeback
//Issue interface
input issue_packet_t issue,
input logic alu_issued,
output logic [31:0] rs1_data,
output logic [31:0] rs2_data,
output logic [31:0] rs_data [REGFILE_READ_PORTS],
//ID Metadata
output id_t ids_retiring [COMMIT_PORTS],
output logic retired [COMMIT_PORTS],
@ -63,10 +61,11 @@ module register_file_and_writeback
logic [XLEN-1:0] unit_rd [NUM_WB_UNITS];
//Per-ID muxes for commit buffer
logic [$clog2(NUM_WB_UNITS)-1:0] retiring_unit_select [COMMIT_PORTS];
logic [31:0] rs1_data_set [COMMIT_PORTS];
logic [31:0] rs2_data_set [COMMIT_PORTS];
logic [31:0] retiring_data [COMMIT_PORTS];
typedef logic [31:0] rs_data_set_t [REGFILE_READ_PORTS];
rs_data_set_t rs_data_set [COMMIT_PORTS];
genvar i;
////////////////////////////////////////////////////
//Implementation
@ -110,14 +109,13 @@ module register_file_and_writeback
//Implemented in seperate module as there is not universal tool support for inferring
//arrays of memory blocks.
generate for (i = 0; i < COMMIT_PORTS; i++) begin
register_file register_file_blocks (
register_file #(.NUM_READ_PORTS(REGFILE_READ_PORTS)) register_file_blocks (
.clk, .rst,
.issue,
.rd_addr(retired_rd_addr[i]),
.new_data(retiring_data[i]),
.commit(retired[i] & (|retired_rd_addr[i])),
.rs1_data(rs1_data_set[i]),
.rs2_data(rs2_data_set[i])
.read_addr(issue.rs_addr),
.data(rs_data_set[i])
);
end endgenerate
@ -134,7 +132,7 @@ module register_file_and_writeback
regfile_bank_sel regfile_lvt (
.clk, .rst,
.rs1_addr(issue.rs1_addr), .rs2_addr(issue.rs2_addr),
.rs1_addr(issue.rs_addr[RS1]), .rs2_addr(issue.rs_addr[RS2]),
.rs1_sel,
.rs2_sel,
.rd_addr(retired_rd_addr),
@ -143,8 +141,8 @@ module register_file_and_writeback
////////////////////////////////////////////////////
//Register File Muxing
assign rs1_data = rs1_data_set[rs1_sel];
assign rs2_data = rs2_data_set[rs2_sel];
assign rs_data[RS1] = rs_data_set[rs1_sel][RS1];
assign rs_data[RS2] = rs_data_set[rs2_sel][RS2];
////////////////////////////////////////////////////
//End of Implementation

View file

@ -27,6 +27,8 @@ package riscv_types;
parameter PAGE_ADDR_W = 12;
parameter ECODE_W = 5;
typedef logic [4:0] rs_addr_t;
typedef struct packed {
logic [6:0] fn7;
logic [4:0] rs2_addr;

View file

@ -58,8 +58,8 @@ module taiga (
ras_interface ras();
issue_packet_t issue;
logic [31:0] rs1_data;
logic [31:0] rs2_data;
logic [31:0] rs_data [REGFILE_READ_PORTS];
alu_inputs_t alu_inputs;
load_store_inputs_t ls_inputs;
@ -100,12 +100,9 @@ module taiga (
logic [31:0] decode_pc;
logic [31:0] decode_instruction;
//Issue stage
id_t rs1_id;
id_t rs2_id;
logic rs1_inuse;
logic rs2_inuse;
logic rs1_id_inuse;
logic rs2_id_inuse;
id_t rs_id [REGFILE_READ_PORTS];
logic rs_inuse [REGFILE_READ_PORTS];
logic rs_id_inuse [REGFILE_READ_PORTS];
//Branch predictor
branch_metadata_t branch_metadata_if;
branch_metadata_t branch_metadata_ex;

View file

@ -158,18 +158,23 @@ package taiga_config;
//Branch Predictor Options
parameter USE_BRANCH_PREDICTOR = 1;
parameter BRANCH_PREDICTOR_WAYS = 2;
parameter BRANCH_TABLE_ENTRIES = 512;//min 512
parameter BRANCH_TABLE_ENTRIES = 512; //min 512
parameter RAS_DEPTH = 8;
////////////////////////////////////////////////////
//ID limit
//MAX_IDS restricted to a power of 2
parameter MAX_IDS = 64;
parameter MAX_IDS = 8; //8 sufficient for rv32im configs
////////////////////////////////////////////////////
//Number of commit ports
parameter COMMIT_PORTS = 3;
parameter COMMIT_PORTS = 2; //min 2
parameter REGFILE_READ_PORTS = 2; //min 2, for RS1 and RS2
typedef enum logic {
RS1 = 0,
RS2 = 1
} rs1_index_t;
////////////////////////////////////////////////////
//Trace Options

View file

@ -30,7 +30,6 @@ package taiga_types;
localparam LOG2_COMMIT_PORTS = $clog2(COMMIT_PORTS);
typedef logic[$clog2(MAX_IDS)-1:0] id_t;
typedef logic[WB_UNITS_WIDTH-1:0] unit_id_t;
typedef logic[1:0] branch_predictor_metadata_t;
@ -87,8 +86,7 @@ package taiga_types;
logic [2:0] fn3;
logic [6:0] opcode;
logic [4:0] rs1_addr;
logic [4:0] rs2_addr;
rs_addr_t [REGFILE_READ_PORTS-1:0] rs_addr;//packed style instead of unpacked due to tool limitations
logic [4:0] rd_addr;
logic uses_rs1;