Chaining Scalaz Lens set operations - scalaz

I'm trying to learn scalaz7 lenses. Is there a better way to chain set operations?
case class Outer(left: Inner, right: Inner)
case class Inner(top: Int, bottom: Int)
val left = Lens.lensu[Outer, Inner](
(o,v) => o.copy(left = v),
_.left
)
val right = Lens.lensu[Outer, Inner](
(o,v) => o.copy(right = v),
_.right
)
val top = Lens.lensu[Inner, Int](
(o,v) => o.copy(top = v),
_.top
)
val leftTop = left >=> top
val rightTop = right >=> top
val outer0 = Outer(Inner(10,20), Inner(30, 40))
val outer1 = rightTop.set(leftTop.set(outer0, 11), 33)
Update:
I have a feeling that the answer might be to use the state monad, though I barely understand why this seems to work. Would be interested to know if there is a neater way.
val modifier = for{
_ <- leftTop := 11
_ <- rightTop := 33
} yield Unit
modifier(outer0)._1 // = Outer(Inner(11,20),Inner(33,40))

You can simplify the State monad version somewhat:
(leftTop := 11) >> (rightTop := 33) exec outer0
Or, if you prefer:
val modifier = (leftTop := 11) >> (rightTop := 33)
modifier.exec(outer0)
Your original State version looks a little weird since the <- in a for statement is just syntax sugar for calls to .flatMap. Simplifying things a bit, the result of leftTop := 11 has a type like State[Outer, Outer, Int], which is roughly equivalent to a function with type Outer => (Outer, Int). State keeps track of the Outer part of the result and passes the Int part to .flatMap. Since you don't care about the Int result, you assign it to _ and ignore it.
The >> does the same thing, it's a .flatMap that ignores it's argument and is the same as writing:
(leftTop := 11) flatMap (_ => rightTop := 33)
The result of this is a State computation, which has a helper function .exec that runs the computation with an initial state (outer0) and returns the final state (discarding any result).
If you want to avoid using State, you'll pretty much have to do it the way you started out. The whole point of State is to pass intermediate results between steps without explicitly mentioning them.

Related

suggestName for IO(Vec(...))

