diff --git a/src/main/scala/rocket/dcache.scala b/src/main/scala/rocket/dcache.scala index 9bd89541..a10d4080 100644 --- a/src/main/scala/rocket/dcache.scala +++ b/src/main/scala/rocket/dcache.scala @@ -4,7 +4,9 @@ package rocket import Chisel._ import junctions._ +import diplomacy._ import uncore.tilelink._ +import uncore.tilelink2._ import uncore.agents._ import uncore.coherence._ import uncore.constants._ @@ -495,60 +497,74 @@ class DCache(implicit p: Parameters) extends L1HellaCacheModule()(p) { } } -class ScratchpadSlavePort(implicit p: Parameters) extends CoreModule()(p) { - val io = new Bundle { - val tl = new ClientUncachedTileLinkIO().flip - val dmem = new HellaCacheIO +class ScratchpadSlavePort(implicit p: Parameters) extends LazyModule { + val beatBytes = p(XLen)/8 + val node = TLManagerNode(TLManagerPortParameters( + Seq(TLManagerParameters( + address = List(AddressSet(0x80000000L, p(DataScratchpadSize))), + regionType = RegionType.UNCACHED, + executable = true, + supportsPutPartial = TransferSizes(1, beatBytes), + supportsPutFull = TransferSizes(1, beatBytes), + fifoId = Some(0))), // requests handled in FIFO order + beatBytes = beatBytes, + minLatency = 1)) + + lazy val module = new LazyModuleImp(this) with HasCoreParameters { + val io = new Bundle { + val tl_in = node.bundleIn + val dmem = new HellaCacheIO + } + + val tl_in = io.tl_in(0) + val edge = node.edgesIn(0) + val beatBytes = edge.manager.beatBytes + + require(coreDataBits == beatBytes*8) + require(usingDataScratchpad) + + val s_ready :: s_wait :: s_replay :: s_grant :: Nil = Enum(UInt(), 4) + val state = Reg(init = s_ready) + when (io.dmem.resp.valid) { state := s_grant } + when (tl_in.d.fire()) { state := s_ready } + when (io.dmem.s2_nack) { state := s_replay } + when (io.dmem.req.fire()) { state := s_wait } + + val acq = Reg(tl_in.a.bits) + when (io.dmem.resp.valid) { acq.data := io.dmem.resp.bits.data } + when (tl_in.a.fire()) { acq := tl_in.a.bits } + + val isWrite = edge.hasData(acq) + val isRead = !isWrite + + def formCacheReq(acq: TLBundleA) = { + val req = Wire(new HellaCacheReq) + // treat all loads as full words, so bytes appear in correct lane + req.typ := Mux(isRead, log2Ceil(beatBytes), acq.size) + req.cmd := Mux(isRead, M_XRD, M_XWR) + req.addr := Mux(isRead, ~(~acq.address | (beatBytes-1)), acq.address) + req.tag := UInt(0) + req + } + + val ready = state === s_ready || tl_in.d.fire() + io.dmem.req.valid := (tl_in.a.valid && ready) || state === s_replay + tl_in.a.ready := io.dmem.req.ready && ready + io.dmem.req.bits := formCacheReq(Mux(state === s_replay, acq, tl_in.a.bits)) + // this blows. the TL data is already in the correct byte lane, but the D$ + // expects right-justified store data, so that it can steer the bytes. + io.dmem.s1_data := new LoadGen(acq.size, Bool(false), acq.address(log2Ceil(beatBytes)-1,0), acq.data, Bool(false), beatBytes).data + io.dmem.s1_kill := false + io.dmem.invalidate_lr := false + + // place AMO data in correct word lane + val minAMOBytes = 4 + val grantData = Mux(io.dmem.resp.valid, io.dmem.resp.bits.data, acq.data) + val alignedGrantData = Mux(acq.size <= log2Ceil(minAMOBytes), Fill(coreDataBytes/minAMOBytes, grantData(8*minAMOBytes-1, 0)), grantData) + + tl_in.d.valid := io.dmem.resp.valid || state === s_grant + tl_in.d.bits := Mux(isRead, + edge.AccessAck(acq, UInt(0), alignedGrantData), + edge.AccessAck(acq, UInt(0))) } - - val s_ready :: s_wait :: s_replay :: s_grant :: Nil = Enum(UInt(), 4) - val state = Reg(init = s_ready) - when (io.dmem.resp.valid) { state := s_grant } - when (io.tl.grant.fire()) { state := s_ready } - when (io.dmem.s2_nack) { state := s_replay } - when (io.dmem.req.fire()) { state := s_wait } - - val acq = Reg(io.tl.acquire.bits) - when (io.dmem.resp.valid) { acq.data := io.dmem.resp.bits.data } - when (io.tl.acquire.fire()) { acq := io.tl.acquire.bits } - - val isRead = acq.isBuiltInType(Acquire.getType) - val isWrite = acq.isBuiltInType(Acquire.putType) - assert(state === s_ready || isRead || isWrite) - require(coreDataBits == acq.tlDataBits) - require(usingDataScratchpad) - - def formCacheReq(acq: Acquire) = { - val req = Wire(new HellaCacheReq) - // treat all loads as full words, so bytes appear in correct lane - req.typ := Mux(isRead, log2Ceil(acq.tlDataBytes), acq.op_size()) - req.cmd := acq.op_code() - req.addr := Mux(isRead, ~(~acq.full_addr() | (acq.tlDataBytes-1)), acq.full_addr()) - req.tag := UInt(0) - req - } - - val ready = state === s_ready || io.tl.grant.fire() - io.dmem.req.valid := (io.tl.acquire.valid && ready) || state === s_replay - io.tl.acquire.ready := io.dmem.req.ready && ready - io.dmem.req.bits := formCacheReq(Mux(state === s_replay, acq, io.tl.acquire.bits)) - // this blows. the TL data is already in the correct byte lane, but the D$ - // expects right-justified store data, so that it can steer the bytes. - io.dmem.s1_data := new LoadGen(acq.op_size(), Bool(false), acq.addr_byte(), acq.data, Bool(false), acq.tlDataBytes).data - io.dmem.s1_kill := false - io.dmem.invalidate_lr := false - - // place AMO data in correct word lane - val minAMOBytes = 4 - val grantData = Mux(io.dmem.resp.valid, io.dmem.resp.bits.data, acq.data) - val alignedGrantData = Mux(acq.op_size() <= log2Ceil(minAMOBytes), Fill(coreDataBytes/minAMOBytes, grantData(8*minAMOBytes-1, 0)), grantData) - - io.tl.grant.valid := io.dmem.resp.valid || state === s_grant - io.tl.grant.bits := Grant( - is_builtin_type = Bool(true), - g_type = acq.getBuiltInGrantType(), - client_xact_id = acq.client_xact_id, - manager_xact_id = UInt(0), - addr_beat = acq.addr_beat, - data = alignedGrantData) } diff --git a/src/main/scala/rocket/tile.scala b/src/main/scala/rocket/tile.scala index 5d30c1a1..f3c9d27b 100644 --- a/src/main/scala/rocket/tile.scala +++ b/src/main/scala/rocket/tile.scala @@ -27,40 +27,43 @@ case class RoccParameters( case class TileBundleConfig( nCachedTileLinkPorts: Int, nUncachedTileLinkPorts: Int, - xLen: Int, - hasSlavePort: Boolean) + xLen: Int) -class TileIO(c: TileBundleConfig)(implicit p: Parameters) extends Bundle { +class TileIO(c: TileBundleConfig, node: Option[TLInwardNode] = None)(implicit p: Parameters) extends Bundle { val cached = Vec(c.nCachedTileLinkPorts, new ClientTileLinkIO) val uncached = Vec(c.nUncachedTileLinkPorts, new ClientUncachedTileLinkIO) val hartid = UInt(INPUT, c.xLen) val interrupts = new TileInterrupts().asInput - val slave = c.hasSlavePort.option(new ClientUncachedTileLinkIO().flip) + val slave = node.map(_.inward.bundleIn) val resetVector = UInt(INPUT, c.xLen) override def cloneType = new TileIO(c).asInstanceOf[this.type] } abstract class TileImp(l: LazyTile)(implicit p: Parameters) extends LazyModuleImp(l) { + val io: TileIO +} + +abstract class LazyTile(implicit p: Parameters) extends LazyModule { val nCachedTileLinkPorts = p(NCachedTileLinkPorts) val nUncachedTileLinkPorts = p(NUncachedTileLinkPorts) val dcacheParams = p.alterPartial({ case CacheName => "L1D" }) val bc = TileBundleConfig( nCachedTileLinkPorts = nCachedTileLinkPorts, nUncachedTileLinkPorts = nUncachedTileLinkPorts, - xLen = p(XLen), - hasSlavePort = p(DataScratchpadSize) > 0) + xLen = p(XLen)) - val io: TileIO -} - -abstract class LazyTile(implicit p: Parameters) extends LazyModule { val module: TileImp } class RocketTile(implicit p: Parameters) extends LazyTile { + val slave = if (p(DataScratchpadSize) == 0) None else Some(TLOutputNode()) + val scratch = if (p(DataScratchpadSize) == 0) None else Some(LazyModule(new ScratchpadSlavePort()(dcacheParams))) + + (slave zip scratch) foreach { case (node, lm) => node := lm.node } + lazy val module = new TileImp(this) { - val io = new TileIO(bc) + val io = new TileIO(bc, slave) val buildRocc = p(BuildRoCC) val usingRocc = !buildRocc.isEmpty val nRocc = buildRocc.size @@ -146,11 +149,7 @@ class RocketTile(implicit p: Parameters) extends LazyTile { core.io.ptw <> ptw.io.dpath } - io.slave foreach { case slavePort => - val adapter = Module(new ScratchpadSlavePort()(dcacheParams)) - adapter.io.tl <> TileLinkFragmenter(slavePort) - adapter.io.dmem +=: dcPorts - } + scratch.foreach { lm => lm.module.io.dmem +=: dcPorts } require(dcPorts.size == core.dcacheArbPorts) val dcArb = Module(new HellaCacheArbiter(dcPorts.size)(dcacheParams)) diff --git a/src/main/scala/uncore/tilelink2/package.scala b/src/main/scala/uncore/tilelink2/package.scala index 55ff6b27..3fcd3fc5 100644 --- a/src/main/scala/uncore/tilelink2/package.scala +++ b/src/main/scala/uncore/tilelink2/package.scala @@ -5,9 +5,11 @@ import diplomacy._ package object tilelink2 { + type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle] type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle] type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle] type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]] + def OH1ToOH(x: UInt) = (x << 1 | UInt(1)) & ~Cat(UInt(0, width=1), x) def OH1ToUInt(x: UInt) = OHToUInt(OH1ToOH(x)) def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0)