Reputation: 313
I want to code with for-loop for redundant part.
Coding.
//Priority Encoder
class P_Encoder(NumInputs: UInt) extends Module {
val io = new Bundle {
val Req[NumInputs] = Bool(INPUT) //Requests
val Rls[NumInputs] = Bool(INPUT) //Releases
val Grant[NumInputs] = UInt(OUTPUT(log(NumInputs))) //Grants
}
val cnt = 0
for (i<-0 to NumInputs-1) {
when (io.Req[i] & !io.Rls[i]) {
cnt := cnt + 1.W
io.Grant[i] = cnt
}
else {
io.Grant[i] = 0.W
}
}
}
I want to code using "for-loop" to code redundant part.
Upvotes: 2
Views: 1144
Reputation: 4051
I agree with everything @jkoenig says.
In an another example assuming Jack's IO structure, there are times I like
using foldLeft
combined with when
/elsewhen
io.rel.zip(io.req).zipWithIndex.foldLeft(when(false.B){}) { case (lastWhen,((req, rel), index)) =>
lastWhen.elsewhen(req && !rel) {
io.grant := index.U
}
} otherwise {
io.grant := 0.U
}
when
and elsewhen
both return a WhenClause
which can be used with foldLeft to keep adding clauses.
Upvotes: 2
Reputation: 6064
There are a few minor issues with this code:
val req = Input(Vec(numInputs, Bool()))
(assuming import chisel3._
, but this should also work in Chisel._
for Chisel 3.2)if
and else
are used for static parameterization (ie. at hardware elaboration time) while when
and .otherwise
are used for dynamic logic (eg. actual muxes)UInt
is for hardware types, if you have a static parameter (like numInputs
), use a Scala Int
Other than the minor syntactical stuff, the trickiest part of getting this code right is understanding the difference between Scala constructs that are only run at elaboration time (ie. when the Scala program generates the hardware), vs. what actually shows up in the hardware. I would suggest reading this thread from the chisel-users mailing list for some more context about some of this stuff: https://groups.google.com/d/msg/chisel-users/gRoNnH-Y5hE/ynDCtmNPCAAJ
I'm a little confused as to what value io.grant
is supposed to get, but I'm assuming it should be the index of the highest priority io.req
.
Here's an untested version of your code that I think should work and do what you want:
//Priority Encoder
class P_Encoder(numInputs: Int) extends Module {
// We wrap ports in IO
val io = IO(new Bundle {
val req = Input(Vec(numInputs, Bool()))
val rls = Input(Vec(numInputs, Bool()))
val grant = Output(UInt(log2Up(numInputs).W))
})
io.grant := 0.U // default grant value
// Due to Chisel last connect semantics, the last connection wins
// Thus the highest index will have priority
for (i <- 0 to numInputs - 1) {
when (io.req(i) && !io.rls(i)) {
io.grant := i.U
}
}
}
This code is tricky because it's mixing an elaboration time for
loop with hardware when
s and connections, I'm going to manually unroll this loop to illustrate what it's doing:
io.grant := 0.U
when (io.req(0) && !io.rls(0)) {
io.grant := 0.U
}
when (io.req(1) && !io.rls(1)) {
io.grant := 1.U
}
when (io.req(2) && !io.rls(2)) {
io.grant := 2.U
}
...
Alternatively, we can just reuse the built-in PriorityEncoder utility if we want
import chisel3.util.PriorityEncoder
val enables = io.req.zip(io.rls).map { case (x, y) => x && !y }
// PriorityEncoder gives priority to *lowest* order bit
io.grant := PriorityEncoder(enables)
Upvotes: 2