Decode/Issue cleanup

Signed-off-by: Eric Matthews <ematthew@sfu.ca>
This commit is contained in:
Eric Matthews 2023-04-28 14:18:35 -04:00
parent 17c45f0050
commit 89810cec57
5 changed files with 66 additions and 79 deletions

View file

@ -85,13 +85,11 @@ module decode_and_issue
logic uses_rd;
rs_addr_t decode_rs_addr [REGFILE_READ_PORTS];
logic [$clog2(CONFIG.NUM_WB_GROUPS)-1:0] decode_wb_group;
logic issue_valid;
logic operands_ready;
logic issue_hold;
logic [REGFILE_READ_PORTS-1:0] operand_ready;
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_to;
logic [$clog2(CONFIG.NUM_WB_GROUPS)-1:0] issue_rs_wb_group [REGFILE_READ_PORTS];
@ -99,9 +97,6 @@ module decode_and_issue
logic pre_issue_exception_pending;
logic illegal_instruction_pattern;
logic illegal_instruction_pattern_r;
logic [REGFILE_READ_PORTS-1:0] rs_conflict;
genvar i;
////////////////////////////////////////////////////
@ -109,8 +104,8 @@ module decode_and_issue
//Can move data into issue stage if:
// there is no instruction currently in the issue stage, or
// an instruction could issue (issue_flush, issue_hold and whether the instruction is valid are not needed in this check)
assign issue_stage_ready = ((~issue.stage_valid) | (issue_valid & |issue_ready)) & ~gc.issue_hold;
// an instruction could issue (ignoring gc.fetch_flush)
assign issue_stage_ready = (~issue.stage_valid) | (|issue_to);
assign decode_advance = decode.valid & issue_stage_ready;
//Instruction aliases
@ -132,19 +127,18 @@ module decode_and_issue
////////////////////////////////////////////////////
//Renamer Support
logic [$clog2(CONFIG.NUM_WB_GROUPS)-1:0] renamer_wb_group;
always_comb begin
renamer_wb_group = $clog2(CONFIG.NUM_WB_GROUPS)'(CONFIG.NUM_WB_GROUPS - 1);
decode_wb_group = $clog2(CONFIG.NUM_WB_GROUPS)'(CONFIG.NUM_WB_GROUPS - 1);
if (unit_needed[UNIT_IDS.ALU])
renamer_wb_group = 0;
decode_wb_group = 0;
else if (unit_needed[UNIT_IDS.LS] )
renamer_wb_group = 1;
decode_wb_group = 1;
end
assign renamer.rd_addr = decode_instruction.rd_addr;
assign renamer.rs_addr = decode_rs_addr;
assign renamer.uses_rd = uses_rd;
assign renamer.rd_wb_group = renamer_wb_group;
assign renamer.rd_wb_group = decode_wb_group;
assign renamer.id = decode.id;
////////////////////////////////////////////////////
@ -168,7 +162,7 @@ module decode_and_issue
issue_rs_wb_group <= renamer.rs_wb_group;
issue.rd_addr <= decode_instruction.rd_addr;
issue.phys_rd_addr <= renamer.phys_rd_addr;
issue_rd_wb_group <= renamer_wb_group;
issue_rd_wb_group <= decode_wb_group;
issue.is_multicycle <= ~unit_needed[UNIT_IDS.ALU];
issue.id <= decode.id;
issue.exception_unit <= decode_exception_unit;
@ -190,24 +184,23 @@ module decode_and_issue
end
////////////////////////////////////////////////////
//Unit ready
generate for (i=0; i<NUM_UNITS; i++)
assign unit_ready[i] = unit_issue[i].ready;
//Issue Determination
assign issue_hold = gc.issue_hold | pre_issue_exception_pending;
generate for (i=0; i<REGFILE_READ_PORTS; i++)
assign operand_ready[i] = ~rf.inuse[i] | (rf.inuse[i] & ~issue_uses_rs[i]);
endgenerate
////////////////////////////////////////////////////
//Issue Determination
generate for (i=0; i<REGFILE_READ_PORTS; i++)
assign rs_conflict[i] = rf.inuse[i] & issue_uses_rs[i];
endgenerate
assign operands_ready = ~|rs_conflict;
//Unit EX signals
generate for (i = 0; i < NUM_UNITS; i++) begin : gen_unit_issue_signals
assign unit_issue[i].possible_issue = issue.stage_valid & unit_needed_issue_stage[i] & unit_issue[i].ready;
assign issue_to[i] = unit_issue[i].possible_issue & (&operand_ready) & ~issue_hold;
assign unit_issue[i].new_request = issue_to[i] & ~gc.fetch_flush;
assign unit_issue[i].id = issue.id;
end endgenerate
assign issue_ready = unit_needed_issue_stage & unit_ready;
assign issue_valid = issue.stage_valid & operands_ready & ~gc.issue_hold & ~pre_issue_exception_pending;
assign issue_to = {NUM_UNITS{issue_valid & ~gc.fetch_flush}} & issue_ready;
assign instruction_issued = issue_valid & ~gc.fetch_flush & |issue_ready;
assign instruction_issued = |issue_to & ~gc.fetch_flush;
assign instruction_issued_with_rd = instruction_issued & issue.uses_rd;
////////////////////////////////////////////////////
@ -226,25 +219,15 @@ module decode_and_issue
constant_alu <= ((decode_instruction.upper_opcode inside {LUI_T}) ? '0 : decode.pc) + ((decode_instruction.upper_opcode inside {LUI_T, AUIPC_T}) ? {decode.instruction[31:12], 12'b0} : 4);
end
////////////////////////////////////////////////////
//Unit EX signals
generate for (i = 0; i < NUM_UNITS; i++) begin : gen_unit_issue_signals
assign unit_issue[i].possible_issue = issue.stage_valid & unit_needed_issue_stage[i] & unit_issue[i].ready;
assign unit_issue[i].new_request = issue_to[i];
assign unit_issue[i].id = issue.id;
end endgenerate
////////////////////////////////////////////////////
//Illegal Instruction check
generate if (CONFIG.INCLUDE_M_MODE) begin : gen_decode_exceptions
logic new_exception;
exception_code_t ecode;
exception_code_t ecall_code;
//ECALL and EBREAK captured here, but seperated out when ecode is set
assign illegal_instruction_pattern = ~|unit_needed;
always_ff @(posedge clk) begin
if (rst)
illegal_instruction_pattern_r <= 0;
else if (issue_stage_ready)
illegal_instruction_pattern_r <= illegal_instruction_pattern;
end
//TODO: Consider ways of parameterizing so that any exception generating unit
//can be automatically added to this expression
@ -254,14 +237,13 @@ module decode_and_issue
unit_needed[UNIT_IDS.BR] : decode_exception_unit = BR_EXCEPTION;
default : decode_exception_unit = PRE_ISSUE_EXCEPTION;
endcase
if (illegal_instruction_pattern)
if (~decode.fetch_metadata.ok)
decode_exception_unit = PRE_ISSUE_EXCEPTION;
end
////////////////////////////////////////////////////
//ECALL/EBREAK
//The type of call instruction is depedent on the current privilege level
exception_code_t ecall_code;
always_comb begin
case (current_privilege)
USER_PRIVILEGE : ecall_code = ECALL_U;
@ -271,19 +253,26 @@ module decode_and_issue
endcase
end
always_ff @(posedge clk) begin
if (issue_stage_ready) begin
ecode <=
decode.instruction inside {ECALL} ? ecall_code :
decode.instruction inside {EBREAK} ? BREAK :
illegal_instruction_pattern ? ILLEGAL_INST :
decode.fetch_metadata.error_code; //(~decode.fetch_metadata.ok)
end
end
////////////////////////////////////////////////////
//Exception generation (ecall/ebreak/illegal instruction/propagated fetch error)
logic new_exception;
exception_code_t ecode;
always_ff @(posedge clk) begin
if (rst)
pre_issue_exception_pending <= 0;
else if (issue_stage_ready)
pre_issue_exception_pending <= illegal_instruction_pattern | (~decode.fetch_metadata.ok) | decode.instruction inside {ECALL, EBREAK};
pre_issue_exception_pending <= illegal_instruction_pattern | (~decode.fetch_metadata.ok);
end
assign new_exception = issue.stage_valid & pre_issue_exception_pending & ~(gc.issue_hold | gc.fetch_flush);
assign new_exception = issue.stage_valid & pre_issue_exception_pending & ~(gc.issue_hold | gc.fetch_flush | exception.valid);
always_ff @(posedge clk) begin
if (rst)
@ -292,18 +281,6 @@ module decode_and_issue
exception.valid <= (exception.valid | new_exception) & ~exception.ack;
end
logic is_ecall_r;
always_ff @(posedge clk) begin
if (issue_stage_ready)
is_ecall_r <= (decode_instruction.upper_opcode == SYSTEM_T) & (decode.instruction[31:20] == ECALL_imm);
end
assign ecode =
illegal_instruction_pattern_r ? ILLEGAL_INST :
is_ecall_r ? ecall_code :
~issue.fetch_metadata.ok ? issue.fetch_metadata.error_code :
BREAK;
always_ff @(posedge clk) begin
if (new_exception) begin
exception.code <= ecode;

