Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AXI4 Deinterleaver: update to chisel3 to get inferred reset #2479

Merged
merged 5 commits into from
May 29, 2020
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions src/main/scala/amba/axi4/Deinterleaver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

package freechips.rocketchip.amba.axi4

import Chisel._
import chisel3.util.IrrevocableIO
import chisel3._
import chisel3.util.{Cat, IrrevocableIO, isPow2, log2Ceil,
log2Up, OHToUInt, Queue, QueueIO, UIntToOH}
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.util.{leftOR, rightOR, UIntToOH1, OH1ToOH}
Expand All @@ -27,28 +28,39 @@ class AXI4Deinterleaver(maxReadBytes: Int)(implicit p: Parameters) extends LazyM
val beats = (maxReadBytes+beatBytes-1) / beatBytes

// This adapter leaves the control + write paths completely untouched
out.ar <> in.ar
out.aw <> in.aw
out.w <> in.w
in.b <> out.b
out.ar :<> in.ar
out.aw :<> in.aw
out.w :<> in.w
in.b :<> out.b

if (beats <= 1) {
// Nothing to do if only single-beat R
in.r <> out.r
in.r :<> out.r
} else {
// Queues to buffer R responses
val qs = Seq.tabulate(endId) { i =>
val depth = edgeOut.master.masters.find(_.id.contains(i)).flatMap(_.maxFlight).getOrElse(0)
if (depth > 0) {
Module(new Queue(out.r.bits.cloneType, beats)).io
val q = Module(new Queue(out.r.bits.cloneType, beats))
q.suggestName(s"queue_${i}")
q.io
} else {
Wire(new QueueIO(out.r.bits.cloneType, beats))
// These are unused IDs and should be never used.
// But, to satisfy type checks we must produce a Wire of the
// correct type.
val q = Wire(new QueueIO(out.r.bits.cloneType, beats))
q.suggestName(s"queue_wire_${i}")
assert(!q.enq.valid, s"ID ${i} should not be used")
// These could just be marked DontCare
q.deq :<> q.enq
mwachs5 marked this conversation as resolved.
Show resolved Hide resolved
q.count := 0.U
q
mwachs5 marked this conversation as resolved.
Show resolved Hide resolved
}
}

// Which ID is being enqueued and dequeued?
val locked = RegInit(Bool(false))
val deq_id = Reg(UInt(width=log2Up(endId)))
val locked = RegInit(false.B)
val deq_id = Reg(UInt(log2Up(endId).W))
val enq_id = out.r.bits.id
val deq_OH = UIntToOH(deq_id, endId)
val enq_OH = UIntToOH(enq_id, endId)
Expand All @@ -57,18 +69,18 @@ class AXI4Deinterleaver(maxReadBytes: Int)(implicit p: Parameters) extends LazyM
val pending = Cat(Seq.tabulate(endId) { i =>
val depth = edgeOut.master.masters.find(_.id.contains(i)).flatMap(_.maxFlight).getOrElse(0)
if (depth == 0) {
Bool(false)
false.B
} else {
val count = RegInit(UInt(0, width=log2Ceil(beats+1)))
val next = Wire(count)
val count = RegInit(0.U(log2Ceil(beats+1).W))
val next = Wire(chiselTypeOf(count))
val inc = enq_OH(i) && out.r.fire() && out.r.bits.last
val dec = deq_OH(i) && in.r.fire() && in.r.bits.last
next := count + inc.asUInt - dec.asUInt
count := next
// Bounds checking
assert (!dec || count =/= UInt(0))
assert (!inc || count =/= UInt(beats))
next =/= UInt(0)
assert (!dec || count =/= 0.U)
assert (!inc || count =/= beats.U)
next =/= 0.U
}
}.reverse)

Expand All @@ -81,14 +93,19 @@ class AXI4Deinterleaver(maxReadBytes: Int)(implicit p: Parameters) extends LazyM

// Transmit the selected burst to inner
in.r.valid := locked
in.r.bits := Vec(qs.map(_.deq.bits))(deq_id)
(deq_OH.asBools zip qs) foreach { case (s, q) =>
val deq_bits = VecInit(qs.map(_.deq.bits))
in.r.bits := deq_bits(deq_id)
mwachs5 marked this conversation as resolved.
Show resolved Hide resolved
val deq_OH_bools = deq_OH.asBools
require(deq_OH_bools.size == qs.size, s"deq_OH.size != qs.size (${deq_OH_bools.size} vs ${qs.size})")
(deq_OH_bools zip qs) foreach { case (s, q) =>
q.deq.ready := s && in.r.fire()
}

require(enq_OH_bools.size == qs.size, s"enq_OH.size != qs.size (${enq_OH_bools.size} vs ${qs.size})")
mwachs5 marked this conversation as resolved.
Show resolved Hide resolved
// Feed response into matching Q
out.r.ready := Vec(qs.map(_.enq.ready))(enq_id)
(enq_OH.asBools zip qs) foreach { case (s, q) =>
val enq_readys = VecInit(qs.map(_.enq.ready))
out.r.ready := enq_readys(enq_id)
mwachs5 marked this conversation as resolved.
Show resolved Hide resolved
(enq_OH_bools zip qs) foreach { case (s, q) =>
q.enq.valid := s && out.r.valid
q.enq.bits := out.r.bits
}
Expand Down