Clear compressed and uncompressed BTBs on mispred
This fixes a wedge in the frontend: the fetch stage could get stuck in a loop, with the next address predictor deciding that the redirect PC is a compressed instruction doing a close jump. On mispredict, this would get retrained, but "mispedict" was denoted as an untaken branch to PC+2. If unlucky, PC+2 could cross an alignment boundary, causing the untaken branch to be interpreted as a long branch, leaving an old competing entry in the compressed branch BTB, which would then take priority. Fix by always marking entries in both close and long BTBs when not taken: to avoid hurting performance, this kind of update will not insert into either BTB unless already present.
This commit is contained in:
@@ -120,10 +120,11 @@ module mkBtbCore(NextAddrPred#(hashSz))
|
||||
pc, getBank(pc), taken, nextPc, $time);*/
|
||||
CompressedTarget shortMask = -1;
|
||||
CapMem mask = ~zeroExtend(shortMask);
|
||||
if ((pc&mask) == (nextPc&mask))
|
||||
compressedRecords[getBank(pc)].update(lookupKey(pc), VnD{v:taken, d:truncate(nextPc)});
|
||||
else
|
||||
fullRecords[getBank(pc)].update(lookupKey(pc), VnD{v:taken, d:nextPc});
|
||||
let compressable = (pc&mask) == (nextPc&mask);
|
||||
if (compressable || !taken)
|
||||
compressedRecords[getBank(pc)].updateMayInsert(lookupKey(pc), VnD{v:taken, d:truncate(nextPc)}, taken);
|
||||
if (!compressable || !taken)
|
||||
fullRecords[getBank(pc)].updateMayInsert(lookupKey(pc), VnD{v:taken, d:nextPc}, taken);
|
||||
endrule
|
||||
|
||||
method Action put_pc(CapMem pc);
|
||||
|
||||
@@ -118,6 +118,7 @@ Bitwise#(ix), Eq#(ix), Arith#(ix));
|
||||
endmodule
|
||||
|
||||
interface MapSplit#(type ky, type ix, type vl, numeric type as);
|
||||
method Action updateMayInsert(MapKeyIndex#(ky,ix) key, vl value, Bool insert);
|
||||
method Action update(MapKeyIndex#(ky,ix) key, vl value);
|
||||
method Action lookupStart(MapKeyIndex#(ky,ix) lookup_key);
|
||||
method Maybe#(vl) lookupRead;
|
||||
@@ -133,6 +134,7 @@ Bitwise#(ix), Eq#(ix), Arith#(ix), PrimIndex#(ix, a__));
|
||||
Vector#(as, RWBramCore#(ix, ky)) updateKeys <- replicateM(mkRWBramCoreUG);
|
||||
Reg#(MapKeyIndex#(ky,ix)) lookupReg <- mkRegU;
|
||||
Reg#(MapKeyIndexValue#(ky,ix,vl)) updateReg <- mkRegU;
|
||||
Reg#(Bool) updateInsert <- mkRegU;
|
||||
Reg#(Bool) updateFresh <- mkDReg(False);
|
||||
Reg#(Bit#(TLog#(as))) wayNext <- mkReg(0);
|
||||
Integer a = valueof(as);
|
||||
@@ -147,23 +149,32 @@ Bitwise#(ix), Eq#(ix), Arith#(ix), PrimIndex#(ix, a__));
|
||||
if (clearCount == ~0) clearReg <= False;
|
||||
end else if (updateFresh) begin
|
||||
let u = updateReg;
|
||||
Bit#(TLog#(as)) way = wayNext;
|
||||
Maybe#(Bit#(TLog#(as))) hitWay = Invalid;
|
||||
for (Integer i = 0; i < a; i = i + 1)
|
||||
if (updateKeys[i].rdResp == u.key) way = fromInteger(i);
|
||||
if (updateKeys[i].rdResp == u.key) hitWay = Valid(fromInteger(i));
|
||||
// Always write to both the main memory bank and the copy used for updates.
|
||||
/*$display("MapUpdate - index: %x, key: %x, value: %x, way: %x",
|
||||
u.index, u.key, u.value, way);*/
|
||||
mem[way].wrReq(u.index, MapKeyValue{key: u.key, value: u.value});
|
||||
updateKeys[way].wrReq(u.index, u.key);
|
||||
wayNext <= (wayNext == fromInteger(a-1)) ? 0 : (wayNext + 1);
|
||||
if (updateInsert || isValid(hitWay)) begin
|
||||
let way = fromMaybe(wayNext, hitWay);
|
||||
mem[way].wrReq(u.index, MapKeyValue{key: u.key, value: u.value});
|
||||
updateKeys[way].wrReq(u.index, u.key);
|
||||
wayNext <= (wayNext == fromInteger(a-1)) ? 0 : (wayNext + 1);
|
||||
end
|
||||
end
|
||||
endrule
|
||||
|
||||
method Action update(MapKeyIndex#(ky,ix) ki, vl value);
|
||||
function Action updateFn(MapKeyIndex#(ky,ix) ki, vl value, Bool insert) = action
|
||||
updateReg <= MapKeyIndexValue{key: ki.key, index: ki.index, value: value};
|
||||
updateFresh <= True;
|
||||
updateInsert <= insert;
|
||||
for (Integer i = 0; i < a; i = i + 1) updateKeys[i].rdReq(ki.index);
|
||||
endmethod
|
||||
endaction;
|
||||
|
||||
method Action updateMayInsert(MapKeyIndex#(ky,ix) ki, vl value, Bool insert) =
|
||||
updateFn(ki, value, insert);
|
||||
method Action update(MapKeyIndex#(ky,ix) ki, vl value) =
|
||||
updateFn(ki, value, True);
|
||||
method Action lookupStart(MapKeyIndex#(ky,ix) ki);
|
||||
lookupReg <= ki;
|
||||
for (Integer i = 0; i < a; i = i + 1) mem[i].rdReq(ki.index);
|
||||
|
||||
Reference in New Issue
Block a user