FetchStage: Use EHRs to remove conflicts between doDecode and doFetch3

This conflict was introduced by 53aacff7c when compressed support was
added. Previously, doDecode could be scheduled in the same cycle as
doFetch3 (and only in that order), but the Reg reads added to doDecode
prevented this. Instead, use EHRs to allow a bypass path from doDecode
to doFetch3. This means we can issue every cycle again, rather than only
every other cycle.
This commit is contained in:
James Clarke
2019-11-03 04:12:34 +00:00
parent 87daa8e319
commit 67be950d3a

View File

@@ -321,13 +321,13 @@ module mkFetchStage(FetchStage);
Integer pc_redirect_port = 2;
// Epochs
Reg#(Bool) decode_epoch <- mkReg(False);
Ehr#(2, Bool) decode_epoch <- mkEhr(False);
Reg#(Epoch) f_main_epoch <- mkReg(0); // fetch estimate of main epoch
// Regs to hold the first half of an instruction that straddles a cache line boundary
Reg #(Bool) rg_pending_straddle <- mkReg (False);
Reg #(Addr) rg_half_inst_pc <- mkRegU; // The PC of the straddling instruction
Reg #(Bit #(16)) rg_half_inst_lsbs <- mkRegU; // The 16 lsbs of the straddling instruction
// Regs/wires to hold the first half of an instruction that straddles a cache line boundary
Ehr #(2, Bool) ehr_pending_straddle <- mkEhr (False);
Ehr #(2, Addr) ehr_half_inst_pc <- mkEhr (?); // The PC of the straddling instruction
Ehr #(2, Bit #(16)) ehr_half_inst_lsbs <- mkEhr (?); // The 16 lsbs of the straddling instruction
// Pipeline Stage FIFOs
Fifo#(2, Tuple2#(Bit#(TLog#(SupSize)),Fetch1ToFetch2)) f12f2 <- mkCFFifo;
@@ -456,7 +456,7 @@ module mkFetchStage(FetchStage);
let out = Fetch1ToFetch2 {
pc: pc,
pred_next_pc: pred_next_pc,
decode_epoch: decode_epoch,
decode_epoch: decode_epoch[0],
main_epoch: f_main_epoch};
f12f2.enq(tuple2(fromInteger(posLastSup),out));
if (verbose) $display("Fetch1: ", fshow(out));
@@ -539,11 +539,11 @@ module mkFetchStage(FetchStage);
end
end
if (fetch3In.decode_epoch != decode_epoch) begin
if (fetch3In.decode_epoch != decode_epoch[1]) begin
// Just drop it.
if (verbosity > 0) begin
$display ("----------------");
$display ("Fetch3: Drop: decode epoch: %d", decode_epoch);
$display ("Fetch3: Drop: decode epoch: %d", decode_epoch[1]);
$display ("Fetch3: f22f3.first: ", fshow (f22f3.first));
$display ("Fetch3: inst_d: ", fshow (inst_d));
end
@@ -554,8 +554,8 @@ module mkFetchStage(FetchStage);
Addr start_PC = fetch3In.pc;
// Handle cache-line boundary straddling instruction, if one is pending
if (rg_pending_straddle) begin
if (fetch3In.pc != rg_half_inst_pc + 4) begin
if (ehr_pending_straddle[1]) begin
if (fetch3In.pc != ehr_half_inst_pc[1] + 4) begin
$display ("----------------");
$display ("Fetch3: straddle: pc mismatch");
$display ("Fetch3: f22f3.first: ", fshow (f22f3.first));
@@ -564,17 +564,17 @@ module mkFetchStage(FetchStage);
end
else begin
// Prepend onto the sequence: { first-half of the instruction , 0 }
v_x16 = shiftInAt0 (shiftInAt0 (v_x16, rg_half_inst_lsbs), 0);
v_x16 = shiftInAt0 (shiftInAt0 (v_x16, ehr_half_inst_lsbs[1]), 0);
let bound = valueOf (SupSizeX2) - 1;
if (n_x16s < (fromInteger (bound) - 1))
n_x16s = n_x16s + 2;
else if (n_x16s < fromInteger (bound))
n_x16s = n_x16s + 1;
start_PC = rg_half_inst_pc;
rg_pending_straddle <= False;
start_PC = ehr_half_inst_pc[1];
ehr_pending_straddle[1] <= False;
if (verbosity > 0) begin
$display ("----------------");
$display ("Fetch3: straddle: prepend x16 %0h", rg_half_inst_lsbs);
$display ("Fetch3: straddle: prepend x16 %0h", ehr_half_inst_lsbs[1]);
$display ("Fetch3: f22f3.first: ", fshow (f22f3.first));
$display ("Fetch3: inst_d: ", fshow (inst_d));
$display ("Fetch3: v_x16: ", fshow (v_x16));
@@ -606,7 +606,7 @@ module mkFetchStage(FetchStage);
// The main_epoch check is required to make sure this stage doesn't
// redirect the PC if a later stage already redirected the PC.
if (fetch3In.main_epoch == f_main_epoch) begin
Bool decode_epoch_local = decode_epoch; // next value for decode epoch
Bool decode_epoch_local = decode_epoch[0]; // next value for decode epoch
Maybe#(Addr) redirectPc = Invalid; // next pc redirect by branch predictor
Maybe#(TrainNAP) trainNAP = Invalid; // training data sent to next addr pred
`ifdef PERF_COUNT
@@ -619,9 +619,9 @@ module mkFetchStage(FetchStage);
if ((inst_data[i].inst_kind == Inst_32b_Lsbs) && (fromInteger(i) <= nbSup)) begin
if (fetch3In.decode_epoch == decode_epoch_local) begin
// Save the half-instruction and redirect doFetch1 to get the next cache line
rg_pending_straddle <= True;
rg_half_inst_pc <= inst_data[i].pc;
rg_half_inst_lsbs <= inst_data[i].orig_inst [15:0];
ehr_pending_straddle[0] <= True;
ehr_half_inst_pc[0] <= inst_data[i].pc;
ehr_half_inst_lsbs[0] <= inst_data[i].orig_inst [15:0];
decode_epoch_local = ! decode_epoch_local;
let next_PC = inst_data[i].pc + 4;
redirectPc = tagged Valid (next_PC);
@@ -782,7 +782,7 @@ module mkFetchStage(FetchStage);
if(redirectPc matches tagged Valid .nextPc) begin
pc_reg[pc_decode_port] <= nextPc;
end
decode_epoch <= decode_epoch_local;
decode_epoch[0] <= decode_epoch_local;
// send training data for next addr pred
if (trainNAP matches tagged Valid .x) begin
napTrainByDecQ.enq(x);