提交 9080bd71 编写于 作者: A Allen

WritebackUnit: use parallel state machine structure.

Also: blocked same block miss req and same block reqs.

This satisfies TL spec page 68:
Release:
master should not issue a Release if there is a pending Grant on the block.
Once the Release is issued, the master should not issue ProbeAcks, Acquires,or further Releases
until it receives a ReleaseAck from the slave acknowledging completion of the writeback.
上级 7a427828
......@@ -151,7 +151,7 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame
val mainPipe = Module(new MainPipe)
val missQueue = Module(new MissQueue(edge))
val probeQueue = Module(new ProbeQueue(edge))
val wb = Module(new WritebackUnit(edge))
val wb = Module(new WritebackQueue(edge))
//----------------------------------------
......@@ -244,7 +244,10 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame
missReqArb.io.in(MainPipeMissReqPort) <> mainPipe.io.miss_req
for (w <- 0 until LoadPipelineWidth) { missReqArb.io.in(w + 1) <> ldu(w).io.miss_req }
missQueue.io.req <> missReqArb.io.out
wb.io.miss_req.valid := missReqArb.io.out.valid
wb.io.miss_req.bits := missReqArb.io.out.bits.addr
block_decoupled(missReqArb.io.out, missQueue.io.req, wb.io.block_miss_req)
// refill to load queue
io.lsu.lsq <> missQueue.io.refill
......@@ -282,9 +285,7 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame
//----------------------------------------
// wb
// add a queue between MainPipe and WritebackUnit to reduce MainPipe stalls due to WritebackUnit busy
val wb_queue = Module(new Queue(new WritebackReq, cfg.nReleaseEntries, flow = true))
wb_queue.io.enq <> mainPipe.io.wb_req
wb.io.req <> wb_queue.io.deq
wb.io.req <> mainPipe.io.wb_req
bus.c <> wb.io.mem_release
// connect bus d
......@@ -318,4 +319,10 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame
io.prefetch.valid := missQueue.io.req.fire()
io.prefetch.bits := missQueue.io.req.bits
def block_decoupled[T <: Data](source: DecoupledIO[T], sink: DecoupledIO[T], block_signal: Bool) = {
sink.valid := source.valid && !block_signal
source.ready := sink.ready && !block_signal
sink.bits := source.bits
}
}
......@@ -3,7 +3,7 @@ package xiangshan.cache
import chisel3._
import chisel3.util._
import utils.{XSDebug, HasTLDump}
import freechips.rocketchip.tilelink.{TLBundleC, TLBundleD, TLEdgeOut, TLPermissions}
import freechips.rocketchip.tilelink.{TLBundleC, TLBundleD, TLEdgeOut, TLPermissions, TLArbiter}
class WritebackReq extends DCacheBundle {
val addr = UInt(PAddrBits.W)
......@@ -18,44 +18,55 @@ class WritebackReq extends DCacheBundle {
}
}
class WritebackUnit(edge: TLEdgeOut) extends DCacheModule with HasTLDump
class WritebackEntry(edge: TLEdgeOut) extends DCacheModule with HasTLDump
{
val io = IO(new Bundle {
val id = Input(UInt())
val req = Flipped(DecoupledIO(new WritebackReq))
val mem_release = DecoupledIO(new TLBundleC(edge.bundle))
val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
val block_addr = Output(Valid(UInt()))
})
val s_invalid :: s_release_req :: s_release_resp :: Nil = Enum(3)
val state = RegInit(s_invalid)
// internal regs
// remaining beats
val remain = RegInit(0.U(refillCycles.W))
val remain_set = WireInit(0.U(refillCycles.W))
val remain_clr = WireInit(0.U(refillCycles.W))
remain := (remain | remain_set) & ~remain_clr
// used source id
// source id 0 is reserved for ProbeAck[Data]
val used = RegInit(0.U((cfg.nReleaseEntries - 1).W))
val used_set = WireInit(0.U((cfg.nReleaseEntries - 1).W))
val used_clr = WireInit(0.U((cfg.nReleaseEntries - 1).W))
used := (used | used_set) & ~used_clr
val busy = remain.orR
val all_used = used.andR
val req_reg = Reg(new WritebackReq)
val req = Mux(busy, req_reg, io.req.bits)
// assign default signals to output signals
io.req.ready := false.B
io.mem_release.valid := false.B
io.mem_release.bits := DontCare
io.mem_grant.ready := false.B
io.block_addr.valid := state =/= s_invalid
io.block_addr.bits := req.addr
when (state =/= s_invalid) {
XSDebug("WritebackEntry: %d state: %d block_addr: %x\n", io.id, state, io.block_addr.bits)
}
// --------------------------------------------------------------------------------
// s_invalid: receive requests
// new req entering
// source to use for this transaction
val source = Reg(UInt())
io.req.ready := !busy && (!io.req.bits.voluntary || !all_used)
io.req.ready := state === s_invalid
when (io.req.fire()) {
assert (remain === 0.U)
remain_set := Mux(io.req.bits.hasData, ~0.U(refillCycles.W), 1.U(refillCycles.W))
used_set := Mux(io.req.bits.voluntary, PriorityEncoderOH(~used), 0.U)
// source 0 is reserved for ProbeAck[Data]
source := Mux(io.req.bits.voluntary, PriorityEncoder(~used) + 1.U, 0.U)
req_reg := io.req.bits
state := s_release_req
}
// --------------------------------------------------------------------------------
......@@ -69,14 +80,14 @@ class WritebackUnit(edge: TLEdgeOut) extends DCacheModule with HasTLDump
}
val probeResponse = edge.ProbeAck(
fromSource = source,
fromSource = io.id,
toAddress = req.addr,
lgSize = log2Ceil(cfg.blockBytes).U,
reportPermissions = req.param
)
val probeResponseData = edge.ProbeAck(
fromSource = source,
fromSource = io.id,
toAddress = req.addr,
lgSize = log2Ceil(cfg.blockBytes).U,
reportPermissions = req.param,
......@@ -84,14 +95,14 @@ class WritebackUnit(edge: TLEdgeOut) extends DCacheModule with HasTLDump
)
val voluntaryRelease = edge.Release(
fromSource = source,
fromSource = io.id,
toAddress = req.addr,
lgSize = log2Ceil(cfg.blockBytes).U,
shrinkPermissions = req.param
)._2
val voluntaryReleaseData = edge.Release(
fromSource = source,
fromSource = io.id,
toAddress = req.addr,
lgSize = log2Ceil(cfg.blockBytes).U,
shrinkPermissions = req.param,
......@@ -105,15 +116,73 @@ class WritebackUnit(edge: TLEdgeOut) extends DCacheModule with HasTLDump
when (io.mem_release.fire()) { remain_clr := PriorityEncoderOH(remain) }
val (_, _, release_done, _) = edge.count(io.mem_release)
when (state === s_release_req && release_done) {
state := Mux(req.voluntary, s_release_resp, s_invalid)
}
// --------------------------------------------------------------------------------
// receive ReleaseAck for Releases
// we are alway ready
// remember to assert any invalid grant
io.mem_grant.ready := used(io.mem_grant.bits.source - 1.U)
when (io.mem_grant.fire()) {
used_clr := UIntToOH(io.mem_grant.bits.source - 1.U)
when (state === s_release_resp) {
io.mem_grant.ready := true.B
when (io.mem_grant.fire()) {
state := s_invalid
}
}
}
class WritebackQueue(edge: TLEdgeOut) extends DCacheModule with HasTLDump
{
val io = IO(new Bundle {
val req = Flipped(DecoupledIO(new WritebackReq))
val mem_release = DecoupledIO(new TLBundleC(edge.bundle))
val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
val miss_req = Flipped(Valid(UInt()))
val block_miss_req = Output(Bool())
})
// allocate a free entry for incoming request
val primary_ready = Wire(Vec(cfg.nReleaseEntries, Bool()))
val allocate = primary_ready.asUInt.orR
val alloc_idx = PriorityEncoder(primary_ready)
val req = io.req
val block_conflict = Wire(Bool())
req.ready := allocate && !block_conflict
// assign default values to output signals
io.mem_release.valid := false.B
io.mem_release.bits := DontCare
io.mem_grant.ready := false.B
val entries = (0 until cfg.nReleaseEntries) map { i =>
val entry = Module(new WritebackEntry(edge))
entry.io.id := i.U
// entry req
entry.io.req.valid := (i.U === alloc_idx) && allocate && req.valid && !block_conflict
primary_ready(i) := entry.io.req.ready
entry.io.req.bits := req.bits
entry.io.mem_grant.valid := (i.U === io.mem_grant.bits.source) && io.mem_grant.valid
entry.io.mem_grant.bits := io.mem_grant.bits
when (i.U === io.mem_grant.bits.source) {
io.mem_grant.ready := entry.io.mem_grant.ready
}
entry
}
block_conflict := VecInit(entries.map(e => e.io.block_addr.valid && e.io.block_addr.bits === io.req.bits.addr)).asUInt.orR
val miss_req_conflict = VecInit(entries.map(e => e.io.block_addr.valid && e.io.block_addr.bits === io.miss_req.bits)).asUInt.orR
io.block_miss_req := io.miss_req.valid && miss_req_conflict
TLArbiter.robin(edge, io.mem_release, entries.map(_.io.mem_release):_*)
// sanity check
// print all input/output requests for debug purpose
// print req
when (io.req.fire()) {
......@@ -123,4 +192,16 @@ class WritebackUnit(edge: TLEdgeOut) extends DCacheModule with HasTLDump
when (io.mem_release.fire()) {
io.mem_release.bits.dump
}
when (io.mem_grant.fire()) {
io.mem_grant.bits.dump
}
when (io.miss_req.valid) {
XSDebug("miss_req: addr: %x\n", io.miss_req.bits)
}
when (io.block_miss_req) {
XSDebug("block_miss_req\n")
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册