diff --git a/core/alu_unit.sv b/core/alu_unit.sv index 2921c1f..d61e9e8 100755 --- a/core/alu_unit.sv +++ b/core/alu_unit.sv @@ -27,7 +27,6 @@ import taiga_types::*; module alu_unit( input logic clk, input logic rst, - input logic single_cycle_issue_possible, unit_issue_interface.unit issue, input alu_inputs_t alu_inputs, unit_writeback_interface.unit wb @@ -78,7 +77,7 @@ module alu_unit( //////////////////////////////////////////////////// //Output - assign issue.ready = single_cycle_issue_possible;//single_cycle_issue_possible; + assign issue.ready = 1; assign wb.rd = result; assign wb.done = issue.new_request; assign wb.id = issue.id; diff --git a/core/csr_regs.sv b/core/csr_regs.sv index 186e9e4..2ed4d2d 100755 --- a/core/csr_regs.sv +++ b/core/csr_regs.sv @@ -59,7 +59,7 @@ module csr_regs //WB input logic instruction_retired, - + input logic [$clog2(MAX_COMPLETE_COUNT)-1:0] retire_inc, //External input logic interrupt, @@ -491,22 +491,13 @@ endgenerate //////////////////////////////////////////////////// //Timers and Counters //Register increment for instructions completed - logic instruction_completed; - assign instruction_completed = instruction_retired & ~gc_supress_writeback; - always_ff @(posedge clk) begin - if (rst) - inst_ret_inc <= 0; - else - inst_ret_inc <= INST_RET_INC_W'(instruction_completed) + INST_RET_INC_W'(instruction_issued_no_rd); - end - always_ff @(posedge clk) begin if (rst) begin mcycle <= 0; minst_ret <= 0; end else begin mcycle <= mcycle + 1; - minst_ret <= minst_ret + COUNTER_W'(inst_ret_inc); + minst_ret <= minst_ret + COUNTER_W'(retire_inc); end end diff --git a/core/decode_and_issue.sv b/core/decode_and_issue.sv index 6bde868..369e5e4 100755 --- a/core/decode_and_issue.sv +++ b/core/decode_and_issue.sv @@ -35,7 +35,10 @@ module decode_and_issue ( input logic [31:0] decode_pc, input logic [31:0] decode_instruction, - register_file_issue_interface.issue rf_issue, + output issue_packet_t issue, + input logic [31:0] rs1_data, + input logic [31:0] rs2_data, + input id_t rs2_id, output alu_inputs_t alu_inputs, output load_store_inputs_t ls_inputs, @@ -51,10 +54,14 @@ module decode_and_issue ( input logic gc_issue_flush, 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, output logic instruction_issued, - output id_t issue_id, - output logic issue_stage_valid, + output logic id_issued, output logic instruction_issued_no_rd, output logic instruction_issued_with_rd, @@ -91,6 +98,11 @@ module decode_and_issue ( logic uses_rs1; logic uses_rs2; logic uses_rd; + logic uses_rs1_issue_stage; + logic uses_rs2_issue_stage; + logic uses_rd_issue_stage; + + logic rd_zero; logic [4:0] rs1_addr; @@ -101,6 +113,8 @@ module decode_and_issue ( logic environment_op; logic nop; + logic issue_stage_valid; + id_t issue_id; logic issue_valid; logic operands_ready; logic [NUM_UNITS-1:0] unit_operands_ready; @@ -112,18 +126,20 @@ module decode_and_issue ( logic [NUM_UNITS-1:0] unit_needed_issue_stage; logic [NUM_UNITS-1:0] unit_ready; logic [NUM_UNITS-1:0] issue_ready; - logic [NUM_UNITS-1:0] issue; + logic [NUM_UNITS-1:0] issue_to; logic illegal_instruction_pattern; logic issue_stage_ready; + logic rs1_conflict; + logic rs2_conflict; + logic [2:0] fn3_issue_stage; logic [6:0] opcode_issue_stage; logic [4:0] rs1_addr_issue_stage; logic [4:0] rs2_addr_issue_stage; logic [4:0] rd_addr_issue_stage; - logic uses_rd_issue_stage; logic [31:0] pc_issue_stage; logic [31:0] instruction_issue_stage; @@ -149,8 +165,10 @@ module decode_and_issue ( rs1_addr_issue_stage <= rs1_addr; rs2_addr_issue_stage <= rs2_addr; rd_addr_issue_stage <= rd_addr; - uses_rd_issue_stage <= uses_rd; issue_id <= decode_id; + uses_rs1_issue_stage <= uses_rs1; + uses_rs2_issue_stage <= uses_rs2; + uses_rd_issue_stage <= uses_rd; end end @@ -175,19 +193,16 @@ module decode_and_issue ( assign nop = (opcode_trim inside {LUI_T, AUIPC_T, ARITH_T, ARITH_IMM_T} && rd_zero); //////////////////////////////////////////////////// - //Register File interface inputs - assign rf_issue.rs1_addr = rs1_addr_issue_stage; - assign rf_issue.rs2_addr = rs2_addr_issue_stage; - assign rf_issue.rd_addr = rd_addr_issue_stage; - - always_ff @(posedge clk) begin - if (issue_stage_ready) begin - rf_issue.uses_rs1 <= uses_rs1; - rf_issue.uses_rs2 <= uses_rs2; - end - end - assign rf_issue.instruction_issued = instruction_issued_with_rd & (|rd_addr_issue_stage); - assign rf_issue.id = issue_id; + //Issue stage general outputs + assign issue.rs1_addr = rs1_addr_issue_stage; + assign issue.rs2_addr = rs2_addr_issue_stage; + assign issue.rd_addr = rd_addr_issue_stage; + assign issue.uses_rs1 = uses_rs1_issue_stage; + assign issue.uses_rs2 = uses_rs2_issue_stage; + assign issue.uses_rd = uses_rd_issue_stage; + assign issue.id = issue_id; + assign issue.stage_valid = issue_stage_valid; + assign issue.issued = instruction_issued; //////////////////////////////////////////////////// //Unit Determination @@ -220,17 +235,20 @@ module decode_and_issue ( //Issue Determination assign issue_valid = issue_stage_valid & ~gc_issue_hold & ~gc_fetch_flush; - assign operands_ready = ~rf_issue.rs1_conflict & ~rf_issue.rs2_conflict; + assign rs1_conflict = rs1_inuse & rs1_id_inuse & uses_rs1_issue_stage; + assign rs2_conflict = rs2_inuse & rs2_id_inuse & uses_rs2_issue_stage; + + + assign operands_ready = ~rs1_conflict & ~rs2_conflict; //All units share the same operand ready logic except load-store which has an internal forwarding path always_comb begin unit_operands_ready = {NUM_UNITS{operands_ready}}; - unit_operands_ready[LS_UNIT_WB_ID] = ~rf_issue.rs1_conflict & ~rf_issue.rs2_conflict; - unit_operands_ready[BRANCH_UNIT_ID] &= unit_ready[ALU_UNIT_WB_ID]; + unit_operands_ready[LS_UNIT_WB_ID] = ~rs1_conflict & ~rs2_conflict; end assign issue_ready = unit_needed_issue_stage & unit_ready; - assign issue = {NUM_UNITS{issue_valid}} & unit_operands_ready & issue_ready; + assign issue_to = {NUM_UNITS{issue_valid}} & unit_operands_ready & issue_ready; assign instruction_issued = issue_valid & |(unit_operands_ready & issue_ready); assign instruction_issued_no_rd = instruction_issued & ~uses_rd_issue_stage; @@ -277,14 +295,14 @@ module decode_and_issue ( case(alu_rs1_sel_r) ALU_RS1_ZERO : alu_rs1_data = '0; ALU_RS1_PC : alu_rs1_data = pc_issue_stage; - default : alu_rs1_data = rf_issue.rs1_data; //ALU_RS1_RF + default : alu_rs1_data = rs1_data; //ALU_RS1_RF endcase case(alu_rs2_sel_r) ALU_RS2_LUI_AUIPC : alu_rs2_data = {instruction_issue_stage[31:12], 12'b0}; ALU_RS2_ARITH_IMM : alu_rs2_data = 32'(signed'(instruction_issue_stage[31:20])); ALU_RS2_JAL_JALR : alu_rs2_data = 4; - ALU_RS2_RF : alu_rs2_data = rf_issue.rs2_data; + ALU_RS2_RF : alu_rs2_data = rs2_data; endcase end @@ -332,10 +350,10 @@ module decode_and_issue ( assign alu_inputs.slt_path = alu_slt_path; - assign alu_inputs.in1 = {(rf_issue.rs1_data[XLEN-1] & ~fn3_issue_stage[0]), alu_rs1_data};//(fn3[0] is SLTU_fn3); + assign alu_inputs.in1 = {(rs1_data[XLEN-1] & ~fn3_issue_stage[0]), alu_rs1_data};//(fn3[0] is SLTU_fn3); assign alu_inputs.in2 = {(alu_rs2_data[XLEN-1] & ~fn3_issue_stage[0]), alu_rs2_data}; - assign alu_inputs.shifter_in = rf_issue.rs1_data; - assign alu_inputs.shift_amount = opcode_issue_stage[5] ? rf_issue.rs2_data[4:0] : rs2_addr_issue_stage; + assign alu_inputs.shifter_in = rs1_data; + assign alu_inputs.shift_amount = opcode_issue_stage[5] ? rs2_data[4:0] : rs2_addr_issue_stage; //////////////////////////////////////////////////// //Load Store unit inputs @@ -380,10 +398,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 : fn3_issue_stage; - assign ls_inputs.rs1 = rf_issue.rs1_data; - assign ls_inputs.rs2 = rf_issue.rs2_data; - assign ls_inputs.forwarded_store = 0;//rf_issue.rs2_conflict; - assign ls_inputs.store_forward_id = rf_issue.rs2_id; + assign ls_inputs.rs1 = rs1_data; + assign ls_inputs.rs2 = rs2_data; + assign ls_inputs.forwarded_store = 0;//rs2_conflict; + assign ls_inputs.store_forward_id = rs2_id; //////////////////////////////////////////////////// //Branch unit inputs @@ -443,8 +461,8 @@ module decode_and_issue ( assign branch_inputs.issue_pc = pc_issue_stage; assign branch_inputs.issue_pc_valid = issue_stage_valid; - assign branch_inputs.rs1 = rf_issue.rs1_data; - assign branch_inputs.rs2 = rf_issue.rs2_data; + assign branch_inputs.rs1 = rs1_data; + assign branch_inputs.rs2 = rs2_data; //////////////////////////////////////////////////// @@ -483,17 +501,17 @@ module decode_and_issue ( assign gc_inputs.instruction = instruction_issue_stage; assign gc_inputs.is_csr = is_csr_r; assign gc_inputs.is_fence = is_fence; - assign gc_inputs.is_i_fence = ENABLE_M_MODE & issue[GC_UNIT_ID] & is_ifence_r; + assign gc_inputs.is_i_fence = ENABLE_M_MODE & issue_to[GC_UNIT_ID] & is_ifence_r; - assign gc_inputs.rs1 = rf_issue.rs1_data; - assign gc_inputs.rs2 = rf_issue.rs2_data; - assign gc_flush_required = ENABLE_M_MODE && issue[GC_UNIT_ID] && potential_flush; + assign gc_inputs.rs1 = rs1_data; + assign gc_inputs.rs2 = rs2_data; + 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 = rf_issue.rs1_data; - assign mul_inputs.rs2 = rf_issue.rs2_data; + assign mul_inputs.rs1 = rs1_data; + assign mul_inputs.rs2 = rs2_data; assign mul_inputs.op = fn3_issue_stage[1:0]; end endgenerate @@ -508,7 +526,7 @@ module decode_and_issue ( logic current_op_resuses_rs1_rs2; always_ff @(posedge clk) begin - if (issue[DIV_UNIT_WB_ID]) begin + if (issue_to[DIV_UNIT_WB_ID]) begin prev_div_rs1_addr <= rs1_addr; prev_div_rs2_addr <= rs2_addr; end @@ -527,8 +545,8 @@ module decode_and_issue ( .result(prev_div_result_valid) ); - assign div_inputs.rs1 = rf_issue.rs1_data; - assign div_inputs.rs2 = rf_issue.rs2_data; + assign div_inputs.rs1 = rs1_data; + assign div_inputs.rs2 = rs2_data; assign div_inputs.op = fn3_issue_stage[1:0]; assign div_inputs.reuse_result = prev_div_result_valid & current_op_resuses_rs1_rs2; end endgenerate @@ -537,10 +555,10 @@ module decode_and_issue ( //Unit EX signals generate for (i = 0; i < NUM_UNITS; i++) begin assign unit_issue[i].possible_issue = unit_needed_issue_stage[i] & unit_operands_ready[i] & issue_stage_valid & ~gc_issue_hold; - assign unit_issue[i].new_request = issue[i]; + assign unit_issue[i].new_request = issue_to[i]; assign unit_issue[i].id = issue_id; always_ff @(posedge clk) begin - unit_issue[i].new_request_r <= issue[i]; + unit_issue[i].new_request_r <= issue_to[i]; end end endgenerate diff --git a/core/gc_unit.sv b/core/gc_unit.sv index 91cc7e6..839deed 100644 --- a/core/gc_unit.sv +++ b/core/gc_unit.sv @@ -57,6 +57,7 @@ module gc_unit( //ID Management output logic system_op_or_exception_complete, + output logic exception_with_rd_complete, output id_t system_op_or_exception_id, //Exception @@ -64,9 +65,8 @@ module gc_unit( input logic [31:0] exception_pc, //WB + input logic [$clog2(MAX_COMPLETE_COUNT)-1:0] retire_inc, input logic instruction_retired, - input logic instruction_queue_empty, - input logic writeback_is_idle, //unit_writeback_interface.unit gc_wb, //External @@ -192,6 +192,7 @@ module gc_unit( assign system_op_or_exception_complete = (issue.new_request & (gc_inputs.is_fence | gc_inputs.is_i_fence)) | gc_exception.valid; + assign exception_with_rd_complete = ls_exception.valid; assign system_op_or_exception_id = issue.new_request ? issue.id : exception_id; //Instruction decode @@ -331,7 +332,7 @@ module gc_unit( .result(processing_csr) ); - assign csr_ready_to_complete = processing_csr & ls_is_idle & writeback_is_idle; + assign csr_ready_to_complete = processing_csr & ls_is_idle; always_ff @(posedge clk) begin csr_ready_to_complete_r <= csr_ready_to_complete; csr_id <= instruction_id; diff --git a/core/id_management.sv b/core/id_management.sv index 3a4ee50..90191f5 100644 --- a/core/id_management.sv +++ b/core/id_management.sv @@ -46,10 +46,11 @@ module id_management output logic decode_id_valid, //Issue stage - input id_t issue_id, - input logic issue_stage_valid, - input logic dummy_id_complete, - input logic id_issued, + input issue_packet_t issue, + input id_t rs1_id, + input id_t rs2_id, + output logic rs1_id_inuse, + output logic rs2_id_inuse, //ID freeing input logic store_complete, @@ -59,10 +60,13 @@ module id_management input id_t branch_id, input logic system_op_or_exception_complete, + input logic exception_with_rd_complete, input id_t system_op_or_exception_id, - input logic instruction_retired, - input id_t retired_id + input id_t ids_retiring [COMMIT_PORTS], + input logic retired [COMMIT_PORTS], + + output logic [$clog2(MAX_COMPLETE_COUNT)-1:0] retire_inc ); ////////////////////////////////////////// id_t pc_id_i; @@ -71,15 +75,28 @@ module id_management //FIFO to store IDs that have been fetched but not yet decoded fifo_interface #(.DATA_WIDTH(LOG2_MAX_IDS)) fetch_fifo(); - //Toggle memory blocks for tracking completion after issue - logic decoded_toggle_mem [MAX_IDS]; - logic decoded_issued_toggle_mem [MAX_IDS]; - logic issued_toggle_mem [MAX_IDS]; - logic branch_complete_toggle_mem [MAX_IDS]; - logic store_complete_toggle_mem [MAX_IDS]; - logic system_op_or_exception_complete_toggle_mem [MAX_IDS]; - logic retired_toggle_mem [MAX_IDS]; + //Toggle memory results for tracking completion after issue + logic decoded_status; + 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 [$clog2(MAX_COMPLETE_COUNT)-1:0] complete_count; //////////////////////////////////////////////////// //Implementation @@ -126,59 +143,144 @@ module id_management //TODO: support arbitrary rst assertion (clear signal from global control) //Instruction decoded and (issued or flushed) pair - initial decoded_toggle_mem = '{default: 0}; - always_ff @ (posedge clk) begin - if (decode_advance & ~gc_fetch_flush) - decoded_toggle_mem[decode_id] <= ~decoded_toggle_mem[decode_id]; - end + toggle_memory decode_toggle_mem ( + .clk, .rst, + .toggle(decode_advance & ~gc_fetch_flush), + .toggle_id(decode_id), + .read_id(pc_id_i), + .read_data(decoded_status) + ); - initial decoded_issued_toggle_mem = '{default: 0}; - always_ff @ (posedge clk) begin - if (id_issued | (gc_fetch_flush & issue_stage_valid)) - decoded_issued_toggle_mem[issue_id] <= ~decoded_issued_toggle_mem[issue_id]; - end + toggle_memory decoded_issued_toggle_mem ( + .clk, .rst, + .toggle(issue.issued | (gc_fetch_flush & issue.stage_valid)), + .toggle_id(issue.id), + .read_id(pc_id_i), + .read_data(decoded_issued_status) + ); //Post issue status tracking - initial issued_toggle_mem = '{default: 0}; - always_ff @ (posedge clk) begin - if (id_issued) - issued_toggle_mem[issue_id] <= ~issued_toggle_mem[issue_id]; - end + toggle_memory issued_toggle_mem ( + .clk, .rst, + .toggle(issue.issued), + .toggle_id(issue.id), + .read_id(pc_id_i), + .read_data(issued_status) + ); + toggle_memory issued_toggle_mem_rs1 ( + .clk, .rst, + .toggle(issue.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(issue.issued & issue.uses_rd), + .toggle_id(issue.id), + .read_id(rs2_id), + .read_data(issued_status_rs2) + ); - initial branch_complete_toggle_mem = '{default: 0}; - always_ff @ (posedge clk) begin - if (branch_complete) - branch_complete_toggle_mem[branch_id] <= ~branch_complete_toggle_mem[branch_id]; - end + toggle_memory branch_toggle_mem ( + .clk, .rst, + .toggle(branch_complete), + .toggle_id(branch_id), + .read_id(pc_id_i), + .read_data(branch_complete_status) + ); - initial store_complete_toggle_mem = '{default: 0}; - always_ff @ (posedge clk) begin - if (store_complete) - store_complete_toggle_mem[store_id] <= ~store_complete_toggle_mem[store_id]; - end + toggle_memory store_toggle_mem ( + .clk, .rst, + .toggle(store_complete), + .toggle_id(store_id), + .read_id(pc_id_i), + .read_data(store_complete_status) + ); - initial system_op_or_exception_complete_toggle_mem = '{default: 0}; - always_ff @ (posedge clk) begin - if (system_op_or_exception_complete) - system_op_or_exception_complete_toggle_mem[system_op_or_exception_id] <= ~system_op_or_exception_complete_toggle_mem[system_op_or_exception_id]; - end + toggle_memory system_op_or_exception_complete_toggle_mem ( + .clk, .rst, + .toggle(system_op_or_exception_complete), + .toggle_id(system_op_or_exception_id), + .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) + ); + //One memory per commit port + genvar i; + generate for (i = 0; i < COMMIT_PORTS; i++) begin + toggle_memory retired_toggle_mem ( + .clk, .rst, + .toggle(retired[i]), + .toggle_id(ids_retiring[i]), + .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]) + ); + end endgenerate - initial retired_toggle_mem = '{default: 0}; - always_ff @ (posedge clk) begin - if (instruction_retired) - retired_toggle_mem[retired_id] <= ~retired_toggle_mem[retired_id]; + logic id_retired_xor; + logic id_retired_xor_rs1; + logic id_retired_xor_rs2; + always_comb begin + id_retired_xor = 0; + id_retired_xor_rs1 = 0; + id_retired_xor_rs2 = 0; + for (int i = 0; i < COMMIT_PORTS; i++) begin + id_retired_xor ^= retired_status[i]; + id_retired_xor_rs1 ^= retired_status_rs1[i]; + id_retired_xor_rs2^= retired_status_rs2[i]; + end end //Computed one cycle in advance using pc_id_i logic id_not_in_decode_issue; logic id_not_inflight; - assign id_not_in_decode_issue = ~(decoded_toggle_mem[pc_id_i] ^ decoded_issued_toggle_mem[pc_id_i]); + assign id_not_in_decode_issue = ~(decoded_status ^ decoded_issued_status); assign id_not_inflight = - ~(issued_toggle_mem[pc_id_i] ^ - branch_complete_toggle_mem[pc_id_i] ^ - store_complete_toggle_mem[pc_id_i] ^ - system_op_or_exception_complete_toggle_mem[pc_id_i] ^ - retired_toggle_mem[pc_id_i]); + ~(issued_status ^ + branch_complete_status ^ + store_complete_status ^ + system_op_or_exception_complete_status ^ + id_retired_xor); + + //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 ^ + id_retired_xor_rs1); + + assign rs2_id_inuse = + (issued_status_rs2 ^ + exception_with_rd_complete_status_rs2 ^ + id_retired_xor_rs2); always_ff @ (posedge clk) begin if (rst) @@ -187,6 +289,17 @@ module id_management pc_id_available <= id_not_in_decode_issue & id_not_inflight; end + localparam MCC_W = $clog2(MAX_COMPLETE_COUNT); + always_comb begin + complete_count = MCC_W'(branch_complete) + MCC_W'(store_complete) + MCC_W'(system_op_or_exception_complete); + for (int i = 0; i < COMMIT_PORTS; i++) begin + complete_count += MCC_W'(retired[i]); + end + end + always_ff @ (posedge clk) begin + retire_inc <= complete_count; + end + //////////////////////////////////////////////////// //End of Implementation //////////////////////////////////////////////////// diff --git a/core/instruction_metadata.sv b/core/instruction_metadata.sv index b581844..363292b 100644 --- a/core/instruction_metadata.sv +++ b/core/instruction_metadata.sv @@ -43,15 +43,22 @@ module instruction_metadata output logic [31:0] decode_pc, output logic [31:0] decode_instruction, + //Issue stage + input issue_packet_t issue, + output id_t rs1_id, + output id_t rs2_id, + output logic rs1_inuse, + output logic rs2_inuse, + //Branch Predictor input branch_metadata_t branch_metadata_if, input id_t branch_id, output branch_metadata_t branch_metadata_ex, //Writeback/Register File - input id_t retired_id, - output logic [4:0] retired_rd_addr, - + input id_t ids_retiring [COMMIT_PORTS], + output logic [4:0] retired_rd_addr [COMMIT_PORTS], + output id_t id_for_rd [COMMIT_PORTS], //Exception input id_t exception_id, output logic [31:0] exception_pc @@ -62,6 +69,10 @@ module instruction_metadata logic [31:0] instruction_table [MAX_IDS]; logic [$bits(branch_metadata_t)-1:0] branch_metadata_table [MAX_IDS]; logic [31:0] rd_table [MAX_IDS]; + + //Writes to register file + logic uses_rd [MAX_IDS]; + id_t rd_to_id_table [32]; //////////////////////////////////////////////////// //Implementation @@ -83,11 +94,19 @@ module instruction_metadata instruction_table[fetch_id] <= fetch_instruction; end - //rd table - // always_ff @ (posedge clk) begin - // if (instruction_retired) - // rd_table[id_retired] <= retired_rd; - // end + //////////////////////////////////////////////////// + //Operand inuse determination + initial uses_rd = '{default: 0}; + always_ff @ (posedge clk) begin + if (issue.issued) + uses_rd[issue.id] <= issue.uses_rd; + end + + initial rd_to_id_table = '{default: 0}; + always_ff @ (posedge clk) begin + if (issue.issued & issue.uses_rd)//tracks most recently issued instruction that writes to the register file + rd_to_id_table[issue.rd_addr] <= issue.id; + end //////////////////////////////////////////////////// //Outputs @@ -99,8 +118,20 @@ module instruction_metadata //Branch Predictor assign branch_metadata_ex = branch_metadata_table[branch_id]; - //Register File - assign retired_rd_addr = instruction_table[retired_id][11:7]; + //Issue + assign rs1_id = rd_to_id_table[issue.rs1_addr]; + assign rs2_id = rd_to_id_table[issue.rs2_addr]; + + assign rs1_inuse = uses_rd[rs1_id]; + assign rs2_inuse = uses_rd[rs2_id]; + + //Writeback support + always_comb begin + for (int i = 0; i < COMMIT_PORTS; i++) begin + retired_rd_addr[i] = instruction_table[ids_retiring[i]][11:7]; + id_for_rd[i] = rd_to_id_table[retired_rd_addr[i]]; + end + end //Exception Support generate if (ENABLE_M_MODE) begin diff --git a/core/load_store_unit.sv b/core/load_store_unit.sv index 8236edf..5faa14b 100755 --- a/core/load_store_unit.sv +++ b/core/load_store_unit.sv @@ -103,7 +103,6 @@ module load_store_unit ( logic [NUM_SUB_UNITS-1:0] sub_unit_address_match; logic unit_stall; - logic done_r; typedef struct packed{ logic [2:0] fn3; @@ -227,7 +226,7 @@ endgenerate assign units_ready = &unit_ready; assign load_complete = |unit_data_valid; - assign ready_for_issue = units_ready & (~unit_switch_stall) & (~done_r | wb.ack); + assign ready_for_issue = units_ready & (~unit_switch_stall); assign issue.ready = lsq.ready; assign issue_request = lsq.accepted; @@ -242,7 +241,7 @@ endgenerate assign load_attributes.data_in = load_attributes_in; assign load_attributes.push = issue_request & shared_inputs.load; - assign load_attributes.pop = ((done_r | load_complete) & wb.ack); + assign load_attributes.pop = load_complete; assign load_attributes.supress_push = 0; assign stage2_attr = load_attributes.data_out; @@ -317,16 +316,8 @@ endgenerate //////////////////////////////////////////////////// //Output bank - always_ff @ (posedge clk) begin - if (wb.ack) - done_r <= 0; - else if (load_complete) - done_r <= 1; - end - - assign wb.rd = csr_done ? csr_rd : final_load_data; - assign wb.done = csr_done | load_complete | done_r; + assign wb.done = csr_done | load_complete; assign wb.id = csr_done ? csr_id : stage2_attr.id; //////////////////////////////////////////////////// diff --git a/core/regfile_bank_sel.sv b/core/regfile_bank_sel.sv new file mode 100644 index 0000000..00e430e --- /dev/null +++ b/core/regfile_bank_sel.sv @@ -0,0 +1,93 @@ +/* + * Copyright © 2020 Eric Matthews, Lesley Shannon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Initial code developed under the supervision of Dr. Lesley Shannon, + * Reconfigurable Computing Lab, Simon Fraser University. + * + * Author(s): + * Eric Matthews + */ + + +module regfile_bank_sel + import taiga_config::*; + import taiga_types::*; + ( + input logic clk, + input logic rst, + + //Register file + input logic [4:0] rs1_addr, + input logic [4:0] rs2_addr, + + output logic [LOG2_COMMIT_PORTS-1:0] rs1_sel, + output logic [LOG2_COMMIT_PORTS-1:0] rs2_sel, + + //Writeback + input logic[4:0] rd_addr [COMMIT_PORTS], + input rd_retired [COMMIT_PORTS] + + ); + ////////////////////////////////////////// + typedef logic [LOG2_COMMIT_PORTS-1:0] sel_bank_t [32] ; + sel_bank_t sel_bank [COMMIT_PORTS]; + + logic [LOG2_COMMIT_PORTS-1:0] new_bank_sel [COMMIT_PORTS]; + genvar i; + //////////////////////////////////////////////////// + //Implementation + + //////////////////////////////////////////////////// + //New Entry Determination + //New entry is the current port index XORed with the content of all other write ports + //existing memory contents + always_comb begin + for (int i = 0; i < COMMIT_PORTS; i++) begin + new_bank_sel[i] = LOG2_COMMIT_PORTS'(i); + for (int j = 0; j < COMMIT_PORTS; j++) begin + if (j != i) new_bank_sel[i] ^= sel_bank[j][rd_addr[i]]; + end + end + end + + //////////////////////////////////////////////////// + //Memory Blocks + generate for (i = 0; i < COMMIT_PORTS; i++) begin + initial sel_bank[i] = '{default: 0}; + always_ff @ (posedge clk) begin + if (rd_retired[i]) + sel_bank[i][rd_addr[i]] <= new_bank_sel[i]; + end + end endgenerate + + //////////////////////////////////////////////////// + //Outputs + always_comb begin + rs1_sel = 0; + rs2_sel = 0; + for (int i = 0; i < COMMIT_PORTS; i++) begin + rs1_sel ^= sel_bank[i][rs1_addr]; + rs2_sel ^= sel_bank[i][rs2_addr]; + end + end + + //////////////////////////////////////////////////// + //End of Implementation + //////////////////////////////////////////////////// + + //////////////////////////////////////////////////// + //Assertions + +endmodule diff --git a/core/register_file.sv b/core/register_file.sv old mode 100755 new mode 100644 index 190f14f..2f09651 --- a/core/register_file.sv +++ b/core/register_file.sv @@ -20,111 +20,57 @@ * Eric Matthews */ -import taiga_config::*; -import riscv_types::*; -import taiga_types::*; - -module register_file( +module register_file + import taiga_config::*; + import riscv_types::*; + import taiga_types::*; + ( input logic clk, input logic rst, - input logic gc_supress_writeback, - input logic instruction_issued, - register_file_writeback_interface.rf wb, - register_file_issue_interface.rf issue, + //Issue interface + input issue_packet_t issue, + input logic [4:0] rd_addr, + input logic [31:0] new_data, + input logic commit, - //ID Metadata - input logic [4:0] retired_rd_addr, + output logic [31:0] rs1_data, + output logic [31:0] rs2_data + ); - //Trace signals - output logic tr_rs1_forwarding_needed, - output logic tr_rs2_forwarding_needed, - output logic tr_rs1_and_rs2_forwarding_needed - ); + logic [31:0] register_file [32]; + genvar i; + //////////////////////////////////////////////////// + //Implementation - (* ramstyle = "MLAB, no_rw_check" *) logic [XLEN-1:0] register [32]; - (* ramstyle = "MLAB, no_rw_check" *) id_t in_use_by [32]; - - logic rs1_inuse; - logic rs2_inuse; - - logic rs1_feedforward; - logic rs2_feedforward; - - logic valid_write; - logic in_use_match; - ////////////////////////////////////////// + //////////////////////////////////////////////////// + //Register File //Assign zero to r0 and initialize all registers to zero - initial register = '{default: 0}; - initial in_use_by = '{default: 0}; - //Writeback unit does not assert wb.commit when the target register is r0 + initial register_file = '{default: 0}; always_ff @ (posedge clk) begin - if (~gc_supress_writeback & in_use_match) - register[retired_rd_addr] <= wb.rd_data; + if (commit) + register_file[rd_addr] <= new_data; end - - assign in_use_match = (wb.id == in_use_by[retired_rd_addr]) && valid_write; - - reg_inuse inuse (.*, - .clr(1'b0), - .rs1_addr(issue.rs1_addr),.rs2_addr(issue.rs2_addr), .issued_rd_addr(issue.rd_addr), - .retired_rd_addr(retired_rd_addr), - .issued(issue.instruction_issued), - .retired(in_use_match), - .rs1_inuse(rs1_inuse), - .rs2_inuse(rs2_inuse) - ); - - always_ff @ (posedge clk) begin - if (issue.instruction_issued) - in_use_by[issue.rd_addr] <= issue.id; - end - - assign wb.rs1_id = in_use_by[issue.rs1_addr]; - assign wb.rs2_id = in_use_by[issue.rs2_addr]; - assign issue.rs2_id = wb.rs2_id; - - assign valid_write = (|retired_rd_addr) & wb.retiring; - - assign rs1_feedforward = rs1_inuse; - assign rs2_feedforward = rs2_inuse; - - assign issue.rs1_data = rs1_feedforward ? wb.rs1_data : register[issue.rs1_addr]; - assign issue.rs2_data = rs2_feedforward ? wb.rs2_data : register[issue.rs2_addr]; - - assign issue.rs1_conflict = issue.uses_rs1 & rs1_inuse & ~wb.rs1_valid; - assign issue.rs2_conflict = issue.uses_rs2 & rs2_inuse & ~wb.rs2_valid; - - //////////////////////////////////////////////////// - //End of Implementation - //////////////////////////////////////////////////// + assign rs1_data = register_file[issue.rs1_addr]; + assign rs2_data = register_file[issue.rs2_addr]; //////////////////////////////////////////////////// //Assertions - always_ff @ (posedge clk) begin - assert (!(issue.instruction_issued && issue.rd_addr == 0)) else $error("Write to inuse for register x0 occured!"); - end + write_to_zero_reg_assertion: + assert property (@(posedge clk) disable iff (rst) !(commit & rd_addr == 0)) + else $error("Write to zero reg occured!"); //////////////////////////////////////////////////// //Simulation Only - // synthesis translate_off + //synthesis translate_off logic [31:0][31:0] sim_registers_unamed; simulation_named_regfile sim_register; always_comb begin - foreach(register[i]) - sim_registers_unamed[i] = register[i]; + foreach(register_file[i]) + sim_registers_unamed[i] = register_file[i]; sim_register = sim_registers_unamed; end - // synthesis translate_on - - //////////////////////////////////////////////////// - //Trace Interface - generate if (ENABLE_TRACE_INTERFACE) begin - assign tr_rs1_forwarding_needed = instruction_issued & rs1_inuse & issue.uses_rs1 & ~tr_rs1_and_rs2_forwarding_needed; - assign tr_rs2_forwarding_needed = instruction_issued & rs2_inuse & issue.uses_rs2 & ~tr_rs1_and_rs2_forwarding_needed; - assign tr_rs1_and_rs2_forwarding_needed = instruction_issued & (rs1_inuse & issue.uses_rs1) & (rs2_inuse & issue.uses_rs2); - end - endgenerate + //synthesis translate_on endmodule diff --git a/core/register_file_and_writeback.sv b/core/register_file_and_writeback.sv new file mode 100755 index 0000000..b3b88f5 --- /dev/null +++ b/core/register_file_and_writeback.sv @@ -0,0 +1,151 @@ +/* + * Copyright © 2020 Eric Matthews, Lesley Shannon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Initial code developed under the supervision of Dr. Lesley Shannon, + * Reconfigurable Computing Lab, Simon Fraser University. + * + * Author(s): + * Eric Matthews + */ + +module register_file_and_writeback + import taiga_config::*; + import riscv_types::*; + import taiga_types::*; + ( + input logic clk, + input logic rst, + + //Issue interface + input issue_packet_t issue, + output logic [31:0] rs1_data, + output logic [31:0] rs2_data, + + //ID Metadata + output id_t ids_retiring [COMMIT_PORTS], + output logic retired [COMMIT_PORTS], + input logic [4:0] retired_rd_addr [COMMIT_PORTS], + input id_t id_for_rd [COMMIT_PORTS], + //Writeback + unit_writeback_interface.wb unit_wb[NUM_WB_UNITS], + + //Trace signals + output logic tr_rs1_forwarding_needed, + output logic tr_rs2_forwarding_needed, + output logic tr_rs1_and_rs2_forwarding_needed + ); + + //Register File + typedef logic [XLEN-1:0] register_file_t [32]; + register_file_t register_file [COMMIT_PORTS]; + + logic [LOG2_COMMIT_PORTS-1:0] rs1_sel; + logic [LOG2_COMMIT_PORTS-1:0] rs2_sel; + + //Writeback + logic unit_ack [NUM_WB_UNITS]; + //aliases for write-back-interface signals + id_t unit_instruction_id [NUM_WB_UNITS]; + logic unit_done [NUM_WB_UNITS]; + 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]; + + genvar i; + //////////////////////////////////////////////////// + //Implementation + //Re-assigning interface inputs to array types so that they can be dynamically indexed + generate for (i=0; i< NUM_WB_UNITS; i++) begin : wb_interfaces_to_arrays_g + assign unit_instruction_id[i] = unit_wb[i].id; + assign unit_done[i] = unit_wb[i].done; + assign unit_rd[i] = unit_wb[i].rd; + assign unit_wb[i].ack = unit_ack[i]; + end endgenerate + + //////////////////////////////////////////////////// + //Unit select for register file + //Iterating through all commit ports: + // Search for complete units (in fixed unit order) + // Assign to a commit port, mask that unit and commit port + always_comb begin + unit_ack = '{default: 0}; + retiring_unit_select = '{default: 0}; + retired = '{default: 0}; + + for (int i=0; i < COMMIT_PORTS; i++) begin + for (int j=0; j < NUM_WB_UNITS; j++) begin + if (unit_done[j] & ~unit_ack[j] & ~retired[i]) begin + retiring_unit_select[i] = WB_UNITS_WIDTH'(j); + unit_ack[j] = 1; + retired[i] = 1; + end + end + + //ID muxes + ids_retiring[i] = unit_instruction_id[retiring_unit_select[i]]; + end + end + + //////////////////////////////////////////////////// + //Register Files + //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 ( + .clk, .rst, + .issue, + .rd_addr(retired_rd_addr[i]), + .new_data(unit_rd[retiring_unit_select[i]]), + .commit(retired[i] & (|retired_rd_addr[i])), + .rs1_data(rs1_data_set[i]), + .rs2_data(rs2_data_set[i]) + ); + end endgenerate + + //////////////////////////////////////////////////// + //Register File LVT + + //Only update lvt if the retiring instrucion is the most recently issued + //write to a given register. + logic update_lvt [COMMIT_PORTS]; + always_comb begin + for (int i = 0; i < COMMIT_PORTS; i++) + update_lvt[i] = retired[i];// & (id_for_rd[i] == ids_retiring[i]) OR unit is ALU or other single issue + end + + regfile_bank_sel regfile_lvt ( + .clk, .rst, + .rs1_addr(issue.rs1_addr), .rs2_addr(issue.rs2_addr), + .rs1_sel, + .rs2_sel, + .rd_addr(retired_rd_addr), + .rd_retired(update_lvt) + ); + + //////////////////////////////////////////////////// + //Register File Muxing + assign rs1_data = rs1_data_set[rs1_sel]; + assign rs2_data = rs2_data_set[rs2_sel]; + + //////////////////////////////////////////////////// + //End of Implementation + //////////////////////////////////////////////////// + + //////////////////////////////////////////////////// + //Assertions + +endmodule diff --git a/core/taiga.sv b/core/taiga.sv index 160d8b7..1d294ad 100755 --- a/core/taiga.sv +++ b/core/taiga.sv @@ -57,7 +57,9 @@ module taiga ( ras_interface ras(); - register_file_issue_interface rf_issue(); + issue_packet_t issue; + logic [31:0] rs1_data; + logic [31:0] rs2_data; alu_inputs_t alu_inputs; load_store_inputs_t ls_inputs; @@ -98,9 +100,12 @@ module taiga ( logic [31:0] decode_pc; logic [31:0] decode_instruction; //Issue stage - logic issue_stage_valid; - logic dummy_id_complete; - id_t issue_id; + id_t rs1_id; + id_t rs2_id; + logic rs1_inuse; + logic rs2_inuse; + logic rs1_id_inuse; + logic rs2_id_inuse; //Branch predictor branch_metadata_t branch_metadata_if; branch_metadata_t branch_metadata_ex; @@ -110,10 +115,10 @@ module taiga ( logic branch_complete; id_t branch_id; logic system_op_or_exception_complete; + logic exception_with_rd_complete; id_t system_op_or_exception_id; logic instruction_retired; - id_t retired_id; - logic [4:0] retired_rd_addr; + logic [$clog2(MAX_COMPLETE_COUNT)-1:0] retire_inc; //Exception id_t exception_id; logic [31:0] exception_pc; @@ -147,8 +152,10 @@ module taiga ( writeback_store_interface wb_store(); //WB - logic single_cycle_issue_possible; - logic writeback_is_idle; + id_t ids_retiring [COMMIT_PORTS]; + logic retired [COMMIT_PORTS]; + logic [4:0] retired_rd_addr [COMMIT_PORTS]; + id_t id_for_rd [COMMIT_PORTS]; //Trace Interface Signals logic tr_operand_stall; @@ -218,7 +225,10 @@ module taiga ( //////////////////////////////////////////////////// //Decode/Issue decode_and_issue decode_and_issue_block (.*); - register_file register_file_block (.*, .issue(rf_issue), .wb(rf_wb)); + + //////////////////////////////////////////////////// + //Register File and Writeback + register_file_and_writeback register_file_and_writeback_block (.*); //////////////////////////////////////////////////// //Execution Units @@ -243,11 +253,6 @@ module taiga ( div_unit div_unit_block (.*, .issue(unit_issue[DIV_UNIT_WB_ID]), .wb(unit_wb[DIV_UNIT_WB_ID])); endgenerate - //////////////////////////////////////////////////// - //Writeback Mux and Instruction Tracking - write_back write_back_mux (.*); - - //////////////////////////////////////////////////// //End of Implementation //////////////////////////////////////////////////// diff --git a/core/taiga_config.sv b/core/taiga_config.sv index 0551da2..6bece69 100755 --- a/core/taiga_config.sv +++ b/core/taiga_config.sv @@ -165,11 +165,11 @@ package taiga_config; //////////////////////////////////////////////////// //ID limit //MAX_IDS restricted to a power of 2 - parameter MAX_IDS = 32; + parameter MAX_IDS = 64; //////////////////////////////////////////////////// - //Number of Writeback Buffers - parameter WRITEBACK_BUFFERS = 3; + //Number of commit ports + parameter COMMIT_PORTS = 3; //////////////////////////////////////////////////// //Trace Options @@ -187,19 +187,15 @@ package taiga_config; //////////////////////////////////////////////////// //Write-Back Unit IDs - parameter NUM_MULTI_CYCLE_WB_UNITS = 1 + USE_MUL + USE_DIV;//LS - parameter NUM_SINGLE_CYCLE_WB_UNITS = 1;//ALU - - parameter NUM_WB_UNITS = NUM_MULTI_CYCLE_WB_UNITS + NUM_SINGLE_CYCLE_WB_UNITS; - + parameter NUM_WB_UNITS = 2 + USE_MUL + USE_DIV;//ALU and LS parameter NUM_UNITS = NUM_WB_UNITS + 2;//Branch and CSRs - parameter LS_UNIT_WB_ID = 0; + parameter ALU_UNIT_WB_ID = 0; + parameter LS_UNIT_WB_ID = 1; parameter DIV_UNIT_WB_ID = LS_UNIT_WB_ID + USE_DIV; parameter MUL_UNIT_WB_ID = DIV_UNIT_WB_ID + 1; - parameter ALU_UNIT_WB_ID = MUL_UNIT_WB_ID + USE_MUL; //Non-writeback units - parameter BRANCH_UNIT_ID = ALU_UNIT_WB_ID + 1; + parameter BRANCH_UNIT_ID = MUL_UNIT_WB_ID + 1; parameter GC_UNIT_ID = BRANCH_UNIT_ID + 1; //////////////////////////////////////////////////// diff --git a/core/taiga_types.sv b/core/taiga_types.sv index 239f869..c7ce5f8 100755 --- a/core/taiga_types.sv +++ b/core/taiga_types.sv @@ -24,7 +24,10 @@ package taiga_types; import taiga_config::*; import riscv_types::*; + localparam MAX_COMPLETE_COUNT = 3 + COMMIT_PORTS; //Branch + Store + System + COMMIT_PORTS + localparam WB_UNITS_WIDTH = $clog2(NUM_WB_UNITS); + localparam LOG2_COMMIT_PORTS = $clog2(COMMIT_PORTS); typedef logic[$clog2(MAX_IDS)-1:0] id_t; @@ -71,6 +74,17 @@ package taiga_types; logic [BRANCH_PREDICTOR_WAYS-1:0] branch_predictor_update_way; } branch_metadata_t; + typedef struct packed{ + logic[4:0] rs1_addr; + logic[4:0] rs2_addr; + logic[4:0] rd_addr; + logic uses_rs1; + logic uses_rs2; + logic uses_rd; + id_t id; + logic stage_valid; + logic issued; + } issue_packet_t; typedef struct packed{ logic [XLEN:0] in1;//contains sign padding bit for slt operation diff --git a/core/toggle_memory.sv b/core/toggle_memory.sv new file mode 100644 index 0000000..ce839d8 --- /dev/null +++ b/core/toggle_memory.sv @@ -0,0 +1,56 @@ +/* + * Copyright © 2020 Eric Matthews, Lesley Shannon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Initial code developed under the supervision of Dr. Lesley Shannon, + * Reconfigurable Computing Lab, Simon Fraser University. + * + * Author(s): + * Eric Matthews + */ + +module toggle_memory + + import taiga_config::*; + import taiga_types::*; + ( + input logic clk, + input logic rst, + + input logic toggle, + input id_t toggle_id, + + input id_t read_id, + output logic read_data + ); + //////////////////////////////////////////////////// + //Implementation + logic id_toggle_memory [MAX_IDS]; + + initial id_toggle_memory = '{default: 0}; + always_ff @ (posedge clk) begin + if (toggle) + id_toggle_memory[toggle_id] <= ~id_toggle_memory[toggle_id]; + end + + assign read_data = id_toggle_memory[read_id]; + + //////////////////////////////////////////////////// + //End of Implementation + //////////////////////////////////////////////////// + + //////////////////////////////////////////////////// + //Assertions + +endmodule diff --git a/core/write_back.sv b/core/write_back.sv deleted file mode 100755 index 4334d1b..0000000 --- a/core/write_back.sv +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright © 2017-2020 Eric Matthews, Lesley Shannon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Initial code developed under the supervision of Dr. Lesley Shannon, - * Reconfigurable Computing Lab, Simon Fraser University. - * - * Author(s): - * Eric Matthews - */ - -import taiga_config::*; -import riscv_types::*; -import taiga_types::*; - -module write_back( - input logic clk, - input logic rst, - - input logic gc_fetch_flush, - input logic instruction_issued_with_rd, - - unit_writeback_interface.wb unit_wb[NUM_WB_UNITS], - register_file_writeback_interface.writeback rf_wb, - - output logic instruction_retired, - output id_t retired_id, - - output logic single_cycle_issue_possible, - output logic writeback_is_idle, - - //Trace signals - output unit_id_t tr_num_instructions_completing, - output id_t tr_num_instructions_in_flight, - output id_t tr_num_of_instructions_pending_writeback - ); - ////////////////////////////////////// - logic unit_ack [NUM_WB_UNITS]; - //aliases for write-back-interface signals - id_t unit_instruction_id [NUM_WB_UNITS]; - logic unit_done [NUM_WB_UNITS]; - logic [XLEN-1:0] unit_rd [NUM_WB_UNITS]; - //Per-ID muxes for commit buffer - logic [$clog2(NUM_WB_UNITS)-1:0] buffer_unit_select [WRITEBACK_BUFFERS]; - //Commit buffer - typedef struct packed{ - logic [XLEN-1:0] rd; - id_t id; - } commit_buffer_t; - commit_buffer_t commit_buffer [WRITEBACK_BUFFERS]; - logic commit_buffer_valid [WRITEBACK_BUFFERS]; - - id_t id_retiring; - - localparam LOG2_WRITEBACK_BUFFERS = $clog2(WRITEBACK_BUFFERS); - - logic retiring; - logic [$clog2(NUM_WB_UNITS):0] num_units_done; - logic [$clog2(WRITEBACK_BUFFERS):0] num_buffers_ready; - - logic result_ready [WRITEBACK_BUFFERS]; - - logic commit_buffer_ready [WRITEBACK_BUFFERS]; - - logic [LOG2_WRITEBACK_BUFFERS-1:0] commit_buffer_index_retiring; - - genvar i, j; - //////////////////////////////////////////////////// - //Implementation - //Re-assigning interface inputs to array types so that they can be dynamically indexed - generate for (i=0; i< NUM_WB_UNITS; i++) begin : wb_interfaces_to_arrays_g - assign unit_instruction_id[i] = unit_wb[i].id; - assign unit_done[i] = unit_wb[i].done; - assign unit_rd[i] = unit_wb[i].rd; - assign unit_wb[i].ack = unit_ack[i]; - end endgenerate - - //////////////////////////////////////////////////// - //Unit done determination - always_comb begin - num_units_done = 0; - for (int i=0; i < NUM_MULTI_CYCLE_WB_UNITS; i++) begin - num_units_done += ($clog2(NUM_WB_UNITS)+1)'(unit_done[i]); - end - num_buffers_ready = 0; - for (int i=0; i < WRITEBACK_BUFFERS; i++) begin - num_buffers_ready += ($clog2(WRITEBACK_BUFFERS)+1)'(commit_buffer_ready[i]); - end - single_cycle_issue_possible = (($clog2(NUM_WB_UNITS)+1)'(num_buffers_ready) > num_units_done); - end - - //////////////////////////////////////////////////// - //Commit Buffer index retiring - //Priority given to decreasing indices - always_comb begin - commit_buffer_index_retiring = 0; - for (int i=WRITEBACK_BUFFERS-1; i >= 0; i--) begin - if (commit_buffer_valid[i]) - commit_buffer_index_retiring = LOG2_WRITEBACK_BUFFERS'(i); - end - end - - //////////////////////////////////////////////////// - //Commit Buffer ready to accept new data - always_comb begin - for (int i=0; i < WRITEBACK_BUFFERS; i++) begin - commit_buffer_ready[i] = ~commit_buffer_valid[i]; - end - //Can always retire, so if not retiring, this index will not be valid and thus ready to commit to - commit_buffer_ready[commit_buffer_index_retiring] = 1; - end - - //////////////////////////////////////////////////// - //Unit select for writeback buffer - logic commit_buffer_write [WRITEBACK_BUFFERS]; - always_comb begin - unit_ack = '{default: 0}; - buffer_unit_select = '{default: 0}; - commit_buffer_write = '{default: 0}; - for (int i=0; i < WRITEBACK_BUFFERS; i++) begin - for (int j=0; j < NUM_WB_UNITS; j++) begin - if (unit_done[j] & ~unit_ack[j] & ~commit_buffer_write[i]) begin - buffer_unit_select[i] = $clog2(NUM_WB_UNITS)'(j); - unit_ack[j] = commit_buffer_ready[i]; - commit_buffer_write[i] = commit_buffer_ready[i]; - end - end - end - // single_cycle_issue_possible = 0; - // for (int i=0; i < WRITEBACK_BUFFERS; i++) begin - // if (commit_buffer_ready[i] & ~commit_buffer_write[i]) begin - // single_cycle_issue_possible = 1; - // buffer_unit_select[i] = ALU_UNIT_WB_ID; - // commit_buffer_write[i] = 1; - // break; - // end - // end - end - - //////////////////////////////////////////////////// - //Writeback Commit Buffer - always_ff @ (posedge clk) begin - for (int i=0; i < WRITEBACK_BUFFERS; i++) begin - if (rst) - commit_buffer_valid[i] <= 0; - else - commit_buffer_valid[i] <= commit_buffer_write[i] | (commit_buffer_valid[i] & ~commit_buffer_ready[i]); - end - end - - always_ff @ (posedge clk) begin - for (int i=0; i < WRITEBACK_BUFFERS; i++) begin - if (commit_buffer_ready[i]) begin - commit_buffer[i].rd <= unit_rd[buffer_unit_select[i]]; - commit_buffer[i].id <= unit_instruction_id[buffer_unit_select[i]]; - end - end - end - - //////////////////////////////////////////////////// - //Register File Interface - always_comb begin - retiring = 0; - for (int i=0; i < WRITEBACK_BUFFERS; i++) begin - retiring |= commit_buffer_valid[i]; - end - end - - assign id_retiring = commit_buffer[commit_buffer_index_retiring].id; - - //Instruction completion tracking for retired instruction count - assign instruction_retired = retiring; - assign retired_id = id_retiring; - - - assign rf_wb.id = id_retiring; - assign rf_wb.retiring = instruction_retired; - assign rf_wb.rd_data = commit_buffer[commit_buffer_index_retiring].rd; - - //Register bypass for issue operands - logic [WRITEBACK_BUFFERS-1:0] rs1_addr_match; - logic [WRITEBACK_BUFFERS-1:0] rs2_addr_match; - logic [LOG2_WRITEBACK_BUFFERS-1:0] rs1_sel; - logic [LOG2_WRITEBACK_BUFFERS-1:0] rs2_sel; - always_comb begin - writeback_is_idle = 0; - rs1_sel = {LOG2_WRITEBACK_BUFFERS{1'b?}}; - rs2_sel = {LOG2_WRITEBACK_BUFFERS{1'b?}}; - for (int i=0; i < WRITEBACK_BUFFERS; i++) begin - writeback_is_idle |= commit_buffer_valid[i]; - rs1_addr_match[i] = commit_buffer_valid[i] && (commit_buffer[i].id == rf_wb.rs1_id); - rs2_addr_match[i] = commit_buffer_valid[i] && (commit_buffer[i].id == rf_wb.rs2_id); - if (rs1_addr_match[i]) - rs1_sel = LOG2_WRITEBACK_BUFFERS'(i); - if (rs2_addr_match[i]) - rs2_sel = LOG2_WRITEBACK_BUFFERS'(i); - end - writeback_is_idle = ~writeback_is_idle; - end - - assign rf_wb.rs1_valid = |rs1_addr_match; - assign rf_wb.rs2_valid = |rs2_addr_match; - assign rf_wb.rs1_data = commit_buffer[rs1_sel].rd; - assign rf_wb.rs2_data = commit_buffer[rs2_sel].rd; - //////////////////////////////////////////////////// - //End of Implementation - //////////////////////////////////////////////////// - - //////////////////////////////////////////////////// - //Assertions - - //////////////////////////////////////////////////// - //Trace Interface - // instruction_id_t num_of_instructions_pending_writeback; - // generate if (ENABLE_TRACE_INTERFACE) begin - //Checks if any two pairs are set indicating mux contention - // always_comb begin - // tr_num_instructions_completing = 0; - // for (int i=0; i 2 ? 2'b1 : 0; - // end - // end - // endgenerate - -endmodule diff --git a/core/writeback_id_tracking.sv b/core/writeback_id_tracking.sv deleted file mode 100644 index 804a19b..0000000 --- a/core/writeback_id_tracking.sv +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright © 2019 Eric Matthews, Lesley Shannon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Initial code developed under the supervision of Dr. Lesley Shannon, - * Reconfigurable Computing Lab, Simon Fraser University. - * - * Author(s): - * Eric Matthews - */ - -import taiga_config::*; -import taiga_types::*; - -module writeback_id_tracking - ( - input logic clk, - input logic rst, - input logic issued, - input logic retired, - output logic id_available, - output instruction_id_t oldest_id, - output instruction_id_t next_id, - output logic empty - ); - ////////////////////////////////////////// - localparam LOG2_MAX_INFLIGHT_COUNT = $clog2(MAX_INFLIGHT_COUNT); - logic [LOG2_MAX_INFLIGHT_COUNT:0] inflight_count; - //////////////////////////////////////////////////// - //Implementation - always_ff @ (posedge clk) begin - if (rst) - oldest_id <= 0; - else - oldest_id <= oldest_id + LOG2_MAX_INFLIGHT_COUNT'(retired); - end - always_ff @ (posedge clk) begin - if (rst) - next_id <= 0; - else - next_id <= next_id + LOG2_MAX_INFLIGHT_COUNT'(issued); - end - - //Upper bit is id_available - always_ff @ (posedge clk) begin - if (rst) - inflight_count <= '1; - else - inflight_count <= inflight_count + (LOG2_MAX_INFLIGHT_COUNT+1)'(retired) - (LOG2_MAX_INFLIGHT_COUNT+1)'(issued); - end - - assign empty = &inflight_count;//all ones - assign id_available = inflight_count[LOG2_MAX_INFLIGHT_COUNT]; - - //////////////////////////////////////////////////// - //End of Implementation - //////////////////////////////////////////////////// - - //////////////////////////////////////////////////// - //Assertions - always_ff @ (posedge clk) begin - assert (rst | !(~rst & ~id_available & issued)) else $error("Issued without valid ID!"); - assert (rst | !(~rst & empty & (retired & ~issued))) else $error("Retired without any instruction inflight!"); - end -endmodule diff --git a/tools/taiga_compile_order b/tools/taiga_compile_order index 457f62a..87d4f56 100644 --- a/tools/taiga_compile_order +++ b/tools/taiga_compile_order @@ -98,10 +98,9 @@ ../core/illegal_instruction_checker.sv ../core/decode_and_issue.sv -../core/reg_inuse.sv -../core/register_file.sv - -../core/write_back.sv +../core/regfile_bank_sel.sv +../core/register_file.sv +../core/register_file_and_writeback.sv ../core/placer_randomizer.sv @@ -110,6 +109,7 @@ ../l2_arbiter/l2_round_robin.sv ../l2_arbiter/l2_arbiter.sv +../core/toggle_memory.sv ../core/id_management.sv ../core/instruction_metadata.sv