support for multiple write ports on regfile

This commit is contained in:
Eric Matthews 2020-06-03 11:27:37 -07:00
parent 421385747c
commit 1cf2513700
17 changed files with 656 additions and 571 deletions

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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
////////////////////////////////////////////////////

View file

@ -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

View file

@ -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;
////////////////////////////////////////////////////

93
core/regfile_bank_sel.sv Normal file
View file

@ -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 <ematthew@sfu.ca>
*/
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

116
core/register_file.sv Executable file → Normal file
View file

@ -20,111 +20,57 @@
* Eric Matthews <ematthew@sfu.ca>
*/
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

View file

@ -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 <ematthew@sfu.ca>
*/
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

View file

@ -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
////////////////////////////////////////////////////

View file

@ -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;
////////////////////////////////////////////////////

View file

@ -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

56
core/toggle_memory.sv Normal file
View file

@ -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 <ematthew@sfu.ca>
*/
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

View file

@ -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 <ematthew@sfu.ca>
*/
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<NUM_WB_UNITS; i++) begin
// tr_num_instructions_completing += unit_done[i];
// end
// num_of_instructions_pending_writeback = 0;
// for (int i=0; i<MAX_INFLIGHT_COUNT-1; i++) begin
// num_of_instructions_pending_writeback += ID_W'(id_writeback_pending_r[i]);
// end
// tr_num_instructions_in_flight = tr_num_of_instructions_pending_writeback > 2 ? 2'b1 : 0;
// end
// end
// endgenerate
endmodule

View file

@ -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 <ematthew@sfu.ca>
*/
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

View file

@ -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