// See LICENSE for license details. package rocket import Chisel._ import Chisel.ImplicitConversions._ import junctions._ import diplomacy._ import config._ import uncore.constants._ import uncore.tilelink2._ import uncore.util._ class ScratchpadSlavePort(implicit val p: Parameters) extends LazyModule { val coreDataBytes = p(XLen)/8 val node = TLManagerNode(TLManagerPortParameters( Seq(TLManagerParameters( address = List(AddressSet(0x80000000L, BigInt(p(DataScratchpadSize)-1))), regionType = RegionType.UNCACHED, executable = true, supportsArithmetic = if (p(UseAtomics)) TransferSizes(1, coreDataBytes) else TransferSizes.none, supportsLogical = if (p(UseAtomics)) TransferSizes(1, coreDataBytes) else TransferSizes.none, supportsPutPartial = TransferSizes(1, coreDataBytes), supportsPutFull = TransferSizes(1, coreDataBytes), supportsGet = TransferSizes(1, coreDataBytes), fifoId = Some(0))), // requests handled in FIFO order beatBytes = coreDataBytes, minLatency = 1)) lazy val module = new LazyModuleImp(this) { 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 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 = acq.opcode === TLMessages.PutFullData || acq.opcode === TLMessages.PutPartialData val isRead = !edge.hasData(acq) def formCacheReq(acq: TLBundleA) = { val req = Wire(new HellaCacheReq) req.cmd := MuxLookup(acq.opcode, Wire(M_XRD), Array( TLMessages.PutFullData -> M_XWR, TLMessages.PutPartialData -> M_XWR, TLMessages.ArithmeticData -> MuxLookup(acq.param, Wire(M_XRD), Array( TLAtomics.MIN -> M_XA_MIN, TLAtomics.MAX -> M_XA_MAX, TLAtomics.MINU -> M_XA_MINU, TLAtomics.MAXU -> M_XA_MAXU, TLAtomics.ADD -> M_XA_ADD)), TLMessages.LogicalData -> MuxLookup(acq.param, Wire(M_XRD), Array( TLAtomics.XOR -> M_XA_XOR, TLAtomics.OR -> M_XA_OR, TLAtomics.AND -> M_XA_AND, TLAtomics.SWAP -> M_XA_SWAP)), TLMessages.Get -> M_XRD)) // treat all loads as full words, so bytes appear in correct lane req.typ := Mux(isRead, log2Ceil(coreDataBytes), acq.size) req.addr := Mux(isRead, ~(~acq.address | (coreDataBytes-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)) // 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(coreDataBytes)-1,0), acq.data, Bool(false), coreDataBytes).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(isWrite, edge.AccessAck(acq, UInt(0)), edge.AccessAck(acq, UInt(0), UInt(0))) tl_in.d.bits.data := alignedGrantData // Tie off unused channels tl_in.b.valid := Bool(false) tl_in.c.ready := Bool(true) tl_in.e.ready := Bool(true) } }