提交 54453403 编写于 作者: Z Zihao Yu

Merge branch 'icache-mmio' into 'master'

Icache mmio

See merge request projectn/noop!31
......@@ -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
}
......@@ -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
}
}
......@@ -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)
......
......@@ -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")
......
......@@ -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
}
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")
}
......@@ -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))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册