View file

@ -166,7 +166,7 @@ module gc_unit
assign instruction = decode_stage.instruction;
assign unit_needed =
(CONFIG.INCLUDE_M_MODE & decode_stage.instruction inside {ECALL, EBREAK, MRET}) |
(CONFIG.INCLUDE_M_MODE & decode_stage.instruction inside {MRET}) |
(CONFIG.INCLUDE_S_MODE & decode_stage.instruction inside {SRET, SFENCE_VMA}) |
(CONFIG.INCLUDE_IFENCE & decode_stage.instruction inside {FENCE_I});
always_comb begin

View file

@ -316,7 +316,7 @@ interface unsigned_division_interface #(parameter DATA_WIDTH = 32);
modport divider (output remainder, quotient, done, input dividend, dividend_CLZ, divisor, divisor_CLZ, divisor_is_zero, start);
endinterface
interface renamer_interface #(parameter NUM_WB_GROUPS = 2);
interface renamer_interface #(parameter NUM_WB_GROUPS = 3);
import cva5_config::*;
import riscv_types::*;
import cva5_types::*;
@ -342,7 +342,7 @@ interface renamer_interface #(parameter NUM_WB_GROUPS = 2);
);
endinterface
interface register_file_issue_interface #(parameter NUM_WB_GROUPS = 2);
interface register_file_issue_interface #(parameter NUM_WB_GROUPS = 3);
import cva5_config::*;
import riscv_types::*;
import cva5_types::*;

