2016-11-27 16:16:37 -08:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
// See LICENSE.Berkeley for license details.
|
2016-11-18 19:01:36 -08:00
|
|
|
|
|
|
|
package rocket
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
import Chisel.ImplicitConversions._
|
2016-11-18 19:11:34 -08:00
|
|
|
import config._
|
2016-11-18 19:01:36 -08:00
|
|
|
import util._
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This module buffers requests made by the SimpleHellaCacheIF in case they
|
|
|
|
* are nacked. Nacked requests must be replayed in order, and no other requests
|
|
|
|
* must be allowed to go through until the replayed requests are successfully
|
|
|
|
* completed.
|
|
|
|
*/
|
|
|
|
class SimpleHellaCacheIFReplayQueue(depth: Int)
|
|
|
|
(implicit val p: Parameters) extends Module
|
|
|
|
with HasL1HellaCacheParameters {
|
|
|
|
val io = new Bundle {
|
|
|
|
val req = Decoupled(new HellaCacheReq).flip
|
|
|
|
val nack = Valid(Bits(width = coreDCacheReqTagBits)).flip
|
|
|
|
val resp = Valid(new HellaCacheResp).flip
|
|
|
|
val replay = Decoupled(new HellaCacheReq)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Registers to store the sent request
|
|
|
|
// When a request is sent the first time,
|
|
|
|
// it is stored in one of the reqs registers
|
|
|
|
// and the corresponding inflight bit is set.
|
|
|
|
// The reqs register will be deallocated once the request is
|
|
|
|
// successfully completed.
|
|
|
|
val inflight = Reg(init = UInt(0, depth))
|
|
|
|
val reqs = Reg(Vec(depth, new HellaCacheReq))
|
|
|
|
|
|
|
|
// The nack queue stores the index of nacked requests (in the reqs vector)
|
|
|
|
// in the order that they were nacked. A request is enqueued onto nackq
|
|
|
|
// when it is newly nacked (i.e. not a nack for a previous replay).
|
|
|
|
// The head of the nack queue will be replayed until it is
|
|
|
|
// successfully completed, at which time the request is dequeued.
|
|
|
|
// No new requests will be made or other replays attempted until the head
|
|
|
|
// of the nackq is successfully completed.
|
|
|
|
val nackq = Module(new Queue(UInt(width = log2Up(depth)), depth))
|
|
|
|
val replaying = Reg(init = Bool(false))
|
|
|
|
|
|
|
|
val next_inflight_onehot = PriorityEncoderOH(~inflight)
|
|
|
|
val next_inflight = OHToUInt(next_inflight_onehot)
|
|
|
|
|
|
|
|
val next_replay = nackq.io.deq.bits
|
|
|
|
val next_replay_onehot = UIntToOH(next_replay)
|
|
|
|
val next_replay_req = reqs(next_replay)
|
|
|
|
|
|
|
|
// Keep sending the head of the nack queue until it succeeds
|
|
|
|
io.replay.valid := nackq.io.deq.valid && !replaying
|
|
|
|
io.replay.bits := next_replay_req
|
|
|
|
// Don't allow new requests if there is are replays waiting
|
|
|
|
// or something being nacked.
|
|
|
|
io.req.ready := !inflight.andR && !nackq.io.deq.valid && !io.nack.valid
|
|
|
|
|
|
|
|
// Match on the tags to determine the index of nacks or responses
|
|
|
|
val nack_onehot = Cat(reqs.map(_.tag === io.nack.bits).reverse) & inflight
|
|
|
|
val resp_onehot = Cat(reqs.map(_.tag === io.resp.bits.tag).reverse) & inflight
|
|
|
|
|
|
|
|
val replay_complete = io.resp.valid && replaying && io.resp.bits.tag === next_replay_req.tag
|
|
|
|
val nack_head = io.nack.valid && nackq.io.deq.valid && io.nack.bits === next_replay_req.tag
|
|
|
|
|
|
|
|
// Enqueue to the nack queue if there is a nack that is not in response to
|
|
|
|
// the previous replay
|
|
|
|
nackq.io.enq.valid := io.nack.valid && !nack_head
|
|
|
|
nackq.io.enq.bits := OHToUInt(nack_onehot)
|
|
|
|
assert(!nackq.io.enq.valid || nackq.io.enq.ready,
|
|
|
|
"SimpleHellaCacheIF: ReplayQueue nack queue overflow")
|
|
|
|
|
|
|
|
// Dequeue from the nack queue if the last replay was successfully completed
|
|
|
|
nackq.io.deq.ready := replay_complete
|
|
|
|
assert(!nackq.io.deq.ready || nackq.io.deq.valid,
|
|
|
|
"SimpleHellaCacheIF: ReplayQueue nack queue underflow")
|
|
|
|
|
|
|
|
// Set inflight bit when a request is made
|
|
|
|
// Clear it when it is successfully completed
|
|
|
|
inflight := (inflight | Mux(io.req.fire(), next_inflight_onehot, UInt(0))) &
|
|
|
|
~Mux(io.resp.valid, resp_onehot, UInt(0))
|
|
|
|
|
|
|
|
when (io.req.fire()) {
|
|
|
|
reqs(next_inflight) := io.req.bits
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only one replay outstanding at a time
|
|
|
|
when (io.replay.fire()) { replaying := Bool(true) }
|
|
|
|
when (nack_head || replay_complete) { replaying := Bool(false) }
|
|
|
|
}
|
|
|
|
|
|
|
|
// exposes a sane decoupled request interface
|
|
|
|
class SimpleHellaCacheIF(implicit p: Parameters) extends Module
|
|
|
|
{
|
|
|
|
val io = new Bundle {
|
|
|
|
val requestor = new HellaCacheIO().flip
|
|
|
|
val cache = new HellaCacheIO
|
|
|
|
}
|
|
|
|
|
|
|
|
val replayq = Module(new SimpleHellaCacheIFReplayQueue(2))
|
|
|
|
val req_arb = Module(new Arbiter(new HellaCacheReq, 2))
|
|
|
|
|
|
|
|
val req_helper = DecoupledHelper(
|
|
|
|
req_arb.io.in(1).ready,
|
|
|
|
replayq.io.req.ready,
|
|
|
|
io.requestor.req.valid)
|
|
|
|
|
|
|
|
req_arb.io.in(0) <> replayq.io.replay
|
|
|
|
req_arb.io.in(1).valid := req_helper.fire(req_arb.io.in(1).ready)
|
|
|
|
req_arb.io.in(1).bits := io.requestor.req.bits
|
|
|
|
io.requestor.req.ready := req_helper.fire(io.requestor.req.valid)
|
|
|
|
replayq.io.req.valid := req_helper.fire(replayq.io.req.ready)
|
|
|
|
replayq.io.req.bits := io.requestor.req.bits
|
|
|
|
|
|
|
|
val s0_req_fire = io.cache.req.fire()
|
|
|
|
val s1_req_fire = Reg(next = s0_req_fire)
|
|
|
|
val s2_req_fire = Reg(next = s1_req_fire)
|
|
|
|
val s1_req_tag = Reg(next = io.cache.req.bits.tag)
|
|
|
|
val s2_req_tag = Reg(next = s1_req_tag)
|
|
|
|
val s2_kill = Reg(next = io.cache.s1_kill)
|
|
|
|
|
|
|
|
io.cache.invalidate_lr := io.requestor.invalidate_lr
|
|
|
|
io.cache.req <> req_arb.io.out
|
|
|
|
io.cache.s1_kill := io.cache.s2_nack
|
|
|
|
io.cache.s1_data := RegEnable(req_arb.io.out.bits.data, s0_req_fire)
|
|
|
|
|
|
|
|
replayq.io.nack.valid := (io.cache.s2_nack || s2_kill) && s2_req_fire
|
|
|
|
replayq.io.nack.bits := s2_req_tag
|
|
|
|
replayq.io.resp := io.cache.resp
|
|
|
|
io.requestor.resp := io.cache.resp
|
|
|
|
|
|
|
|
assert(!Reg(next = io.cache.req.fire()) ||
|
|
|
|
!(io.cache.xcpt.ma.ld || io.cache.xcpt.ma.st ||
|
|
|
|
io.cache.xcpt.pf.ld || io.cache.xcpt.pf.st),
|
|
|
|
"SimpleHellaCacheIF exception")
|
|
|
|
}
|