From 05f17f5b995f5de041569dbbb3bb2146902b14d6 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 23 Jan 2020 16:01:32 -0800 Subject: [PATCH] [tracegen] Add tracegen support for the BOOM L1D (#362) * [tracegen] Add tracegen support for the BOOM L1D * [tracegen] Split up BOOM Tracegen mixin and shim. * [ci] Fix tracegen hash for testing --- .circleci/config.yml | 62 ++++++ .circleci/defaults.sh | 1 + .circleci/run-tests.sh | 3 + build.sbt | 2 +- .../tracegen/src/main/scala/Configs.scala | 32 ++- .../tracegen/src/main/scala/System.scala | 15 +- generators/tracegen/src/main/scala/Tile.scala | 193 +++++++++++++++++- 7 files changed, 301 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6514fdb8..9fbb2958 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -346,6 +346,35 @@ jobs: key: tracegen-{{ .Branch }}-{{ .Revision }} paths: - "/home/riscvuser/project" + prepare-tracegen-boom: + docker: + - image: riscvboom/riscvboom-images:0.0.12 + environment: + JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit + TERM: dumb + steps: + - add_ssh_keys: + fingerprints: + - "3e:c3:02:5b:ed:64:8c:b7:b0:04:43:bc:83:43:73:1e" + - checkout + - run: + name: Create hash of toolchains + command: | + .circleci/create-hash.sh + - restore_cache: + keys: + - riscv-tools-installed-v4-{{ checksum "../riscv-tools.hash" }} + - restore_cache: + keys: + - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - run: + name: Building the tracegen-boom subproject using Verilator + command: .circleci/do-rtl-build.sh tracegen-boom + no_output_timeout: 120m + - save_cache: + key: tracegen-boom-{{ .Branch }}-{{ .Revision }} + paths: + - "/home/riscvuser/project" prepare-firesim: docker: - image: riscvboom/riscvboom-images:0.0.12 @@ -593,6 +622,30 @@ jobs: - run: name: Run tracegen tests command: .circleci/run-tests.sh tracegen + tracegen-boom-run-tests: + docker: + - image: riscvboom/riscvboom-images:0.0.12 + environment: + JVM_OPTS: -Xmx3200m # Customize the JVM maximum heap limit + TERM: dumb + steps: + - checkout + - run: + name: Create hash of toolchains + command: | + .circleci/create-hash.sh + - restore_cache: + keys: + - riscv-tools-installed-v2-{{ checksum "../riscv-tools.hash" }} + - restore_cache: + keys: + - tracegen-boom-{{ .Branch }}-{{ .Revision }} + - restore_cache: + keys: + - verilator-installed-v3-{{ checksum "sims/verilator/verilator.mk" }} + - run: + name: Run tracegen-boom tests + command: .circleci/run-tests.sh tracegen-boom firesim-run-tests: docker: - image: riscvboom/riscvboom-images:0.0.12 @@ -723,6 +776,11 @@ workflows: - install-riscv-toolchain - install-verilator + - prepare-tracegen-boom: + requires: + - install-riscv-toolchain + - install-verilator + - prepare-firesim: requires: - install-riscv-toolchain @@ -770,6 +828,10 @@ workflows: requires: - prepare-tracegen + - tracegen-boom-run-tests: + requires: + - prepare-tracegen-boom + # Run the firesim tests - firesim-run-tests: requires: diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index c5838a48..08c4222c 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -49,5 +49,6 @@ mapping["blockdevrocketchip"]="SUB_PROJECT=example CONFIG=SimBlockDeviceRocketCo mapping["hwacha"]="SUB_PROJECT=example CONFIG=HwachaRocketConfig" mapping["gemmini"]="SUB_PROJECT=example CONFIG=GemminiRocketConfig" mapping["tracegen"]="SUB_PROJECT=tracegen CONFIG=NonBlockingTraceGenL2Config" +mapping["tracegen-boom"]="SUB_PROJECT=tracegen CONFIG=BoomTraceGenConfig" mapping["firesim"]="DESIGN=FireSim TARGET_CONFIG=DDR3FRFCFSLLC4MB_FireSimRocketChipConfig PLATFORM_CONFIG=BaseF1Config" mapping["fireboom"]="DESIGN=FireSim TARGET_CONFIG=DDR3FRFCFSLLC4MB_FireSimBoomConfig PLATFORM_CONFIG=BaseF1Config" diff --git a/.circleci/run-tests.sh b/.circleci/run-tests.sh index 97789b4c..6d01d182 100755 --- a/.circleci/run-tests.sh +++ b/.circleci/run-tests.sh @@ -65,6 +65,9 @@ case $1 in tracegen) run_tracegen ${mapping[$1]} ;; + tracegen-boom) + run_tracegen ${mapping[$1]} + ;; *) echo "No set of tests for $1. Did you spell it right?" exit 1 diff --git a/build.sbt b/build.sbt index d02c66bb..2fd83c55 100644 --- a/build.sbt +++ b/build.sbt @@ -127,7 +127,7 @@ lazy val example = conditionalDependsOn(project in file("generators/example")) .settings(commonSettings) lazy val tracegen = conditionalDependsOn(project in file("generators/tracegen")) - .dependsOn(rocketchip, sifive_cache) + .dependsOn(rocketchip, sifive_cache, boom) .settings(commonSettings) lazy val utilities = conditionalDependsOn(project in file("generators/utilities")) diff --git a/generators/tracegen/src/main/scala/Configs.scala b/generators/tracegen/src/main/scala/Configs.scala index e3536e6a..dd195296 100644 --- a/generators/tracegen/src/main/scala/Configs.scala +++ b/generators/tracegen/src/main/scala/Configs.scala @@ -32,9 +32,35 @@ class WithTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) memStart = site(ExtMem).get.master.base, numGens = params.size) } - case MaxHartIdBits => if (params.size == 1) 1 else log2Ceil(params.size) + case MaxHartIdBits => log2Ceil(params.size + up(BoomTraceGenKey, site).length) max 1 }) +class WithBoomTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) + extends Config((site, here, up) => { + case BoomTraceGenKey => params.map { dcp => TraceGenParams( + dcache = Some(dcp), + wordBits = site(XLen), + addrBits = 48, + addrBag = { + val nSets = dcp.nSets + val nWays = dcp.nWays + val blockOffset = site(SystemBusKey).blockOffset + val nBeats = min(2, site(SystemBusKey).blockBeats) + val beatBytes = site(SystemBusKey).beatBytes + List.tabulate(2 * nWays) { i => + Seq.tabulate(nBeats) { j => + BigInt((j * beatBytes) + ((i * nSets) << blockOffset)) + } + }.flatten + }, + maxRequests = nReqs, + memStart = site(ExtMem).get.master.base, + numGens = params.size) + } + case MaxHartIdBits => log2Ceil(params.size + up(TraceGenKey, site).length) max 1 +}) + + class TraceGenConfig extends Config( new WithTraceGen(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++ new BaseConfig) @@ -43,6 +69,10 @@ class NonBlockingTraceGenConfig extends Config( new WithTraceGen(List.fill(2) { DCacheParams(nMSHRs = 2, nSets = 16, nWays = 2) }) ++ new BaseConfig) +class BoomTraceGenConfig extends Config( + new WithBoomTraceGen(List.fill(2) { DCacheParams(nMSHRs = 8, nSets = 16, nWays = 2) }) ++ + new BaseConfig) + class WithL2TraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) extends Config((site, here, up) => { case TraceGenKey => params.map { dcp => TraceGenParams( diff --git a/generators/tracegen/src/main/scala/System.scala b/generators/tracegen/src/main/scala/System.scala index 57d048a3..18307678 100644 --- a/generators/tracegen/src/main/scala/System.scala +++ b/generators/tracegen/src/main/scala/System.scala @@ -6,12 +6,18 @@ import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, BufferParams} import freechips.rocketchip.groundtest.{DebugCombiner, TraceGenParams} import freechips.rocketchip.subsystem._ -case object TraceGenKey extends Field[Seq[TraceGenParams]] +case object BoomTraceGenKey extends Field[Seq[TraceGenParams]](Nil) +case object TraceGenKey extends Field[Seq[TraceGenParams]](Nil) trait HasTraceGenTiles { this: BaseSubsystem => - val tiles = p(TraceGenKey).zipWithIndex.map { case (params, i) => + val rocket_tiles = p(TraceGenKey).zipWithIndex.map { case (params, i) => LazyModule(new TraceGenTile(i, params, p)) } + val boom_tiles = p(BoomTraceGenKey).zipWithIndex.map { case (params, i) => + LazyModule(new BoomTraceGenTile(i, params, p)) + } + + val tiles = rocket_tiles ++ boom_tiles tiles.foreach { t => sbus.fromTile(None, buffer = BufferParams.default) { t.masterNode } @@ -26,7 +32,10 @@ trait HasTraceGenTilesModuleImp extends LazyModuleImp { t.module.constants.hartid := i.U } - val status = DebugCombiner(outer.tiles.map(_.module.status)) + val status = DebugCombiner( + outer.rocket_tiles.map(_.module.status) ++ + outer.boom_tiles.map(_.module.status) + ) success := status.finished } diff --git a/generators/tracegen/src/main/scala/Tile.scala b/generators/tracegen/src/main/scala/Tile.scala index 1897224d..28974e1b 100644 --- a/generators/tracegen/src/main/scala/Tile.scala +++ b/generators/tracegen/src/main/scala/Tile.scala @@ -1,14 +1,19 @@ package tracegen import chisel3._ +import chisel3.util._ import freechips.rocketchip.config.Parameters import freechips.rocketchip.diplomacy.{LazyModule, SynchronousCrossing} import freechips.rocketchip.groundtest.{TraceGenerator, TraceGenParams, DummyPTW, GroundTestStatus} -import freechips.rocketchip.rocket.{DCache, NonBlockingDCache, SimpleHellaCacheIF} -import freechips.rocketchip.tile.{BaseTile, BaseTileModuleImp, HartsWontDeduplicate} +import freechips.rocketchip.rocket.{DCache, NonBlockingDCache, SimpleHellaCacheIF, HellaCacheExceptions, HellaCacheReq, HellaCacheIO} +import freechips.rocketchip.rocket.constants.{MemoryOpConstants} +import freechips.rocketchip.tile.{BaseTile, BaseTileModuleImp, HartsWontDeduplicate, TileKey} import freechips.rocketchip.tilelink.{TLInwardNode, TLIdentityNode} import freechips.rocketchip.interrupts._ +import boom.lsu.{BoomNonBlockingDCache, LSU, LSUCoreIO} +import boom.common.{BoomTileParams, MicroOp, BoomCoreParams, BoomModule} + class TraceGenTile(val id: Int, val params: TraceGenParams, q: Parameters) extends BaseTile(params, SynchronousCrossing(), HartsWontDeduplicate(params), q) { val dcache = params.dcache.map { dc => LazyModule( @@ -29,6 +34,190 @@ class TraceGenTile(val id: Int, val params: TraceGenParams, q: Parameters) override lazy val module = new TraceGenTileModuleImp(this) } +class BoomLSUShim(implicit p: Parameters) extends BoomModule()(p) + with MemoryOpConstants { + val io = IO(new Bundle { + val lsu = Flipped(new LSUCoreIO) + val tracegen = Flipped(new HellaCacheIO) + }) + + io.lsu.tsc_reg := 0.U(1.W) + + val rob_sz = numRobEntries + val rob = Reg(Vec(rob_sz, new HellaCacheReq)) + val rob_respd = RegInit(VecInit((~(0.U(rob_sz.W))).asBools)) + val rob_uop = Reg(Vec(rob_sz, new MicroOp)) + val rob_bsy = RegInit(VecInit(0.U(rob_sz.W).asBools)) + val rob_head = RegInit(0.U(log2Up(rob_sz).W)) + val rob_tail = RegInit(0.U(log2Up(rob_sz).W)) + val rob_wait_till_empty = RegInit(false.B) + val ready_for_amo = rob_tail === rob_head && io.lsu.fencei_rdy + when (ready_for_amo) { + rob_wait_till_empty := false.B + } + + def WrapInc(idx: UInt, max: Int): UInt = { + Mux(idx === (max-1).U, 0.U, idx + 1.U) + } + + + io.tracegen.req.ready := (!rob_bsy(rob_tail) && + !rob_wait_till_empty && + (ready_for_amo || !(isAMO(io.tracegen.req.bits.cmd) || io.tracegen.req.bits.cmd === M_XLR || io.tracegen.req.bits.cmd === M_XSC)) && + (WrapInc(rob_tail, rob_sz) =/= rob_head) && + !(io.lsu.ldq_full(0) && isRead(io.tracegen.req.bits.cmd)) && + !(io.lsu.stq_full(0) && isWrite(io.tracegen.req.bits.cmd)) + ) + + val tracegen_uop = WireInit((0.U).asTypeOf(new MicroOp)) + tracegen_uop.uses_ldq := isRead(io.tracegen.req.bits.cmd) && !isWrite(io.tracegen.req.bits.cmd) + tracegen_uop.uses_stq := isWrite(io.tracegen.req.bits.cmd) + tracegen_uop.rob_idx := rob_tail + tracegen_uop.uopc := io.tracegen.req.bits.tag + tracegen_uop.mem_size := io.tracegen.req.bits.size + tracegen_uop.mem_cmd := io.tracegen.req.bits.cmd + tracegen_uop.mem_signed := io.tracegen.req.bits.signed + tracegen_uop.ldq_idx := io.lsu.dis_ldq_idx(0) + tracegen_uop.stq_idx := io.lsu.dis_stq_idx(0) + tracegen_uop.is_amo := isAMO(io.tracegen.req.bits.cmd) || io.tracegen.req.bits.cmd === M_XSC + tracegen_uop.ctrl.is_load := isRead(io.tracegen.req.bits.cmd) && !isWrite(io.tracegen.req.bits.cmd) + tracegen_uop.ctrl.is_sta := isWrite(io.tracegen.req.bits.cmd) + tracegen_uop.ctrl.is_std := isWrite(io.tracegen.req.bits.cmd) + + io.lsu.dis_uops(0).valid := io.tracegen.req.fire() + io.lsu.dis_uops(0).bits := tracegen_uop + + when (io.tracegen.req.fire()) { + rob_tail := WrapInc(rob_tail, rob_sz) + rob_bsy(rob_tail) := true.B + rob_uop(rob_tail) := tracegen_uop + rob_respd(rob_tail) := false.B + rob(rob_tail) := io.tracegen.req.bits + when ( + isAMO(io.tracegen.req.bits.cmd) || + io.tracegen.req.bits.cmd === M_XLR || + io.tracegen.req.bits.cmd === M_XSC + ) { + rob_wait_till_empty := true.B + } + } + + io.lsu.fp_stdata.valid := false.B + io.lsu.fp_stdata.bits := DontCare + + + + io.lsu.commit.valids(0) := (!rob_bsy(rob_head) && rob_head =/= rob_tail && rob_respd(rob_head)) + io.lsu.commit.uops(0) := rob_uop(rob_head) + io.lsu.commit.rbk_valids(0) := false.B + io.lsu.commit.rollback := false.B + io.lsu.commit.fflags := DontCare + when (io.lsu.commit.valids(0)) { + rob_head := WrapInc(rob_head, rob_sz) + } + + when (io.lsu.clr_bsy(0).valid) { + rob_bsy(io.lsu.clr_bsy(0).bits) := false.B + } + when (io.lsu.clr_unsafe(0).valid && rob(io.lsu.clr_unsafe(0).bits).cmd =/= M_XLR) { + rob_bsy(io.lsu.clr_unsafe(0).bits) := false.B + } + when (io.lsu.exe(0).iresp.valid) { + rob_bsy(io.lsu.exe(0).iresp.bits.uop.rob_idx) := false.B + } + + + assert(!io.lsu.lxcpt.valid) + + io.lsu.exe(0).req.valid := RegNext(io.tracegen.req.fire()) + io.lsu.exe(0).req.bits := DontCare + io.lsu.exe(0).req.bits.uop := RegNext(tracegen_uop) + io.lsu.exe(0).req.bits.addr := RegNext(io.tracegen.req.bits.addr) + io.lsu.exe(0).req.bits.data := RegNext(io.tracegen.req.bits.data) + + io.tracegen.resp.valid := io.lsu.exe(0).iresp.valid + io.tracegen.resp.bits := DontCare + io.tracegen.resp.bits.tag := io.lsu.exe(0).iresp.bits.uop.uopc + io.tracegen.resp.bits.size := io.lsu.exe(0).iresp.bits.uop.mem_size + io.tracegen.resp.bits.data := io.lsu.exe(0).iresp.bits.data + + val store_resp_idx = PriorityEncoder((0 until rob_sz) map {i => + !rob_respd(i) && isWrite(rob(i).cmd) + }) + val can_do_store_resp = ~rob_respd(store_resp_idx) && isWrite(rob(store_resp_idx).cmd) && !isRead(rob(store_resp_idx).cmd) + when (can_do_store_resp && !io.lsu.exe(0).iresp.valid) { + rob_respd(store_resp_idx) := true.B + io.tracegen.resp.valid := true.B + io.tracegen.resp.bits.tag := rob(store_resp_idx).tag + } + + when (io.lsu.exe(0).iresp.valid) { + rob_respd(io.lsu.exe(0).iresp.bits.uop.rob_idx) := true.B + } + + io.lsu.exe(0).fresp.ready := true.B + io.lsu.exe(0).iresp.ready := true.B + + + io.lsu.exception := false.B + io.lsu.fence_dmem := false.B + + io.lsu.rob_pnr_idx := rob_tail + io.lsu.commit_load_at_rob_head := false.B + + io.lsu.brinfo := DontCare + io.lsu.brinfo.valid := false.B + io.lsu.rob_head_idx := rob_head + + +} + +class BoomTraceGenTile(val id: Int, val params: TraceGenParams, q: Parameters) + extends BaseTile(params, SynchronousCrossing(), HartsWontDeduplicate(params), q) { + val boom_params = p.alterMap(Map(TileKey -> BoomTileParams( + dcache=params.dcache, + core=BoomCoreParams(nPMPs=0, numLdqEntries=32, numStqEntries=32, useVM=false)))) + val dcache = LazyModule(new BoomNonBlockingDCache(hartId)(boom_params)) + + val intInwardNode: IntInwardNode = IntIdentityNode() + val intOutwardNode: IntOutwardNode = IntIdentityNode() + val slaveNode: TLInwardNode = TLIdentityNode() + val ceaseNode: IntOutwardNode = IntIdentityNode() + val haltNode: IntOutwardNode = IntIdentityNode() + val wfiNode: IntOutwardNode = IntIdentityNode() + + val masterNode = visibilityNode + masterNode := dcache.node + + override lazy val module = new BoomTraceGenTileModuleImp(this) +} + +class BoomTraceGenTileModuleImp(outer: BoomTraceGenTile) + extends BaseTileModuleImp(outer){ + + val status = IO(new GroundTestStatus) + + val tracegen = Module(new TraceGenerator(outer.params)) + tracegen.io.hartid := constants.hartid + + val ptw = Module(new DummyPTW(1)) + val lsu = Module(new LSU()(outer.boom_params, outer.dcache.module.edge)) + val boom_shim = Module(new BoomLSUShim()(outer.boom_params)) + ptw.io.requestors.head <> lsu.io.ptw + outer.dcache.module.io.lsu <> lsu.io.dmem + boom_shim.io.tracegen <> tracegen.io.mem + boom_shim.io.lsu <> lsu.io.core + + // Normally the PTW would use this port + lsu.io.hellacache := DontCare + lsu.io.hellacache.req.valid := false.B + + status.finished := tracegen.io.finished + status.timeout.valid := tracegen.io.timeout + status.timeout.bits := 0.U + status.error.valid := false.B +} + class TraceGenTileModuleImp(outer: TraceGenTile) extends BaseTileModuleImp(outer) { val status = IO(new GroundTestStatus)