View file

@ -367,6 +367,11 @@ module cva5_sim
assign darb_stall = cpu.l1_request[L1_DCACHE_ID].request & ~cpu.l1_request[L1_DCACHE_ID].ack;
end endgenerate
logic [`ISSUE_P.NUM_UNITS-1:0] unit_ready;
generate for (i=0; i<`ISSUE_P.NUM_UNITS; i++)
assign unit_ready[i] = cpu.unit_issue[i].ready;
endgenerate
always_comb begin
stats = '{default: '0};
//Fetch
@ -387,9 +392,9 @@ module cva5_sim
base_no_instruction_stall = ~`ISSUE_P.issue.stage_valid | cpu.gc.fetch_flush;
base_no_id_sub_stall = (`METADATA_P.post_issue_count == MAX_IDS);
base_flush_sub_stall = cpu.gc.fetch_flush;
base_unit_busy_stall = `ISSUE_P.issue.stage_valid & ~|`ISSUE_P.issue_ready;
base_operands_stall = `ISSUE_P.issue.stage_valid & ~`ISSUE_P.operands_ready;
base_hold_stall = `ISSUE_P.issue.stage_valid & (cpu.gc.issue_hold | `ISSUE_P.pre_issue_exception_pending);
base_unit_busy_stall = `ISSUE_P.issue.stage_valid & ~|(`ISSUE_P.unit_needed_issue_stage & unit_ready);
base_operands_stall = `ISSUE_P.issue.stage_valid & ~(&`ISSUE_P.operand_ready);
base_hold_stall = `ISSUE_P.issue.stage_valid & `ISSUE_P.issue_hold;
stall_source_count = 4'(base_no_instruction_stall) + 4'(base_unit_busy_stall) + 4'(base_operands_stall) + 4'(base_hold_stall);
single_source_issue_stall = (stall_source_count == 1);
@ -410,9 +415,9 @@ module cva5_sim
//Issue Stall Source
for (int i = 0; i < REGFILE_READ_PORTS; i++) begin
stats[ISSUE_OPERAND_STALL_ON_LOAD_STAT] |= `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.LS] & `ISSUE_P.rs_conflict[i] ;
stats[ISSUE_OPERAND_STALL_ON_MULTIPLY_STAT] |= EXAMPLE_CONFIG.INCLUDE_MUL & `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.MUL] & `ISSUE_P.rs_conflict[i] ;
stats[ISSUE_OPERAND_STALL_ON_DIVIDE_STAT] |= EXAMPLE_CONFIG.INCLUDE_DIV & `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.DIV] & `ISSUE_P.rs_conflict[i] ;
stats[ISSUE_OPERAND_STALL_ON_LOAD_STAT] |= `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.LS] & ~`ISSUE_P.operand_ready[i] ;
stats[ISSUE_OPERAND_STALL_ON_MULTIPLY_STAT] |= EXAMPLE_CONFIG.INCLUDE_MUL & `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.MUL] & ~`ISSUE_P.operand_ready[i] ;
stats[ISSUE_OPERAND_STALL_ON_DIVIDE_STAT] |= EXAMPLE_CONFIG.INCLUDE_DIV & `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.DIV] & ~`ISSUE_P.operand_ready[i] ;
end
//LS Stats

