diff --git a/src/main/scala/bus/simplebus/Crossbar.scala b/src/main/scala/bus/simplebus/Crossbar.scala index 43399d6c04f66920ef1d787988620862ad39d8e4..54532afd94c4c8697b66b0c48fc13341f08d97e4 100644 --- a/src/main/scala/bus/simplebus/Crossbar.scala +++ b/src/main/scala/bus/simplebus/Crossbar.scala @@ -5,57 +5,47 @@ import chisel3.util._ import utils._ -class SimpleBusCrossbar(m: Int, addressSpace: List[(Long, Long)]) extends Module { +class SimpleBusCrossbar1toN(addressSpace: List[(Long, Long)]) extends Module { val io = IO(new Bundle { - val in = Flipped(Vec(m, new SimpleBusUC)) + val in = Flipped(new SimpleBusUC) val out = Vec(addressSpace.length, new SimpleBusUC) }) - require(m == 1, "now we only support 1 input channel") - val inSel = io.in(0) + val s_idle :: s_resp :: Nil = Enum(2) + val state = RegInit(s_idle) // select the output channel according to the address - val addr = inSel.req.bits.addr + val addr = io.in.req.bits.addr val outSelVec = VecInit(addressSpace.map( range => (addr >= range._1.U && addr < (range._1 + range._2).U))) val outSelIdx = PriorityEncoder(outSelVec) val outSel = io.out(outSelIdx) + val outSelIdxResp = RegEnable(outSelIdx, outSel.req.fire() && (state === s_idle)) + val outSelResp = io.out(outSelIdxResp) - assert(!inSel.req.valid || outSelVec.asUInt.orR, "address decode error, bad addr = 0x%x\n", addr) - assert(!(inSel.req.valid && outSelVec.asUInt.andR), "address decode error, bad addr = 0x%x\n", addr) - - val s_idle :: s_req :: s_resp :: Nil = Enum(3) - val state = RegInit(s_idle) + assert(!io.in.req.valid || outSelVec.asUInt.orR, "address decode error, bad addr = 0x%x\n", addr) + assert(!(io.in.req.valid && outSelVec.asUInt.andR), "address decode error, bad addr = 0x%x\n", addr) // bind out.req channel (io.out zip outSelVec).map { case (o, v) => { - o.req.bits := inSel.req.bits - o.req.valid := v && ((inSel.req.valid && (state === s_idle)) || (state === s_req)) + o.req.bits := io.in.req.bits + o.req.valid := v && (io.in.req.valid && (state === s_idle)) o.resp.ready := v }} - val bypass_s_resp = Mux(outSel.resp.fire(), s_idle, s_resp) - val bypass_s_req = Mux(outSel.req.fire(), bypass_s_resp, s_req) switch (state) { - is (s_idle) { - when (inSel.req.valid) { state := bypass_s_req } - } - is (s_req) { - when (outSel.req.fire()) { state := bypass_s_resp } - } - is (s_resp) { - when (outSel.resp.fire()) { state := s_idle } - } + is (s_idle) { when (outSel.req.fire()) { state := s_resp } } + is (s_resp) { when (outSelResp.resp.fire()) { state := s_idle } } } - inSel.resp.valid := outSel.resp.fire() - inSel.resp.bits <> outSel.resp.bits - outSel.resp.ready := inSel.resp.ready - inSel.req.ready := outSel.req.ready + io.in.resp.valid := outSelResp.resp.fire() + io.in.resp.bits <> outSelResp.resp.bits + outSelResp.resp.ready := io.in.resp.ready + io.in.req.ready := outSel.req.ready Debug() { - when (state === s_idle && inSel.req.valid) { - printf(p"${GTimer()}: xbar: in.req: ${inSel.req.bits}\n") + when (state === s_idle && io.in.req.valid) { + printf(p"${GTimer()}: xbar: in.req: ${io.in.req.bits}\n") } when (outSel.req.fire()) { @@ -65,8 +55,62 @@ class SimpleBusCrossbar(m: Int, addressSpace: List[(Long, Long)]) extends Module printf(p"${GTimer()}: xbar: outSelIdx= ${outSelIdx}, outSel.resp: ${outSel.resp.bits}\n") } - when (inSel.resp.fire()) { - printf(p"${GTimer()}: xbar: in.resp: ${inSel.resp.bits}\n") + when (io.in.resp.fire()) { + printf(p"${GTimer()}: xbar: in.resp: ${io.in.resp.bits}\n") + } + } +} + +class SimpleBusCrossbarNto1(n: Int) extends Module { + val io = IO(new Bundle { + val in = Flipped(Vec(n, new SimpleBusUC)) + val out = new SimpleBusUC + }) + + val s_idle :: s_readResp :: s_writeResp :: Nil = Enum(3) + val state = RegInit(s_idle) + + val lockWriteFun = ((x: SimpleBusReqBundle) => x.isWrite() && x.isBurst()) + val inputArb = Module(new LockingArbiter(chiselTypeOf(io.in(0).req.bits), n, 8, Some(lockWriteFun))) + (inputArb.io.in zip io.in.map(_.req)).map{ case (arb, in) => arb <> in } + val thisReq = inputArb.io.out + assert(!(thisReq.valid && !thisReq.bits.isRead() && !thisReq.bits.isWrite())) + val inflightSrc = Reg(UInt(log2Up(n).W)) + + io.out.req.bits := thisReq.bits + // bind correct valid and ready signals + io.out.req.valid := thisReq.valid && (state === s_idle) + thisReq.ready := io.out.req.ready && (state === s_idle) + + io.in.map(_.resp.bits := io.out.resp.bits) + io.in.map(_.resp.valid := false.B) + (io.in(inflightSrc).resp, io.out.resp) match { case (l, r) => { + l.valid := r.valid + r.ready := l.ready + }} + + switch (state) { + is (s_idle) { + when (thisReq.fire()) { + inflightSrc := inputArb.io.chosen + when (thisReq.bits.isRead()) { state := s_readResp } + .elsewhen (thisReq.bits.isWriteLast() || thisReq.bits.isWriteSingle()) { state := s_writeResp } + } } + is (s_readResp) { when (io.out.resp.fire() && io.out.resp.bits.isReadLast()) { state := s_idle } } + is (s_writeResp) { when (io.out.resp.fire()) { state := s_idle } } } } + +class SimpleBusCrossbar(n: Int, addressSpace: List[(Long, Long)]) extends Module { + val io = IO(new Bundle { + val in = Flipped(Vec(n, new SimpleBusUC)) + val out = Vec(addressSpace.length, new SimpleBusUC) + }) + + val inXbar = Module(new SimpleBusCrossbarNto1(n)) + val outXbar = Module(new SimpleBusCrossbar1toN(addressSpace)) + inXbar.io.in <> io.in + outXbar.io.in <> inXbar.io.out + io.out <> outXbar.io.out +} diff --git a/src/main/scala/noop/Cache.scala b/src/main/scala/noop/Cache.scala index c80696b7f78210919e87a586cd9db8ec77415f43..e21cbdb8d550ce4a182053877ec5052aac4033a2 100644 --- a/src/main/scala/noop/Cache.scala +++ b/src/main/scala/noop/Cache.scala @@ -8,14 +8,29 @@ import bus.simplebus._ import bus.axi4._ import utils._ +case class CacheConfig ( + ro: Boolean = false, + name: String = "cache", + userBits: Int = 0, + + totalSize: Int = 32, // Kbytes + ways: Int = 4 +) + sealed trait HasCacheConst { + implicit val cacheConfig: CacheConfig + val AddrBits: Int val XLEN: Int - val TotalSize = 32 // Kbytes + val ro = cacheConfig.ro + val cacheName = cacheConfig.name + val userBits = cacheConfig.userBits + + val TotalSize = cacheConfig.totalSize + val Ways = cacheConfig.ways val LineSize = XLEN // byte val LineBeats = LineSize / 8 //DATA WIDTH 64 - val Ways = 4 val Sets = TotalSize * 1024 / LineSize / Ways val OffsetBits = log2Up(LineSize) val IndexBits = log2Up(Sets) @@ -40,10 +55,10 @@ sealed trait HasCacheConst { def isSetConflict(a1: UInt, a2: UInt) = (a1.asTypeOf(addrBundle).index === a2.asTypeOf(addrBundle).index) } -sealed abstract class CacheBundle extends Bundle with HasNOOPParameter with HasCacheConst -sealed abstract class CacheModule extends Module with HasNOOPParameter with HasCacheConst +sealed abstract class CacheBundle(implicit cacheConfig: CacheConfig) extends Bundle with HasNOOPParameter with HasCacheConst +sealed abstract class CacheModule(implicit cacheConfig: CacheConfig) extends Module with HasNOOPParameter with HasCacheConst -sealed class MetaBundle extends CacheBundle { +sealed class MetaBundle(implicit val cacheConfig: CacheConfig) extends CacheBundle { val tag = Output(UInt(TagBits.W)) val valid = Output(Bool()) val dirty = Output(Bool()) @@ -56,7 +71,7 @@ sealed class MetaBundle extends CacheBundle { } } -sealed class DataBundle extends CacheBundle { +sealed class DataBundle(implicit val cacheConfig: CacheConfig) extends CacheBundle { val data = Output(UInt(DataBits.W)) def apply(data: UInt) = { @@ -65,15 +80,15 @@ sealed class DataBundle extends CacheBundle { } } -sealed class Stage1IO(val userBits: Int = 0) extends CacheBundle { +sealed class Stage1IO(implicit val cacheConfig: CacheConfig) extends CacheBundle { val req = new SimpleBusReqBundle(userBits = userBits) } // meta read -sealed class CacheStage1(ro: Boolean, name: String, userBits: Int = 0) extends CacheModule { +sealed class CacheStage1(implicit val cacheConfig: CacheConfig) extends CacheModule { val io = IO(new Bundle { val in = Flipped(Decoupled(new SimpleBusReqBundle(userBits = userBits))) - val out = Decoupled(new Stage1IO(userBits)) + val out = Decoupled(new Stage1IO) val metaReadBus = CacheMetaArrayReadBus() val dataReadBus = CacheDataArrayReadBus() @@ -102,19 +117,20 @@ sealed class CacheStage1(ro: Boolean, name: String, userBits: Int = 0) extends C io.in.ready := (!io.in.valid || io.out.fire()) && io.metaReadBus.req.ready && io.dataReadBus.req.ready } -sealed class Stage2IO(val userBits: Int = 0) extends CacheBundle { +sealed class Stage2IO(implicit val cacheConfig: CacheConfig) extends CacheBundle { val req = new SimpleBusReqBundle(userBits = userBits) val metas = Vec(Ways, new MetaBundle) val datas = Vec(Ways, new DataBundle) val hit = Output(Bool()) val waymask = Output(UInt(Ways.W)) + val mmio = Output(Bool()) } // check -sealed class CacheStage2(ro: Boolean, name: String, userBits: Int = 0) extends CacheModule { +sealed class CacheStage2(implicit val cacheConfig: CacheConfig) extends CacheModule { val io = IO(new Bundle { - val in = Flipped(Decoupled(new Stage1IO(userBits))) - val out = Decoupled(new Stage2IO(userBits)) + val in = Flipped(Decoupled(new Stage1IO)) + val out = Decoupled(new Stage2IO) val metaReadResp = Flipped(Vec(Ways, new MetaBundle)) val dataReadResp = Flipped(Vec(Ways, new DataBundle)) }) @@ -131,31 +147,34 @@ sealed class CacheStage2(ro: Boolean, name: String, userBits: Int = 0) extends C io.out.bits.hit := io.in.valid && hitVec.orR io.out.bits.waymask := waymask io.out.bits.datas := io.dataReadResp + io.out.bits.mmio := AddressSpace.isMMIO(req.addr) - io.out.bits.req <> io.in.bits.req + io.out.bits.req <> req io.out.valid := io.in.valid io.in.ready := !io.in.valid || io.out.fire() } // writeback -sealed class CacheStage3(ro: Boolean, name: String, userBits: Int = 0) extends CacheModule { +sealed class CacheStage3(implicit val cacheConfig: CacheConfig) extends CacheModule { val io = IO(new Bundle { - val in = Flipped(Decoupled(new Stage2IO(userBits))) + val in = Flipped(Decoupled(new Stage2IO)) val out = Decoupled(new SimpleBusRespBundle(userBits = userBits)) val isFinish = Output(Bool()) - val addr = Output(UInt(AddrBits.W)) val flush = Input(Bool()) val dataWriteBus = CacheDataArrayWriteBus() val dataReadBus = CacheDataArrayReadBus() val metaWriteBus = CacheMetaArrayWriteBus() val mem = new SimpleBusUC + val mmio = new SimpleBusUC }) val req = io.in.bits.req val addr = req.addr.asTypeOf(addrBundle) + val mmio = io.in.valid && io.in.bits.mmio val hit = io.in.valid && io.in.bits.hit val miss = io.in.valid && !io.in.bits.hit val meta = Mux1H(io.in.bits.waymask, io.in.bits.metas) + assert(!(mmio && hit), "MMIO request should not hit in cache") val dataRead = Mux1H(io.in.bits.waymask, io.in.bits.datas).data val wordMask = Mux(!ro.B && req.isWrite(), MaskExpand(req.wmask), 0.U(DataBits.W)) @@ -170,7 +189,7 @@ sealed class CacheStage3(ro: Boolean, name: String, userBits: Int = 0) extends C data = Wire(new MetaBundle).apply(tag = meta.tag, valid = true.B, dirty = (!ro).B) ) - val s_idle :: s_memReadReq :: s_memReadResp :: s_memWriteReq :: s_memWriteResp :: s_wait_resp :: Nil = Enum(6) + val s_idle :: s_memReadReq :: s_memReadResp :: s_memWriteReq :: s_memWriteResp :: s_mmioReq :: s_mmioResp :: s_wait_resp :: Nil = Enum(8) val state = RegInit(s_idle) val needFlush = RegInit(false.B) when (io.flush && (state =/= s_idle)) { needFlush := true.B } @@ -208,10 +227,16 @@ sealed class CacheStage3(ro: Boolean, name: String, userBits: Int = 0) extends C io.mem.resp.ready := true.B io.mem.req.valid := (state === s_memReadReq) || ((state === s_memWriteReq) && (state2 === s2_memWriteReq)) + // mmio + io.mmio.req.bits := io.in.bits.req + io.mmio.resp.ready := true.B + io.mmio.req.valid := (state === s_mmioReq) + val afterFirstRead = RegInit(false.B) val alreadyOutFire = RegEnable(true.B, init = false.B, io.out.fire()) val readingFirst = !afterFirstRead && io.mem.resp.fire() && (state === s_memReadResp) - val inRdataRegDemand = RegEnable(io.mem.resp.bits.rdata, readingFirst) + val inRdataRegDemand = RegEnable(Mux(mmio, io.mmio.resp.bits.rdata, io.mem.resp.bits.rdata), + Mux(mmio, state === s_mmioResp, readingFirst)) switch (state) { is (s_idle) { @@ -219,8 +244,14 @@ sealed class CacheStage3(ro: Boolean, name: String, userBits: Int = 0) extends C alreadyOutFire := false.B // actually this can use s2 to test - when (miss && !io.flush) { state := Mux(!ro.B && meta.dirty, s_memWriteReq, s_memReadReq) } + when ((miss || mmio) && !io.flush) { + state := Mux(mmio, s_mmioReq, Mux(!ro.B && meta.dirty, s_memWriteReq, s_memReadReq)) + } } + + is (s_mmioReq) { when (io.mmio.req.fire()) { state := s_mmioResp } } + is (s_mmioResp) { when (io.mmio.resp.fire()) { state := s_wait_resp } } + is (s_memReadReq) { when (io.mem.req.fire()) { state := s_memReadResp readBeatCnt.value := addr.wordIndex @@ -267,26 +298,25 @@ sealed class CacheStage3(ro: Boolean, name: String, userBits: Int = 0) extends C io.out.bits.rdata := Mux(hit, dataRead, inRdataRegDemand) io.out.bits.cmd := DontCare io.out.bits.user.zip(io.in.bits.req.user).map { case (o,i) => o := i } - io.out.valid := io.in.valid && Mux(hit, true.B, Mux(req.isWrite(), state === s_wait_resp, afterFirstRead && !alreadyOutFire)) + io.out.valid := io.in.valid && Mux(hit, true.B, Mux(req.isWrite() || mmio, state === s_wait_resp, afterFirstRead && !alreadyOutFire)) // With critical-word first, the pipeline registers between // s2 and s3 can not be overwritten before a missing request // is totally handled. We use io.isFinish to indicate when the // request really ends. io.isFinish := Mux(hit || req.isWrite(), io.out.fire(), (state === s_wait_resp) && (io.out.fire() || alreadyOutFire)) - io.addr := req.addr io.in.ready := io.out.ready && (state === s_idle) && !miss assert(!(metaHitWriteBus.req.valid && metaRefillWriteBus.req.valid)) assert(!(dataHitWriteBus.req.valid && dataRefillWriteBus.req.valid)) Debug(debug) { - printf("%d: [" + name + " stage3]: in.ready = %d, in.valid = %d, state = %d, addr = %x\n", + printf("%d: [" + cacheName + " stage3]: in.ready = %d, in.valid = %d, state = %d, addr = %x\n", GTimer(), io.in.ready, io.in.valid, state, req.addr) } } // probe -sealed class CacheProbeStage(ro: Boolean, name: String) extends CacheModule { +sealed class CacheProbeStage(implicit val cacheConfig: CacheConfig) extends CacheModule { val io = IO(new Bundle { val in = Flipped(Decoupled(new SimpleBusReqBundle)) val out = Decoupled(new SimpleBusRespBundle) @@ -340,22 +370,22 @@ sealed class CacheProbeStage(ro: Boolean, name: String) extends CacheModule { Mux(hit, SimpleBusCmd.probeHit, SimpleBusCmd.probeMiss)) } -class Cache(ro: Boolean, name: String, userBits: Int = 0) extends CacheModule { +class Cache(implicit val cacheConfig: CacheConfig) extends CacheModule { val io = IO(new Bundle { val in = Flipped(new SimpleBusUC(userBits = userBits)) - val addr = Output(UInt(AddrBits.W)) val flush = Input(UInt(2.W)) val out = new SimpleBusC + val mmio = new SimpleBusUC }) // cpu pipeline - val s1 = Module(new CacheStage1(ro, name, userBits)) - val s2 = Module(new CacheStage2(ro, name, userBits)) - val s3 = Module(new CacheStage3(ro, name, userBits)) + val s1 = Module(new CacheStage1) + val s2 = Module(new CacheStage2) + val s3 = Module(new CacheStage3) val metaArray = Module(new SRAMTemplate(new MetaBundle, set = Sets, way = Ways, shouldReset = true, singlePort = true)) val dataArray = Module(new SRAMTemplate(new DataBundle, set = Sets * LineBeats, way = Ways, singlePort = true)) - if (name == "icache") { + if (cacheName == "icache") { // flush icache when executing fence.i val flushICache = WireInit(false.B) BoringUtils.addSink(flushICache, "MOUFlushICache") @@ -367,8 +397,8 @@ class Cache(ro: Boolean, name: String, userBits: Int = 0) extends CacheModule { PipelineConnect(s2.io.out, s3.io.in, s3.io.isFinish, io.flush(1)) io.in.resp <> s3.io.out s3.io.flush := io.flush(1) - io.addr := s3.io.addr io.out.mem <> s3.io.mem + io.mmio <> s3.io.mmio // stalling s1.io.s2Req.valid := s2.io.in.valid @@ -378,7 +408,7 @@ class Cache(ro: Boolean, name: String, userBits: Int = 0) extends CacheModule { s1.io.s2s3Miss := s3.io.in.valid && !s3.io.in.bits.hit // coherence state machine - val coh = Module(new CacheProbeStage(ro, name)) + val coh = Module(new CacheProbeStage) coh.io.in <> io.out.coh.req io.out.coh.resp <> coh.io.out @@ -406,15 +436,25 @@ class Cache(ro: Boolean, name: String, userBits: Int = 0) extends CacheModule { s2.io.metaReadResp := metaArray.io.r.resp.data s2.io.dataReadResp := dataArray.io.r.resp.data - BoringUtils.addSource(s3.io.in.valid && s3.io.in.bits.hit, "perfCntCondM" + name + "Hit") + BoringUtils.addSource(s3.io.in.valid && s3.io.in.bits.hit, "perfCntCondM" + cacheName + "Hit") Debug(debug) { - io.in.dump(name + ".in") + io.in.dump(cacheName + ".in") printf("%d: s1:(%d,%d), s2:(%d,%d), s3:(%d,%d)\n", GTimer(), s1.io.in.valid, s1.io.in.ready, s2.io.in.valid, s2.io.in.ready, s3.io.in.valid, s3.io.in.ready) - when (s1.io.in.valid) { printf(p"[${name}.S1]: ${s1.io.in.bits}\n") } - when (s2.io.in.valid) { printf(p"[${name}.S2]: ${s2.io.in.bits.req}\n") } - when (s3.io.in.valid) { printf(p"[${name}.S3]: ${s3.io.in.bits.req}\n") } - s3.io.mem.dump(name + ".mem") + when (s1.io.in.valid) { printf(p"[${cacheName}.S1]: ${s1.io.in.bits}\n") } + when (s2.io.in.valid) { printf(p"[${cacheName}.S2]: ${s2.io.in.bits.req}\n") } + when (s3.io.in.valid) { printf(p"[${cacheName}.S3]: ${s3.io.in.bits.req}\n") } + s3.io.mem.dump(cacheName + ".mem") + } +} + +object Cache { + def apply(in: SimpleBusUC, mmio: SimpleBusUC, flush: UInt)(implicit cacheConfig: CacheConfig) = { + val cache = Module(new Cache) + cache.io.flush := flush + cache.io.in <> in + mmio <> cache.io.mmio + cache.io.out } } diff --git a/src/main/scala/noop/EXU.scala b/src/main/scala/noop/EXU.scala index bb955c9e07be37b875957ad8f671215483e38742..f3281a0c20f92b24600b732282eea0b7339ff51e 100644 --- a/src/main/scala/noop/EXU.scala +++ b/src/main/scala/noop/EXU.scala @@ -13,9 +13,7 @@ class EXU(implicit val p: NOOPConfig) extends NOOPModule { val out = Decoupled(new CommitIO) val flush = Input(Bool()) val dmem = new SimpleBusUC - val mmio = new SimpleBusUC val forward = new ForwardIO - //val wbData = Input(UInt(32.W)) }) val src1 = io.in.bits.data.src1 @@ -37,7 +35,6 @@ class EXU(implicit val p: NOOPConfig) extends NOOPModule { lsu.io.wdata := src2 io.out.bits.isMMIO := lsu.io.isMMIO io.dmem <> lsu.io.dmem - io.mmio <> lsu.io.mmio lsu.io.out.ready := true.B val mdu = Module(new MDU) diff --git a/src/main/scala/noop/IFU.scala b/src/main/scala/noop/IFU.scala index e72a759ab59a1f52494c10373bcf654cfc9a7ed5..c7018bde6058e1ee116bcf5d424b203089f2693a 100644 --- a/src/main/scala/noop/IFU.scala +++ b/src/main/scala/noop/IFU.scala @@ -13,8 +13,7 @@ trait HasResetVector { class IFU extends NOOPModule with HasResetVector { val io = IO(new Bundle { - val imem = new SimpleBusUC(userBits = AddrBits) - val pc = Input(UInt(AddrBits.W)) + val imem = new SimpleBusUC(userBits = AddrBits*2) val out = Decoupled(new CtrlFlowIO) val redirect = Flipped(new RedirectIO) val flushVec = Output(UInt(4.W)) @@ -41,16 +40,18 @@ class IFU extends NOOPModule with HasResetVector { io.bpFlush := false.B io.imem.req.bits.apply(addr = Cat(pc(AddrBits-1,2),0.U(2.W)), //cache will treat it as Cat(pc(63,3),0.U(3.W)) - size = "b11".U, cmd = SimpleBusCmd.read, wdata = 0.U, wmask = 0.U, user = npc) + size = "b11".U, cmd = SimpleBusCmd.read, wdata = 0.U, wmask = 0.U, user = Cat(npc, pc)) io.imem.req.valid := io.out.ready io.imem.resp.ready := io.out.ready || io.flushVec(0) io.out.bits := DontCare - io.out.bits.pc := io.pc //inst path only uses 32bit inst, get the right inst according to pc(2) - io.out.bits.instr := (if (XLEN == 64) io.imem.resp.bits.rdata.asTypeOf(Vec(2, UInt(32.W)))(io.pc(2)) + io.out.bits.instr := (if (XLEN == 64) io.imem.resp.bits.rdata.asTypeOf(Vec(2, UInt(32.W)))(io.out.bits.pc(2)) else io.imem.resp.bits.rdata) - io.imem.resp.bits.user.map(io.out.bits.pnpc := _) + io.imem.resp.bits.user.map{ case x => + io.out.bits.pc := x(AddrBits-1,0) + io.out.bits.pnpc := x(AddrBits*2-1,AddrBits) + } io.out.valid := io.imem.resp.valid && !io.flushVec(0) BoringUtils.addSource(BoolStopWatch(io.imem.req.valid, io.imem.resp.fire()), "perfCntCondMimemStall") diff --git a/src/main/scala/noop/NOOP.scala b/src/main/scala/noop/NOOP.scala index 23388eb3dea899f21e2bd3d5f2d1a7bce07b7cc2..20eb18e4a2bc9c010e2d4605cfc9be5697c0fb7b 100644 --- a/src/main/scala/noop/NOOP.scala +++ b/src/main/scala/noop/NOOP.scala @@ -80,26 +80,9 @@ class NOOP(implicit val p: NOOPConfig) extends NOOPModule { // forward isu.io.forward <> exu.io.forward - io.imem <> (if (HasIcache) { - val icache = Module(new Cache(ro = true, name = "icache", userBits = AddrBits)) - icache.io.in <> ifu.io.imem - icache.io.flush := Fill(2, ifu.io.flushVec(0) | ifu.io.bpFlush) - ifu.io.pc := icache.io.addr - icache.io.out - } else { ifu.io.imem }) - - io.dmem <> (if (HasDcache) { - val dcache = Module(new Cache(ro = false, name = "dcache")) - dcache.io.in <> exu.io.dmem - dcache.io.flush := Fill(2, false.B) - dcache.io.out - } else { - val busC = Wire(new SimpleBusC) - busC.mem <> exu.io.dmem - busC.coh := DontCare - busC.coh.req.valid := false.B - busC.coh.resp.ready := true.B - busC - }) - io.mmio <> exu.io.mmio + val mmioXbar = Module(new SimpleBusCrossbarNto1(2)) + io.imem <> Cache(ifu.io.imem, mmioXbar.io.in(0), Fill(2, ifu.io.flushVec(0) | ifu.io.bpFlush))( + CacheConfig(ro = true, name = "icache", userBits = AddrBits*2)) + io.dmem <> Cache(exu.io.dmem, mmioXbar.io.in(1), "b00".U)(CacheConfig(ro = false, name = "dcache")) + io.mmio <> mmioXbar.io.out } diff --git a/src/main/scala/noop/fu/LSU.scala b/src/main/scala/noop/fu/LSU.scala index c1cbd3c7c23695ff6bf69b5528886d23a329f525..a23834ccc7728d4fa285af02943afb10a84d7a32 100644 --- a/src/main/scala/noop/fu/LSU.scala +++ b/src/main/scala/noop/fu/LSU.scala @@ -1,5 +1,4 @@ package noop -//TODO(rv64) import chisel3._ import chisel3.util._ import chisel3.util.experimental.BoringUtils @@ -26,7 +25,6 @@ object LSUOpType { class LSUIO extends FunctionUnitIO { val wdata = Input(UInt(XLEN.W)) val dmem = new SimpleBusUC - val mmio = new SimpleBusUC val isMMIO = Output(Bool()) } @@ -63,39 +61,27 @@ class LSU extends NOOPModule { val addr = src1 + src2 val addrLatch = RegNext(addr) val isStore = valid && LSUOpType.isStore(func) + val partialLoad = !isStore && (func =/= LSUOpType.ld) val s_idle :: s_wait_resp :: s_partialLoad :: Nil = Enum(3) val state = RegInit(s_idle) - val mmio = AddressSpace.isMMIO(addr) - val partialLoad = !isStore && (func =/= LSUOpType.ld) - switch (state) { - is (s_idle) { when (valid) { - when (Mux(mmio, io.mmio.req.fire(), dmem.req.fire())) { state := Mux(isStore && !mmio, s_partialLoad, s_wait_resp) } - }} - is (s_wait_resp) { - when (Mux(mmio, io.mmio.resp.fire(), dmem.resp.fire())) { state := Mux(partialLoad, s_partialLoad, s_idle) } - } + is (s_idle) { when (dmem.req.fire()) { state := Mux(isStore, s_partialLoad, s_wait_resp) } } + is (s_wait_resp) { when (dmem.resp.fire()) { state := Mux(partialLoad, s_partialLoad, s_idle) } } is (s_partialLoad) { state := s_idle } } val size = func(1,0) dmem.req.bits.apply(addr = addr, size = size, wdata = genWdata(io.wdata, size), wmask = genWmask(addr, size), cmd = Mux(isStore, SimpleBusCmd.write, SimpleBusCmd.read)) - dmem.req.valid := valid && (state === s_idle) && !mmio + dmem.req.valid := valid && (state === s_idle) dmem.resp.ready := true.B - io.mmio.req.bits := dmem.req.bits - io.mmio.req.valid := valid && (state === s_idle) && mmio - io.mmio.resp.ready := true.B - - io.out.valid := Mux(isStore && !mmio, state === s_partialLoad, Mux(partialLoad, state === s_partialLoad, - Mux(mmio, io.mmio.resp.fire(), dmem.resp.fire() && (state === s_wait_resp)))) + io.out.valid := Mux(isStore || partialLoad, state === s_partialLoad, dmem.resp.fire() && (state === s_wait_resp)) io.in.ready := (state === s_idle) - val mmioLatch = RegNext(mmio) - val rdata = Mux(mmioLatch, io.mmio.resp.bits.rdata, dmem.resp.bits.rdata) + val rdata = dmem.resp.bits.rdata val rdataLatch = RegNext(rdata) val rdataSel = LookupTree(addrLatch(2, 0), List( "b000".U -> rdataLatch(63, 0), @@ -117,10 +103,10 @@ class LSU extends NOOPModule { )) io.out.bits := Mux(partialLoad, rdataPartialLoad, rdata) - io.isMMIO := mmio && valid + io.isMMIO := AddressSpace.isMMIO(addr) && io.out.valid BoringUtils.addSource(dmem.isRead() && dmem.req.fire(), "perfCntCondMloadInstr") BoringUtils.addSource(BoolStopWatch(dmem.isRead(), dmem.resp.fire()), "perfCntCondMloadStall") BoringUtils.addSource(BoolStopWatch(dmem.isWrite(), dmem.resp.fire()), "perfCntCondMstoreStall") - BoringUtils.addSource(io.mmio.req.fire(), "perfCntCondMmmioInstr") + BoringUtils.addSource(io.isMMIO, "perfCntCondMmmioInstr") } diff --git a/src/test/scala/top/SimMMIO.scala b/src/test/scala/top/SimMMIO.scala index 7ca856f309606d4a269eaf47ce7452bc58e63333..3525bbf536206e12598842d2baf49742a1e2a125 100644 --- a/src/test/scala/top/SimMMIO.scala +++ b/src/test/scala/top/SimMMIO.scala @@ -19,8 +19,8 @@ class SimMMIO extends Module { (0x40800000L, 0x8L) // vga ctrl ) - val xbar = Module(new SimpleBusCrossbar(1, devAddrSpace)) - xbar.io.in(0) <> io.rw + val xbar = Module(new SimpleBusCrossbar1toN(devAddrSpace)) + xbar.io.in <> io.rw val uart = Module(new AXI4UART) val timer = Module(new AXI4Timer(sim = true))