clean up queues
This commit is contained in:
parent
990e3a1b34
commit
a1855b12c2
@ -23,7 +23,7 @@ class ioIPrefetcher extends Bundle() {
|
||||
|
||||
class rocketIPrefetcher extends Component() {
|
||||
val io = new ioIPrefetcher();
|
||||
val pdq = (new queueSimplePF(REFILL_CYCLES)) { Bits(width = MEM_DATA_BITS) };
|
||||
val pdq = (new queue(REFILL_CYCLES, flushable = true)) { Bits(width = MEM_DATA_BITS) };
|
||||
|
||||
val s_invalid :: s_valid :: s_refilling :: s_req_wait :: s_resp_wait :: s_bad_resp_wait :: Nil = Enum(6) { UFix() };
|
||||
val state = Reg(resetVal = s_invalid);
|
||||
@ -43,9 +43,6 @@ class rocketIPrefetcher extends Component() {
|
||||
io.mem.req_tag := !(io.icache.req_val && !hit);
|
||||
io.mem.req_addr := Mux(io.mem.req_tag(0).toBool, prefetch_addr, io.icache.req_addr);
|
||||
|
||||
val pdq_reset = Reg(resetVal = Bool(true));
|
||||
pdq_reset <== demand_miss & ~hit | (state === s_bad_resp_wait);
|
||||
|
||||
val fill_cnt = Reg(resetVal = UFix(0, ceil(log(REFILL_CYCLES)/log(2)).toInt));
|
||||
when (ip_mem_resp_val.toBool) { fill_cnt <== fill_cnt + UFix(1); }
|
||||
val fill_done = (~fill_cnt === UFix(0)) & ip_mem_resp_val;
|
||||
@ -59,7 +56,7 @@ class rocketIPrefetcher extends Component() {
|
||||
io.icache.resp_val := (io.mem.resp_val && !io.mem.resp_tag(0).toBool) || (forward && pdq.io.deq.valid);
|
||||
io.icache.resp_data := Mux(forward, pdq.io.deq.bits, io.mem.resp_data);
|
||||
|
||||
pdq.io.q_reset := pdq_reset;
|
||||
pdq.io.flush := Reg(demand_miss && !hit || (state === s_bad_resp_wait), resetVal = Bool(false))
|
||||
pdq.io.enq.bits := io.mem.resp_data;
|
||||
pdq.io.enq.valid := ip_mem_resp_val.toBool;
|
||||
pdq.io.deq.ready := forward;
|
||||
|
@ -197,8 +197,7 @@ class MSHR(id: Int) extends Component {
|
||||
val next_dirty = dirty || io.req_sec_val && io.req_sec_rdy && !req_load
|
||||
val sec_rdy = io.idx_match && !refilled && (dirty || !requested || req_load)
|
||||
|
||||
val rpq = (new queueSimplePF(NRPQ)) { new RPQEntry() }
|
||||
rpq.io.q_reset := Bool(false)
|
||||
val rpq = (new queue(NRPQ)) { new RPQEntry() }
|
||||
rpq.io.enq.valid := (io.req_pri_val && io.req_pri_rdy || io.req_sec_val && sec_rdy) && req_use_rpq
|
||||
rpq.io.enq.bits.offset := io.req_offset
|
||||
rpq.io.enq.bits.cmd := io.req_cmd
|
||||
@ -419,7 +418,7 @@ class WritebackUnit extends Component {
|
||||
val mem_req_data = Bits(MEM_DATA_BITS, OUTPUT)
|
||||
}
|
||||
|
||||
val wbq = (new queueSimplePF(REFILL_CYCLES)) { Bits(width = MEM_DATA_BITS) }
|
||||
val wbq = (new queue(REFILL_CYCLES)) { Bits(width = MEM_DATA_BITS) }
|
||||
val valid = Reg(resetVal = Bool(false))
|
||||
val cnt = Reg() { UFix(width = log2up(REFILL_CYCLES+1)) }
|
||||
val addr = Reg() { new WritebackReq() }
|
||||
@ -430,7 +429,6 @@ class WritebackUnit extends Component {
|
||||
val block_refill = valid && ((io.refill_req.bits.addr(IDX_BITS-1,0) === addr.idx) || (cnt === UFix(REFILL_CYCLES)))
|
||||
val refill_val = io.refill_req.valid && !block_refill
|
||||
|
||||
wbq.io.q_reset := Bool(false)
|
||||
wbq.io.enq.valid := valid && Reg(io.data_req.valid && io.data_req.ready)
|
||||
wbq.io.enq.bits := io.data_resp
|
||||
wbq.io.deq.ready := io.mem_req.ready && !refill_val && (cnt === UFix(REFILL_CYCLES))
|
||||
|
@ -1,226 +1,45 @@
|
||||
package Top
|
||||
{
|
||||
|
||||
import Chisel._
|
||||
import Node._;
|
||||
import scala.math._;
|
||||
|
||||
class ioQueueCtrl(addr_sz: Int) extends Bundle()
|
||||
class ioQueue[T <: Data](flushable: Boolean)(data: => T) extends Bundle
|
||||
{
|
||||
val q_reset = Bool(INPUT);
|
||||
val enq_val = Bool(INPUT);
|
||||
val enq_rdy = Bool(OUTPUT);
|
||||
val deq_val = Bool(OUTPUT);
|
||||
val deq_rdy = Bool(INPUT);
|
||||
val wen = Bool(OUTPUT);
|
||||
val waddr = UFix(addr_sz, OUTPUT);
|
||||
val raddr = UFix(addr_sz, OUTPUT);
|
||||
}
|
||||
|
||||
class queueCtrl(entries: Int) extends Component
|
||||
{
|
||||
val addr_sz = log2up(entries)
|
||||
override val io = new ioQueueCtrl(addr_sz);
|
||||
|
||||
// Enqueue and dequeue pointers
|
||||
|
||||
val enq_ptr = Reg(width = addr_sz, resetVal = UFix(0, addr_sz));
|
||||
val deq_ptr = Reg(width = addr_sz, resetVal = UFix(0, addr_sz));
|
||||
val full = Reg(width = 1, resetVal = Bool(false));
|
||||
|
||||
io.waddr := enq_ptr;
|
||||
io.raddr := deq_ptr;
|
||||
|
||||
// We enq/deq only when they are both ready and valid
|
||||
|
||||
val do_enq = io.enq_rdy && io.enq_val;
|
||||
val do_deq = io.deq_rdy && io.deq_val;
|
||||
|
||||
// Determine if we have pipeline or flowthrough behaviour and
|
||||
// set the write enable accordingly.
|
||||
|
||||
val empty = ~full && (enq_ptr === deq_ptr);
|
||||
|
||||
io.wen := do_enq;
|
||||
|
||||
// Ready signals are calculated from full register. If pipeline
|
||||
// behavior is enabled, then the enq_rdy signal is also calculated
|
||||
// combinationally from the deq_rdy signal. If flowthrough behavior
|
||||
// is enabled then the deq_val signal is also calculated combinationally
|
||||
// from the enq_val signal.
|
||||
|
||||
io.enq_rdy := ~full;
|
||||
io.deq_val := ~empty;
|
||||
|
||||
// Control logic for the enq/deq pointers and full register
|
||||
|
||||
val deq_ptr_inc = deq_ptr + UFix(1, 1);
|
||||
val enq_ptr_inc = enq_ptr + UFix(1, 1);
|
||||
|
||||
val deq_ptr_next =
|
||||
Mux(do_deq, deq_ptr_inc,
|
||||
deq_ptr);
|
||||
|
||||
val enq_ptr_next =
|
||||
Mux(do_enq, enq_ptr_inc,
|
||||
enq_ptr);
|
||||
|
||||
val full_next =
|
||||
Mux(do_enq && ~do_deq && ( enq_ptr_inc === deq_ptr ), Bool(true),
|
||||
Mux(do_deq && full, Bool(false),
|
||||
full));
|
||||
|
||||
when (io.q_reset) {
|
||||
enq_ptr <== UFix(0, addr_sz);
|
||||
deq_ptr <== UFix(0, addr_sz);
|
||||
full <== Bool(false);
|
||||
}
|
||||
otherwise {
|
||||
enq_ptr <== enq_ptr_next;
|
||||
deq_ptr <== deq_ptr_next;
|
||||
full <== full_next;
|
||||
}
|
||||
}
|
||||
|
||||
class ioQueueSimplePF[T <: Data]()(data: => T) extends Bundle
|
||||
{
|
||||
val q_reset = Bool(INPUT);
|
||||
val flush = if (flushable) Bool(INPUT) else null
|
||||
val enq = new ioDecoupled()(data)
|
||||
val deq = new ioDecoupled()(data).flip
|
||||
}
|
||||
|
||||
class queueSimplePF[T <: Data](entries: Int)(data: => T) extends Component
|
||||
class queue[T <: Data](entries: Int, flushable: Boolean = false)(data: => T) extends Component
|
||||
{
|
||||
override val io = new ioQueueSimplePF()(data);
|
||||
val ctrl = new queueCtrl(entries);
|
||||
ctrl.io.q_reset <> io.q_reset;
|
||||
ctrl.io.deq_val <> io.deq.valid;
|
||||
ctrl.io.enq_rdy <> io.enq.ready;
|
||||
ctrl.io.enq_val <> io.enq.valid;
|
||||
ctrl.io.deq_rdy <> io.deq.ready;
|
||||
val ram = Mem(entries, ctrl.io.wen, ctrl.io.waddr, io.enq.bits);
|
||||
ram.read(ctrl.io.raddr) <> io.deq.bits;
|
||||
}
|
||||
|
||||
// TODO: SHOULD USE INHERITANCE BUT BREAKS INTROSPECTION CODE
|
||||
// class IOqueueCtrlFlow extends IOqueueCtrl
|
||||
class ioQueueCtrlFlow(addr_sz: Int) extends Bundle() /* IOqueueCtrl */
|
||||
{
|
||||
val enq_val = Bool(INPUT);
|
||||
val enq_rdy = Bool(OUTPUT);
|
||||
val deq_val = Bool(OUTPUT);
|
||||
val deq_rdy = Bool(INPUT);
|
||||
val wen = Bool(OUTPUT);
|
||||
val waddr = UFix(addr_sz, OUTPUT);
|
||||
val raddr = UFix(addr_sz, OUTPUT);
|
||||
val flowthru = Bool(OUTPUT);
|
||||
}
|
||||
|
||||
class queueCtrlFlow(entries: Int) extends Component
|
||||
{
|
||||
val addr_sz = log2up(entries)
|
||||
override val io = new ioQueueCtrlFlow(addr_sz);
|
||||
// Enqueue and dequeue pointers
|
||||
|
||||
val enq_ptr = Reg(width = addr_sz, resetVal = UFix(0, addr_sz));
|
||||
val deq_ptr = Reg(width = addr_sz, resetVal = UFix(0, addr_sz));
|
||||
val full = Reg(width = 1, resetVal = Bool(false));
|
||||
|
||||
io.waddr := enq_ptr;
|
||||
io.raddr := deq_ptr;
|
||||
|
||||
// We enq/deq only when they are both ready and valid
|
||||
|
||||
val do_enq = io.enq_rdy && io.enq_val;
|
||||
val do_deq = io.deq_rdy && io.deq_val;
|
||||
|
||||
// Determine if we have pipeline or flowthrough behaviour and
|
||||
// set the write enable accordingly.
|
||||
|
||||
val empty = ~full && (enq_ptr === deq_ptr);
|
||||
val do_flowthru = empty && do_enq && do_deq;
|
||||
io.flowthru := do_flowthru;
|
||||
|
||||
io.wen := do_enq && ~do_flowthru;
|
||||
|
||||
// Ready signals are calculated from full register. If pipeline
|
||||
// behavior is enabled, then the enq_rdy signal is also calculated
|
||||
// combinationally from the deq_rdy signal. If flowthrough behavior
|
||||
// is enabled then the deq_val signal is also calculated combinationally
|
||||
// from the enq_val signal.
|
||||
|
||||
io.enq_rdy := ~full;
|
||||
io.deq_val := ~empty || ( empty && io.enq_val );
|
||||
|
||||
// Control logic for the enq/deq pointers and full register
|
||||
|
||||
val deq_ptr_inc = deq_ptr + UFix(1, 1);
|
||||
val enq_ptr_inc = enq_ptr + UFix(1, 1);
|
||||
|
||||
val deq_ptr_next =
|
||||
Mux(do_deq && ~do_flowthru, deq_ptr_inc,
|
||||
deq_ptr);
|
||||
|
||||
val enq_ptr_next =
|
||||
Mux(do_enq && ~do_flowthru, enq_ptr_inc,
|
||||
enq_ptr);
|
||||
|
||||
val full_next =
|
||||
Mux(do_enq && ~do_deq && ( enq_ptr_inc === deq_ptr ), Bool(true),
|
||||
Mux(do_deq && full, Bool(false),
|
||||
full));
|
||||
|
||||
enq_ptr <== enq_ptr_next;
|
||||
deq_ptr <== deq_ptr_next;
|
||||
full <== full_next;
|
||||
}
|
||||
|
||||
class ioQueueDpathFlow[T <: Data](addr_sz: Int)(data: => T) extends Bundle()
|
||||
{
|
||||
val wen = Bool(INPUT);
|
||||
val flowthru = Bool(INPUT);
|
||||
val deq_bits = data.asOutput;
|
||||
val enq_bits = data.asInput;
|
||||
val waddr = UFix(addr_sz, INPUT);
|
||||
val raddr = UFix(addr_sz, INPUT);
|
||||
}
|
||||
|
||||
class queueDpathFlow[T <: Data](entries: Int)(data: => T) extends Component
|
||||
{
|
||||
val addr_sz = log2up(entries)
|
||||
override val io = new ioQueueDpathFlow(addr_sz)(data);
|
||||
val ram = Mem(entries, io.wen, io.waddr, io.enq_bits);
|
||||
val rout = ram(io.raddr);
|
||||
Mux(io.flowthru, io.enq_bits, rout) <> io.deq_bits;
|
||||
}
|
||||
|
||||
class ioQueueFlowPF[T <: Data](data: => T) extends Bundle()
|
||||
{
|
||||
val enq_val = Bool(INPUT);
|
||||
val enq_rdy = Bool(OUTPUT);
|
||||
val enq_bits = data.asInput;
|
||||
val deq_val = Bool(OUTPUT);
|
||||
val deq_rdy = Bool(INPUT);
|
||||
val deq_bits = data.asOutput;
|
||||
}
|
||||
|
||||
class queueFlowPF[T <: Data](entries: Int)(data: => T) extends Component
|
||||
{
|
||||
override val io = new ioQueueFlowPF(data);
|
||||
val ctrl = new queueCtrlFlow(entries);
|
||||
val dpath = new queueDpathFlow(entries)(data);
|
||||
|
||||
ctrl.io.deq_rdy <> io.deq_rdy;
|
||||
ctrl.io.wen <> dpath.io.wen;
|
||||
ctrl.io.raddr <> dpath.io.raddr;
|
||||
ctrl.io.waddr <> dpath.io.waddr;
|
||||
ctrl.io.flowthru <> dpath.io.flowthru;
|
||||
ctrl.io.enq_val <> io.enq_val;
|
||||
dpath.io.enq_bits <> io.enq_bits;
|
||||
|
||||
ctrl.io.deq_val <> io.deq_val;
|
||||
ctrl.io.enq_rdy <> io.enq_rdy;
|
||||
dpath.io.deq_bits <> io.deq_bits;
|
||||
}
|
||||
|
||||
val io = new ioQueue(flushable)(data)
|
||||
|
||||
val enq_ptr = Reg(resetVal = UFix(0, log2up(entries)))
|
||||
val deq_ptr = Reg(resetVal = UFix(0, log2up(entries)))
|
||||
val maybe_full = Reg(resetVal = Bool(false))
|
||||
|
||||
io.deq.valid := maybe_full || enq_ptr != deq_ptr
|
||||
io.enq.ready := !maybe_full || enq_ptr != deq_ptr
|
||||
|
||||
val do_enq = io.enq.ready && io.enq.valid
|
||||
val do_deq = io.deq.ready && io.deq.valid
|
||||
|
||||
if (flushable) {
|
||||
when (io.flush) {
|
||||
deq_ptr <== UFix(0)
|
||||
enq_ptr <== UFix(0)
|
||||
maybe_full <== Bool(false)
|
||||
}
|
||||
}
|
||||
when (do_deq) {
|
||||
deq_ptr <== deq_ptr + UFix(1)
|
||||
}
|
||||
when (do_enq) {
|
||||
enq_ptr <== enq_ptr + UFix(1)
|
||||
}
|
||||
when (do_enq != do_deq) {
|
||||
maybe_full <== do_enq
|
||||
}
|
||||
|
||||
Mem(entries, do_enq, enq_ptr, io.enq.bits).read(deq_ptr) <> io.deq.bits
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user