From f619f4b0a1b88116c5394716bf7db6ee49a7a7bb Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Mon, 15 Nov 2021 11:50:57 +0000 Subject: [PATCH 1/5] Make the associative BTB compressed. That is, only store the bottom 16 bits of the target if the upper bits of pc and nextPc match. Have a single "way" dedicated to full targets. --- src_Core/RISCY_OOO/procs/lib/Btb.bsv | 42 ++++++++++++++++++---------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/lib/Btb.bsv b/src_Core/RISCY_OOO/procs/lib/Btb.bsv index 3c572d3..335d1ab 100644 --- a/src_Core/RISCY_OOO/procs/lib/Btb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Btb.bsv @@ -58,6 +58,7 @@ endinterface // Local BTB Typedefs typedef 1 PcLsbsIgnore; typedef 1024 BtbEntries; +typedef Bit#(16) CompressedTarget; typedef 2 BtbAssociativity; typedef Bit#(TLog#(SupSizeX2)) BtbBank; // Total entries/lanes of superscalar lookup/associativity @@ -94,9 +95,11 @@ module mkBtbCore(NextAddrPred#(hashSz)) Add#(1, a__, TDiv#(tagSz, hashSz)), Add#(b__, tagSz, TMul#(TDiv#(tagSz, hashSz), hashSz))); // Read and Write ordering doesn't matter since this is a predictor - Reg#(BtbBank) firstBank_reg <- mkRegU; - Vector#(SupSizeX2, MapSplit#(HashedTag#(hashSz), BtbIndex, VnD#(CapMem), BtbAssociativity)) - records <- replicateM(mkMapLossyBRAM); + Reg#(CapMem) addr_reg <- mkRegU; + Vector#(SupSizeX2, MapSplit#(HashedTag#(hashSz), BtbIndex, VnD#(CapMem), 1)) + fullRecords <- replicateM(mkMapLossyBRAM); + Vector#(SupSizeX2, MapSplit#(HashedTag#(hashSz), BtbIndex, VnD#(CompressedTarget), BtbAssociativity)) + compressedRecords <- replicateM(mkMapLossyBRAM); RWire#(BtbUpdate) updateEn <- mkRWire; function BtbAddr getBtbAddr(CapMem pc) = unpack(truncateLSB(getAddr(pc))); @@ -114,26 +117,34 @@ module mkBtbCore(NextAddrPred#(hashSz)) let taken = upd.taken; /*$display("MapUpdate in BTB - pc %x, bank: %x, taken: %x, next: %x, time: %t", pc, getBank(pc), taken, nextPc, $time);*/ - records[getBank(pc)].update(lookupKey(pc), VnD{v:taken, d:nextPc}); + 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}); endrule method Action put_pc(CapMem pc); - BtbAddr addr = getBtbAddr(pc); - firstBank_reg <= addr.bank; + addr_reg <= pc; // Start SupSizeX2 BTB lookups, but ensure to lookup in the appropriate // bank for the alignment of each potential branch. for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin - BtbAddr a = unpack(pack(addr) + fromInteger(i)); - records[a.bank].lookupStart(MapKeyIndex{key: hash(a.tag), index: a.index}); + BtbAddr a = unpack(pack(getBtbAddr(pc)) + fromInteger(i)); + fullRecords[a.bank].lookupStart(MapKeyIndex{key: hash(a.tag), index: a.index}); + compressedRecords[a.bank].lookupStart(MapKeyIndex{key: hash(a.tag), index: a.index}); end endmethod method Vector#(SupSizeX2, Maybe#(CapMem)) pred; Vector#(SupSizeX2, Maybe#(CapMem)) ppcs = replicate(Invalid); - for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) - if (records[i].lookupRead matches tagged Valid .record) - ppcs[i] = record.v ? Valid(record.d):Invalid; - ppcs = rotateBy(ppcs,unpack(-firstBank_reg)); // Rotate firstBank down to zeroeth element. + for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin + if (fullRecords[i].lookupRead matches tagged Valid .r) + ppcs[i] = r.v ? Valid(r.d):Invalid; + if (compressedRecords[i].lookupRead matches tagged Valid .r) + ppcs[i] = r.v ? Valid({truncateLSB(addr_reg),r.d}):Invalid; + end + ppcs = rotateBy(ppcs,unpack(-getBtbAddr(addr_reg).bank)); // Rotate firstBank down to zeroeth element. return ppcs; endmethod @@ -143,9 +154,12 @@ module mkBtbCore(NextAddrPred#(hashSz)) `ifdef SECURITY method Action flush method Action flush; - for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) records[i].clear; + for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin + fullRecords[i].clear; + compressedRecords[i].clear; + end endmethod - method flush_done = records[0].clearDone; + method flush_done = fullRecords[0].clearDone; `else method flush = noAction; method flush_done = True; From b84562a027ad78f821cd1a62d1314501364ba394 Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Fri, 7 Jan 2022 09:52:43 +0000 Subject: [PATCH 2/5] Improve scheduling for LatencyTimer to improve timing path discovered on DE10. --- src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv b/src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv index 56b3853..2cdfb04 100644 --- a/src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv +++ b/src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv @@ -23,6 +23,7 @@ import Vector::*; import Types::*; +import ConfigReg::*; // a timer to track latency of multiple misses @@ -39,8 +40,8 @@ module mkLatencyTimer(LatencyTimer#(num, timeWidth)) provisos( Alias#(idxT, Bit#(TLog#(num))), Alias#(timeT, Bit#(timeWidth)) ); - Reg#(Vector#(num, timeT)) timer <- mkReg(replicate(0)); - Reg#(Vector#(num, Bool)) started <- mkReg(replicate(False)); // for checking purposes + Reg#(Vector#(num, timeT)) timer <- mkConfigReg(replicate(0)); + Reg#(Vector#(num, Bool)) started <- mkConfigReg(replicate(False)); // for checking purposes RWire#(idxT) startEn <- mkRWire; RWire#(idxT) doneEn <- mkRWire; From e600fd7d38c238a7d0ff468b2df86e790f8ebb29 Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Sat, 8 Jan 2022 10:15:22 +0000 Subject: [PATCH 3/5] Delay BTB update by a cycle for timing. This should not be a primary degredation of performance since the redirection gets on seperately from this update which will only affect future predictions. --- src_Core/RISCY_OOO/procs/lib/Btb.bsv | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/lib/Btb.bsv b/src_Core/RISCY_OOO/procs/lib/Btb.bsv index 335d1ab..a1d9059 100644 --- a/src_Core/RISCY_OOO/procs/lib/Btb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Btb.bsv @@ -38,6 +38,7 @@ import Types::*; import ProcTypes::*; import ConfigReg::*; +import DReg::*; import Map::*; import Vector::*; import CHERICC_Fat::*; @@ -100,7 +101,7 @@ module mkBtbCore(NextAddrPred#(hashSz)) fullRecords <- replicateM(mkMapLossyBRAM); Vector#(SupSizeX2, MapSplit#(HashedTag#(hashSz), BtbIndex, VnD#(CompressedTarget), BtbAssociativity)) compressedRecords <- replicateM(mkMapLossyBRAM); - RWire#(BtbUpdate) updateEn <- mkRWire; + Reg#(Maybe#(BtbUpdate)) updateEn <- mkDReg(Invalid); function BtbAddr getBtbAddr(CapMem pc) = unpack(truncateLSB(getAddr(pc))); function BtbBank getBank(CapMem pc) = getBtbAddr(pc).bank; @@ -111,7 +112,7 @@ module mkBtbCore(NextAddrPred#(hashSz)) // no flush, accept update (* fire_when_enabled, no_implicit_conditions *) - rule canonUpdate(updateEn.wget matches tagged Valid .upd); + rule canonUpdate(updateEn matches tagged Valid .upd); let pc = upd.pc; let nextPc = upd.nextPc; let taken = upd.taken; @@ -149,7 +150,7 @@ module mkBtbCore(NextAddrPred#(hashSz)) endmethod method Action update(CapMem pc, CapMem nextPc, Bool taken); - updateEn.wset(BtbUpdate {pc: pc, nextPc: nextPc, taken: taken}); + updateEn <= Valid(BtbUpdate {pc: pc, nextPc: nextPc, taken: taken}); endmethod `ifdef SECURITY From 1d6633f42353bca472c00dcceb06a36e6e5e3620 Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Mon, 10 Jan 2022 17:18:01 +0000 Subject: [PATCH 4/5] Buffer redirection from Commit to reduce conflicts in the pipeline. This is a general improvement, and should be upstreamed to master if there are no issues discovered. --- .../RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv | 48 +++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv index 168b20b..faaa514 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv @@ -118,7 +118,8 @@ interface CommitInput; method Action setReconcileD; // recocile D$ // redirect method Action killAll; - method Action redirectPc(CapMem trap_pc + method Action redirectPc( + CapMem trap_pc `ifdef RVFI_DII , Dii_Parcel_Id dii_pid `endif @@ -157,6 +158,13 @@ typedef struct { SpecBits specBits; } RenameErrInfo deriving(Bits, Eq, FShow); +typedef struct { + CapMem trap_pc; +`ifdef RVFI_DII + Dii_Parcel_Id dii_pid; +`endif +} RedirectInfo deriving(Bits, Eq, FShow); + interface CommitStage; // performance method Data getPerf(ComStagePerfType t); @@ -519,6 +527,8 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); // cycle handles trap, redirect and handles system consistency Reg#(Maybe#(CommitTrap)) commitTrap <- mkReg(Invalid); // saves new pc here + FIFO#(RedirectInfo) redirectQ <- mkFIFO; + // maintain system consistency when system state (CSR) changes or for security function Action makeSystemConsistent(Bool flushTlb, Bool flushSecurity, @@ -780,11 +790,11 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); // trap handling & redirect let trap_updates <- csrf.trap(trap.trap, cast(trap.pc), trap.addr, trap.orig_inst); CapPipe new_pc = cast(trap_updates.new_pcc); - inIfc.redirectPc(cast(new_pc) + redirectQ.enq(RedirectInfo{trap_pc: cast(new_pc) `ifdef RVFI_DII - , trap.x.dii_pid + (is_16b_inst(trap.orig_inst) ? 1 : 2) + , dii_pid: trap.x.dii_pid + (is_16b_inst(trap.orig_inst) ? 1 : 2) `endif - ); + }); `ifdef RVFI Rvfi_Traces rvfis = replicate(tagged Invalid); rvfis[0] = genRVFI(trap.x, traceCnt, getTSB(), getAddr(new_pc)); @@ -825,11 +835,11 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); // kill everything, redirect, and increment epoch inIfc.killAll; - inIfc.redirectPc(x.pc -`ifdef RVFI_DII - , x.dii_pid -`endif - ); + redirectQ.enq(RedirectInfo{trap_pc: x.pc + `ifdef RVFI_DII + , dii_pid: x.dii_pid + `endif + }); inIfc.incrementEpoch; // the killed Ld should have claimed phy reg, we should not commit it; @@ -945,11 +955,12 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); m_ret_updates = tagged Valid ret_updates; `endif end - inIfc.redirectPc(next_pc -`ifdef RVFI_DII - , x.dii_pid + (is_16b_inst(x.orig_inst) ? 1 : 2) -`endif - ); + redirectQ.enq(RedirectInfo{trap_pc: next_pc + `ifdef RVFI_DII + , x.dii_pid + (is_16b_inst(x.orig_inst) ? 1 : 2) + `endif + }); + `ifdef RVFI Rvfi_Traces rvfis = replicate(tagged Invalid); @@ -1343,6 +1354,15 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); `endif endrule + rule pass_redirect; + RedirectInfo ri <- toGet(redirectQ).get; + inIfc.redirectPc(ri.trap_pc +`ifdef RVFI_DII + , ri.rii_pid +`endif + ); + endrule + // ================================================================ // INTERFACE From 1e9ee9d12174758bb03e1e2e4a2d0a00935ed4a3 Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Thu, 9 Dec 2021 12:27:57 +0000 Subject: [PATCH 5/5] Simpelest strategy for making wrongSpec not conflict with loads of rules. This triggers some assertions in the ROB what should be dealt with properly if this is going to work. --- .../RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv b/src_Core/RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv index f17bb98..dbdf7c1 100644 --- a/src_Core/RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv +++ b/src_Core/RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv @@ -1,6 +1,6 @@ // Copyright (c) 2017 Massachusetts Institute of Technology -// +// // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -8,10 +8,10 @@ // modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -26,6 +26,13 @@ import HasSpecBits::*; import GetPut::*; import Vector::*; import ReorderBuffer::*; +import FIFO::*; + +typedef struct { + Bool kill_all; + SpecTag spec_tag; + InstTag inst_tag; +} IncorrectSpec deriving(Bits, Eq, FShow); interface GlobalSpecUpdate#(numeric type correctSpecPortNum, numeric type conflictWrongSpecPortNum); interface Vector#(correctSpecPortNum, Put#(SpecTag)) correctSpec; @@ -50,6 +57,9 @@ module mkGlobalSpecUpdate#( Vector#(correctSpecPortNum, RWire#(void)) spec_conflict <- replicateM(mkRWire); // let the caller of conflictWrongSpec to be conflict with wrong spec Vector#(conflictWrongSpecPortNum, RWire#(void)) wrongSpec_conflict <- replicateM(mkRWire); + // must be a single-element fifo to ensure all pushing rules cannot fire while we are waiting + // to kill. + FIFO#(IncorrectSpec) incorrectSpec_ff <- mkFIFO1; (* fire_when_enabled, no_implicit_conditions *) rule canon_correct_spec; @@ -63,6 +73,20 @@ module mkGlobalSpecUpdate#( rob.correctSpeculation(mask); endrule + rule do_incorrect_spec; + IncorrectSpec x <- toGet(incorrectSpec_ff).get; + ifc.incorrectSpeculation(x.kill_all, x.spec_tag); + rob.incorrectSpeculation(x.kill_all, x.spec_tag, x.inst_tag); + // conflict with correct spec + for(Integer i = 0; i < valueof(correctSpecPortNum); i = i+1) begin + spec_conflict[i].wset(?); + end + // conflict with the caller of conflictWrongSpec + for(Integer i = 0; i < valueof(conflictWrongSpecPortNum); i = i+1) begin + wrongSpec_conflict[i].wset(?); + end + endrule + Vector#(correctSpecPortNum, Put#(SpecTag)) correctVec = ?; for(Integer i = 0; i < valueof(correctSpecPortNum); i = i+1) begin correctVec[i] = (interface Put; @@ -85,18 +109,8 @@ module mkGlobalSpecUpdate#( interface correctSpec = correctVec; - method Action incorrectSpec(Bool kill_all, SpecTag spec_tag, InstTag inst_tag); - ifc.incorrectSpeculation(kill_all, spec_tag); - rob.incorrectSpeculation(kill_all, spec_tag, inst_tag); - // conflict with correct spec - for(Integer i = 0; i < valueof(correctSpecPortNum); i = i+1) begin - spec_conflict[i].wset(?); - end - // conflict with the caller of conflictWrongSpec - for(Integer i = 0; i < valueof(conflictWrongSpecPortNum); i = i+1) begin - wrongSpec_conflict[i].wset(?); - end - endmethod + method Action incorrectSpec(Bool kill_all, SpecTag spec_tag, InstTag inst_tag) + = incorrectSpec_ff.enq(IncorrectSpec{kill_all: kill_all, spec_tag: spec_tag, inst_tag: inst_tag}); interface conflictWrongSpec = conflictWrongVec; endmodule