I have a module like so...
class ApbSplitter (clients : List[ApbRange]) extends MultiIOModule {
val nApb = clients.length
val apb = IO(Vec(nApb, new ApbChannel()))
val apb_m = IO(Flipped(new ApbChannel))
...
What I'd like to do is suggestName to each element of the Vec so that instead of prefixed as apb_0_ apb_1_ etc... it's whatever I provide for each element.
I can apb.suggestName but that only affects the leading prefix and the array indices remain. Doing apb(idx).suggestName("blah") compiles but has no effect.
Any way to make this happen?
Got this to work by eliminating the Vec and creating a list of IO
case class ApbRange (name: String, loAddr : Int, hiAddr : Int)
class ApbSplitter (clients : List[ApbRange]) extends MultiIOModule {
val apb = clients.map({x => IO(new ApbChannel).suggestName(x.name)})
val apb_m = IO(Flipped(new ApbChannel))
...
Not sure if this is canonical but seems to do the trick just fine.
Answering this with Brian's other post and comment on his own answer on this post in mind. This is going to be a long answer because it touches on a couple of warts in the Chisel API that are being improved but are certainly relevant in the current version (v3.4.3 as of 12 Aug 2021).
Brian's answer is correct that if you want to name the individual fields you need to use a Seq and not a Vec. The reason for this is that, from Chisel's perspective, an IO of type Vec is a single port with an aggregate type, whereas the Seq is just a sequence of unrelated ports. The Seq is a Scala construct (whereas Vec comes from Chisel), so Chisel itself doesn't know anything about the relationship between the ports in the Seq.
The problem then, is that you need a Vec to do dynamic indexing. You can use VecInit to create a dynamically indexable Wire from your Seq whenever you need to do dynamic indexing:
For example:
class MyModule(names: Seq[String]) extends RawModule {
val enq = names.map(n => IO(Flipped(Decoupled(UInt(8.W)))).suggestName(n))
val idx = IO(Input(UInt(log2Ceil(names.size).W)))
val deq = IO(Decoupled(UInt(8.W)))
// enqWire connects all fields of enq
val enqWire = VecInit(enq)
// Need to make sure backpressure is always driven
enqWire.foreach(_.ready := false.B)
deq <> enqWire(idx)
}
This will work so long as deq is itself a port. It will not work if deq were a Wire because <> is a commutative operator and is thus ambiguous when connecting 2 bidirectional wires. For a longer explanation, see this PR comment.
If deq needs to be a Wire for some reason, you could use a helper module that does have Vecs as ports:
For example:
class InnerHelper(n: Int) extends RawModule {
val enq = IO(Flipped(Vec(n, Decoupled(UInt(8.W)))))
val idx = IO(Input(UInt(log2Ceil(n).W)))
val jdx = IO(Input(UInt(log2Ceil(n).W)))
val deq = IO(Vec(n, Decoupled(UInt(8.W))))
// backpressure defaults
enq.foreach(_.ready := false.B)
deq.foreach { x =>
x.valid := false.B
x.bits := DontCare
}
deq(jdx) <> enq(idx)
}
class MyModule(names: Seq[String]) extends RawModule {
val enq = names.map(n => IO(Flipped(Decoupled(UInt(8.W)))).suggestName(n))
val idx = IO(Input(UInt(log2Ceil(names.size).W)))
val jdx = IO(Input(UInt(log2Ceil(names.size).W)))
val deq = names.map(n => IO(Decoupled(UInt(8.W))).suggestName(s"${n}_out"))
val helper = Module(new InnerHelper(names.size))
helper.enq <> enq
helper.idx := idx
helper.jdx := jdx
helper.deq <> deq
}
It's a bit of a pain, but it at least resolves the ambiguity. There are other utilities we could build--for example, instead of a custom InnerHelper for each case, we could make a utility method that creates a module so that the returned value of dynamically indexing a Seq is a port of a new submodule, but it's a bit tricky.
The good news is that a better way is coming--DataView in Chisel 3.5 should make it possible to view a Seq as a Vec (rather than having to use VecInit which creates a Wire) which makes it easier to avoid this Wire <> connect ambiguity issue. I also hope to either "fix" <> for Wires or perhaps provide a new operator that is not commutative :<>, but that is not yet being worked on.
I am guessing your new apbChannel has a bunch of Input Output signals or wires. So instead of apb(idx).suggestName if your apbChannel has a (say) val ip = Input(Bool()) you can do apb(idx).ip.suggestName("blah")

How to initialize a Reg of Bundle in Chisel?

I declared a Bundle for my specific data :
class RValue (val cSize: Int = 16) extends Bundle {
val rvalue = Output(UInt(cSize.W))
val er = Output(UInt((cSize/2).W))
val part = Output(Bool()) /* set if value is partial */
}
And I want to use it as a register in my module :
val valueReg = Reg(new RValue(cSize))
//...
valueReg.rvalue := 0.U
valueReg.er := 0.U
That works well. But I want to initialize it at Register declaration with RegInit(). Is it Possible ?
val valueReg = RegInit(new RValue(cSize), ?? ) ??
Chick's answer of using Bundle Literals is the cool new way and is nice because you can give a Bundle arbitrary values in a single expression.
If you just want to zero-out the register at reset type, you could always cast from a literal zero to the Bundle:
val valueReg = RegInit(0.U.asTypeOf(new RValue(cSize))
You can do similar things with any literal if you want, but I wouldn't recommend it unless you're zeroing out or setting everything to 1s.
For setting each field to some other value, I think Chick's way is better, but the normal style you'll see in older code is something like:
val valueReg = RegInit({
val bundle = Wire(new RValue(cSize))
bundle.rvalue := 1.U
bundle.er := 2.U
bundle.part := 3.U
bundle
})
In Scala, you can put { } anywhere an expression is needed and the last expression in the Block will be the return value. Thus we can create a Wire with the values we want to reset the register to and then pass that Bundle as the initialization value. It would be equivalent to write:
val valueRegInit = Wire(new RValue(cSize))
valueRegInit.rvalue := 1.U
valueRegInit.er := 2.U
valueRegInit.part := 3.U
val valueReg = RegInit(valueRegInit)
I hope this helps!
BundleLiterals are the new way to do this. First
import chisel3.experimental.BundleLiterals._
Then
val valueReg = RegInit((new RValue(cSize)).Lit(_.rvalue -> 1.U, _.er -> 2.U, _.part -> true.B)
It's possible there will be some problem with having declared the fields in the Bundle with the OutputBinding. I would probably leave that off and just wrap with the output when necessary, e.g.
val rValueOut = IO(Output(new RValue(csize)))

using the right side of the disjoint union properly

what's the best way to turn a Right[List] into a List
I will parse a Json String like so
val parsed_states = io.circe.parser.decode[List[List[String]]](source)
And that will create an value equivalent to this
val example_data = Right(List(List("NAME", "state"), List("Alabama", "01"), List("Alaska", "02"), List("Arizona", "04")))
I'm trying to grok Right, Left, Either and implement the best way to get a list of StateName, StateValue pairs out of that list above.
I see that any of these ways will give me what I need (while dropping the header):
val parsed_states = example_data.toSeq(0).tail
val parsed_states = example_data.getOrElse(<ProbUseNoneHere>).iterator.to(Seq).tail
val parsed_states = example_data.getOrElse(<ProbUseNoneHere>).asInstanceOf[Seq[List[String]]].tail
I guess I'm wondering if I should do it one way or another based on the possible behavior upstream coming out of io.circe.parser.decode or am I overthinking this. I'm new to the Right, Left, Either paradigm and not finding terribly many helpful examples.
in reply to #slouc
trying to connect the dots from your answer as they apply to this use case. so something like this?
def blackBox: String => Either[Exception, List[List[String]]] = (url:String) => {
if (url == "passalong") {
Right(List(List("NAME", "state"), List("Alabama", "01"), List("Alaska", "02"), List("Arizona", "04")))
}
else Left(new Exception(s"This didn't work bc blackbox didn't parse ${url}"))
}
//val seed = "passalong"
val seed = "notgonnawork"
val xx: Either[Exception, List[List[String]]] = blackBox(seed)
def ff(i: List[List[String]]) = i.tail
val yy = xx.map(ff)
val zz = xx.fold(
_ => throw new Exception("<need info here>"),
i => i.tail)
The trick is in not getting state name / state value pairs out of the Either. They should be kept inside. If you want to, you can transform the Either type into something else (e.g. an Option by discarding whatever you possibly had on the left side), but don't destroy the effect. Something should be there to show that decoding could have failed; it can be an Either, Option, Try, etc. Eventually you will process left and right case accordingly, but this should happen as late as possible.
Let's take the following trivial example:
val x: Either[String, Int] = Right(42)
def f(i: Int) = i + 1
You might argue that you need to get the 42 out of the Right so that you can pass it to f. But that's not correct. Let's rewrite the example:
val x: Either[String, Int] = someFunction()
Now what? We have no idea whether we have a Left or a Right in value x, so we can't "get it out". Which integer would you obtain in case it's a Left? (if you really do have an integer value to use in that case, that's fair enough, and I will address that use case a bit later)
What you need to do instead is keep the effect (in this case Either), and you need to continue working in the context of that effect. It's there to show that there was a point in your program (in this case someFunction(), or decoding in your original question) that might have gone wrong.
So if you want to apply f to your potential integer, you need to map the effect with it (we can do that because Either is a functor, but that's a detail which probably exceeds the scope of this answer):
val x: Either[String, Int] = Right(42)
def f(i: Int) = i + 1
val y = x.map(value => f(value)) // Right(43)
val y = x.map(f) // shorter, point-free notation
and
val x: Either[String, Int] = someFunction()
def f(i: Int) = i + 1
// either a Left with some String, or a Right with some integer increased by 1
val y = x.map(f)
Then, at the very end of the chain of computations, you can handle the Left and Right cases; for example, if you were processing an HTTP request, then in case of Left you might return a 500, and in case of Right return a 200.
To address the use case with default value mentioned earlier - if you really want to do that, get rid of the Left and in that case resolve into some value (e.g. 0), then you can use fold:
def f(i: Int) = i + 1
// if x = Left, then z = 0
// if x = Right, then z = x + 1
val z = x.fold(_ => 0, i => i + 1)

"for-loop" to reduce coding on Chisel3.2

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.
There are a few minor issues with this code:
Generally we name variables starting with a lower-case letter in Scala, this is primarily style, but it does have semantic meaning it certain circumstances (like pattern matching)
Square brackets are only used for type parameters (like Java generics), indexing uses normal parentheses in Scala
An input Vec of Bools is normally defined as: 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 whens 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)
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.

chisel hdl vector range assignment

I am new to Chisel HDL. I have a question regarding to Vec assignment. Suppose I have a Vec has n elements, and each one has w-bit SInt,
How can I assign a range of elements, let's say I have two Vec: a = Vec(10, SInt(width=8)), I have b = Vec(3, SInt(width=8)), How can I assign b := a(2:4)?
I know I can do it in for loop, is there any more elegant way to do it? I haven't find any example code or materials on it
Seems you are looking for a slice function in Vec. Glancing through
the Vec class I could not find such a function.
So the short answer is no, there is no elegant way to do this out-of-the-box.
The second most elegant thing is then to put such a function
in your project's util library and try to eventually
get this function upstreamed.
Implementing it in Chisel3 might look something like this:
class FooTester extends BasicTester {
def slice[T <: Data](someVec: Vec[T], startIndex: Int, endIndex: Int) : Vec[T] = {
Vec( for (i <- startIndex to endIndex) yield someVec(i) )
}
// An initialized Vec
val a = Vec(
Range(0, 10)
.map(SInt(_, width=8))
)
// A declared Vec
val b = Wire(Vec(3, SInt(width=8)))
b := slice(a, 2, 4)
assert(b(1) === SInt(3, width=8))
when(Counter(10).inc()) {stop()}
}
for (i <- 3 to 8) { my_vec(i) := something_at_index(i) }