diff --git a/core/decode_and_issue.sv b/core/decode_and_issue.sv index 83a0dd6..5548823 100755 --- a/core/decode_and_issue.sv +++ b/core/decode_and_issue.sv @@ -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 diff --git a/core/id_management.sv b/core/id_management.sv index 5767ab0..0fe4a94 100644 --- a/core/id_management.sv +++ b/core/id_management.sv @@ -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) diff --git a/core/instruction_metadata.sv b/core/instruction_metadata.sv index c58bfc4..39616ab 100644 --- a/core/instruction_metadata.sv +++ b/core/instruction_metadata.sv @@ -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 diff --git a/core/register_file.sv b/core/register_file.sv index 2f09651..f38542b 100644 --- a/core/register_file.sv +++ b/core/register_file.sv @@ -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 diff --git a/core/register_file_and_writeback.sv b/core/register_file_and_writeback.sv index 7533507..665db14 100755 --- a/core/register_file_and_writeback.sv +++ b/core/register_file_and_writeback.sv @@ -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 diff --git a/core/riscv_types.sv b/core/riscv_types.sv index c916a54..3ee504d 100644 --- a/core/riscv_types.sv +++ b/core/riscv_types.sv @@ -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; diff --git a/core/taiga.sv b/core/taiga.sv index 98510ea..3523900 100755 --- a/core/taiga.sv +++ b/core/taiga.sv @@ -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; diff --git a/core/taiga_config.sv b/core/taiga_config.sv index 6bece69..2775b18 100755 --- a/core/taiga_config.sv +++ b/core/taiga_config.sv @@ -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 diff --git a/core/taiga_types.sv b/core/taiga_types.sv index 8c5e22a..26795b6 100755 --- a/core/taiga_types.sv +++ b/core/taiga_types.sv @@ -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;