View file

@ -502,6 +502,11 @@ module cva5_sim
assign darb_stall = cpu.l1_request[L1_DCACHE_ID].request & ~cpu.l1_request[L1_DCACHE_ID].ack;
end endgenerate
logic [`ISSUE_P.NUM_UNITS-1:0] unit_ready;
generate for (i=0; i<`ISSUE_P.NUM_UNITS; i++)
assign unit_ready[i] = cpu.unit_issue[i].ready;
endgenerate
always_comb begin
stats = '{default: '0};
//Fetch
@ -522,9 +527,9 @@ module cva5_sim
base_no_instruction_stall = ~`ISSUE_P.issue.stage_valid | cpu.gc.fetch_flush;
base_no_id_sub_stall = (`METADATA_P.post_issue_count == MAX_IDS);
base_flush_sub_stall = cpu.gc.fetch_flush;
base_unit_busy_stall = `ISSUE_P.issue.stage_valid & ~|`ISSUE_P.issue_ready;
base_operands_stall = `ISSUE_P.issue.stage_valid & ~`ISSUE_P.operands_ready;
base_hold_stall = `ISSUE_P.issue.stage_valid & (cpu.gc.issue_hold | `ISSUE_P.pre_issue_exception_pending);
base_unit_busy_stall = `ISSUE_P.issue.stage_valid & ~|(`ISSUE_P.unit_needed_issue_stage & unit_ready);
base_operands_stall = `ISSUE_P.issue.stage_valid & ~(&`ISSUE_P.operand_ready);
base_hold_stall = `ISSUE_P.issue.stage_valid & `ISSUE_P.issue_hold;
stall_source_count = 4'(base_no_instruction_stall) + 4'(base_unit_busy_stall) + 4'(base_operands_stall) + 4'(base_hold_stall);
single_source_issue_stall = (stall_source_count == 1);
@ -545,9 +550,9 @@ module cva5_sim
//Issue Stall Source
for (int i = 0; i < REGFILE_READ_PORTS; i++) begin
stats[ISSUE_OPERAND_STALL_ON_LOAD_STAT] |= `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.LS] & `ISSUE_P.rs_conflict[i] ;
stats[ISSUE_OPERAND_STALL_ON_MULTIPLY_STAT] |= EXAMPLE_CONFIG.INCLUDE_MUL & `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.MUL] & `ISSUE_P.rs_conflict[i] ;
stats[ISSUE_OPERAND_STALL_ON_DIVIDE_STAT] |= EXAMPLE_CONFIG.INCLUDE_DIV & `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.DIV] & `ISSUE_P.rs_conflict[i] ;
stats[ISSUE_OPERAND_STALL_ON_LOAD_STAT] |= `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.LS] & ~`ISSUE_P.operand_ready[i] ;
stats[ISSUE_OPERAND_STALL_ON_MULTIPLY_STAT] |= EXAMPLE_CONFIG.INCLUDE_MUL & `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.MUL] & ~`ISSUE_P.operand_ready[i] ;
stats[ISSUE_OPERAND_STALL_ON_DIVIDE_STAT] |= EXAMPLE_CONFIG.INCLUDE_DIV & `ISSUE_P.issue.stage_valid & rd_addr_table[`ISSUE_P.issue_rs_addr[i]][`ISSUE_P.UNIT_IDS.DIV] & ~`ISSUE_P.operand_ready[i] ;
end
//LS Stats