Vector of RegEnable - chisel

Looking for an example/advice on how to use RegEnable as vector.
Also I want to control the inputs & enable signals to be a function of the register index in the Vector.
So first, how do I declare Vector of RegEnable(), and second how to iterate over it and connect the input & enable. In the RegEnable() case the declaration and the connection are made in the same statement. Something like:
for (j <- 0 until len) {
val pipe(j) = RegEnable(in(j),en(j))
}
The above code doesn't compile. Also in & en are vectors or bit selection

For this type of thing, it's likely much easier to use RegEnable to construct a Seq[T <: Data] and then construct a Vec out of that. The Vec object has two main apply methods: a varargs one and a seq. For your own reference, take a look at the Chisel Vec object API documentation.
The following full example builds, but the relevant part is the val pipe and val pipe2 lines. You can do this with either a map or a for/yield.
import chisel3._
import chisel3.util.RegEnable
import chisel3.iotesters
import chisel3.experimental.MultiIOModule
class Example(len: Int) extends MultiIOModule {
val in = Seq.fill(len)(IO(Input(UInt(1.W))))
val en = Seq.fill(len)(IO(Input(Bool())))
val mySeq: Seq[Data] = (0 until len).map( j => RegEnable(in(j), en(j)) )
val pipe = Vec(mySeq)
val mySeq2: Seq[Data] = for (j <- 0 until len) yield ( RegEnable(in(j), en(j)) )
val pipe2 = Vec(mySeq2)
}

Related

Exception connecting Vec of IO

Can anyone explain what the problem with this construction is? I have a child module with a Vec of IO that I'm trying to attach to the equivilent IO in the parent module.
This works out fine with just a Seq but I get an exception during elaboration when wrapped up in Vec. The Vec is needed since in my real case that gets indexed with a hardware signal in the child module.
The error:
[error] chisel3.internal.ChiselException: Connection between left (MyBundle[3](Wire in Lower)) and source (MyBundle[3](Wire in Upper)) failed #(0).out: Left or Right unavailable to current module.
The code:
package Testcase
import chisel3._
import chisel3.util._
import chisel3.stage.ChiselStage
import amba._
class MyBundle extends Bundle {
val out = Output(UInt(32.W))
}
class Upper (n : Int) extends RawModule {
val io = VecInit(Seq.fill(n)(IO(new MyBundle)))
val lower = Module(new Lower(n))
// This should word in the Vec case but gets the same error
// lower.io <> io
// This works for non Vec case
(lower.io, io).zipped map (_ <> _)
}
class Lower (n : Int) extends RawModule {
val io = VecInit(Seq.fill(n)(IO(new MyBundle)))
for (i <- 0 to n - 1) {
io(i).out := 0.U
}
}
object VerilogMain extends App {
(new ChiselStage).emitVerilog(new Upper(3), Array("--target-dir", "generated"))
}
The issue here is that VecInit creates a Wire of type Vec and connects everything in the Seq to the elements of that Wire. What you're basically doing is creating a Seq of IOs and then connecting them to a Wire.
This is mentioned in the error message (eg. (MyBundle[3](Wire in Lower))) but I totally see the confusion--it's not all that clear and VecInit is probably misnamed. This particular ambiguity in the API comes from historical design decisions in Chisel that are slowly getting fixed but it is a wart that sometimes bites users, sorry about that.
Here's the right way to accomplish what you want, just using IO(Vec(<n>, <type>)). Vec(<n>, <type>) is the way to create something of type Vec, in this case an IO of type Vec, as opposed to creating a Wire and connecting all of the fields:
class Upper (n : Int) extends RawModule {
//val io = VecInit(Seq.fill(n)(IO(new MyBundle)))
val io = IO(Vec(n, new MyBundle))
val lower = Module(new Lower(n))
// This should word in the Vec case but gets the same error
lower.io <> io
}
class Lower (n : Int) extends RawModule {
//val io = VecInit(Seq.fill(n)(IO(new MyBundle)))
val io = IO(Vec(n, new MyBundle))
for (i <- 0 to n - 1) {
io(i).out := 0.U
}
}
(Scastie link: https://scastie.scala-lang.org/COb88oXGRmKQb7BZ3id9gg)

Can I compute constants in software before Chisel begins designing hardware?

I'm new to Chisel, and I was wondering if it's possible to calculate constants in software before Chisel begins designing any circuitry. For instance, I have a module which takes one parameter, myParameter, but from this parameter I'd like to derive more variables (constant1 and constant2) that would be later used to initialize registers.
class MyModule(myParameter: Int) extends Module {
val io = IO(new Bundle{
val in = Input(SInt(8.W))
val out = Output(SInt(8.W))
})
val constant1 = 2 * myParameter
val constant2 = 17 * myParameter
val register1 = RegInit((constant1).U(8.W))
val register2 = RegInit((constant2).U(8.W))
//...
//...
}
Is there a way to configure Chisel's functionality so that an instance of MyModule(2) will first evaluate all Scala vals in software: constant1 = 2 * 2 = 4 and constant2 = 17 * 2 = 34. Then proceed to instantiate and initialize registers register1 = RegInit(4.U(8.W)) and register2 = RegInit(34.U(8.W))?
I was wondering if it's possible to calculate constants in software before Chisel begins designing any circuitry
Unless I'm misunderstanding your question, this is, in fact, how Chisel works.
Fundamentally, Chisel is a Scala library where the execution of your compiled Scala code creates hardware. This means that any pure-Scala code in your Chisel only exists at elaboration time, that is, during execution of this Scala program (which we call a generator).
Now, values in your program are created in sequential order as defined by Scala (and more-or-less the same as any general purpose programming language). For example, io is defined before constant1 and constant2 so the Chisel object for io will be created before either constants are calculated, but this shouldn't really matter for the purposes of your question.
A common practice in Chisel is to create custom classes to hold parameters when you have a lot of them. In this case, you could do something similar like this:
// Note this doesn't extend anything, it's just a Scala class
// Also note myParameter is a val now, this makes it accessible outside the class
class MyParameters(val myParameter: Int) {
val constant1 = 2 * myParameter
val constant2 = 17 * myParameter
}
class MyModule(params: MyParameters) extends Module {
val io = IO(new Bundle{
val in = Input(SInt(8.W))
val out = Output(SInt(8.W))
})
val register1 = RegInit((params.constant1).U(8.W))
val register2 = RegInit((params.constant2).U(8.W))
//...
//...
}

How to exchange certain bits of the register

I want to exchange certain bits of a register variable, just like the following example.
val data = Reg(UInt(100.W))
val re_order1 = Wire(UInt(log2Ceil(100).W))
val re_order2 = Wire(UInt(log2Ceil(100).W))
//Exchange the bits of the data register in re_order1 and re_order2
data(re_order1) := data(re_order2)
data(re_order2) := data(re_order1)
I tried to use shift and mask to achieve, but found it will be very complicated, is there a simple way
The following chisel Module does what I think you are aiming for here, that is: flip two arbitrary dynamically indexed bits in a register. This is going to require a lot of Muxes to accomplish this but I think this example shows that chisel can generate those pretty cleanly. The basic strategy is to treat the register as a Vec of bools then create a Mux every one of those bools to any other bit, based on whether the bit is referenced as one of the two bit addresses.
Then convert the sequences of generated as a new Vec using VecInit and then convert that vec to a UInt and wire it back into reg.
This module has a little bit of additional code to load the register. You may want to do that some other way.
import chisel3._
import chisel3.util.log2Ceil
import chiseltest._
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers
class FlipBits(bitWidth: Int) extends Module {
val io = IO(new Bundle {
val load = Input(Bool())
val loadValue = Input(UInt(bitWidth.W))
val bitAddress1 = Input(UInt(log2Ceil(bitWidth).W))
val bitAddress2 = Input(UInt(log2Ceil(bitWidth).W))
val out = Output(UInt(bitWidth.W))
})
val reg = RegInit(0.U(bitWidth.W))
val bits = VecInit(reg.asBools())
when(io.load) {
reg := io.loadValue
}.otherwise {
reg := VecInit(bits.indices.map { index =>
val index1 = Mux(index.U === io.bitAddress1, io.bitAddress2, index.U)
val index2 = Mux(index.U === io.bitAddress2, io.bitAddress1, index1)
bits(index2)
}).asUInt
}
io.out := reg
}

Chisel Bundle connection and type Safety

Just noticed you can do something like:
class MyBundle1 extends Bundle {
val a = Bool()
val x = UInt(2.W)
val y = Bool()
}
class MyBundle2 extends Bundle {
val x = Bool()
val y = Bool()
}
class Foo extends Module {
val io = IO(new Bundle {
val in = Input(new MyBundle1)
val out = Output(new MyBundle2)
})
io.out := io.in
}
not get an error and actually get the correct or, at least, expected verilog. One would think that Chisel was type-safe wrt to Bundles in this sort of bulk connection. Is this intentional? If so, is there any particular reasons for it?
The semantics of := on Bundle allow the RHS to have fields that are not present on the LHS, but not vice-versa. The high-level description of x := y is "drive all fields of x with corresponding fields of y."
The bi-directional <> operator is stricter.
I can't speak precisely to the reasoning, but connection operators are often a matter of taste with respect to "do what I mean." The idea of including alternate forms of connection operators for future releases is an ongoing discussion, with the threat of "operator glut" being weighed against the ability of users to specify exactly what they'd like to do.

Maintain connection order on FIRRTL using Cat operator

I want to ask for any idea for the following problem :
I want to connect the input port of a block named dut whose width is 787:0 bits, to a byte interface. I am doing like following :
val io = this.IO(new VerilatorHarnessIO(input_byte_count, output_byte_count*2))
val dut = Module(new DUT(dut_conf))
// inputs
val input_bytes = Cat(io.input_bytes)
val input_width = input_byte_count * 8
dut.io.inputs := input_bytes(input_width-1, input_width - dut_conf.inputBits)
I want that the order of the connection is preserved, ie:
Byte_0[7:0] ->input[7:0]
Byte_1[7:0] ->input[15:8]
But what I am getting is :
Byte_0[7:0] ->input[787:780]
Byte_1[7:0] ->input[779:772]
It will be much easier to debug if the ports are matched.
Is there a way to make this connection in the right order?
Thank you
Using the reverse method before you Cat should do what you want.
Consider the following Chisel:
import chisel3._
import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation}
import chisel3.util.Cat
class Foo extends RawModule {
val in = IO(Input(Vec(4, UInt(8.W))))
val out = IO(Output(UInt(32.W)))
out := Cat(in.reverse)
}
(new ChiselStage)
.execute(Array.empty, Seq(ChiselGeneratorAnnotation(() => new Foo)))
This produces the following Verilog with the bytes in the order you're looking for:
module Foo(
input [7:0] in_0,
input [7:0] in_1,
input [7:0] in_2,
input [7:0] in_3,
output [31:0] out
);
wire [15:0] _T; // #[Cat.scala 29:58]
wire [15:0] _T_1; // #[Cat.scala 29:58]
assign _T = {in_1,in_0}; // #[Cat.scala 29:58]
assign _T_1 = {in_3,in_2}; // #[Cat.scala 29:58]
assign out = {_T_1,_T}; // #[<pastie> 25:7]
endmodule
Cat appears backwards because it matches Verilog semantics and is thus backwards from the perspective of Scala semantics.
Consider:
val xs = List(8, 9, 10)
println(xs(0)) // 8
The left-most element is the lowest order index in Scala. However, in Verilog, you get the opposite:
assign x = {4'hde, 4'had};
The left-most part of that concatenation is actually the high-order nibble in the result. Chisel Cat was made to match Verilog semantics which makes it somewhat counter-intuitive in Scala.
As Schuyler mentioned, you can always reverse your Vec or Seq argument to Cat. Alternatively, you can cast to a UInt which will use the more intuitive Scala order:
import chisel3._
class Foo extends RawModule {
val in = IO(Input(Vec(4, UInt(8.W))))
val out = IO(Output(UInt(32.W)))
out := in.asUInt
}
.asUInt is defined on all Chisel Data, so you can use it to cast Bundles and other types to UInt as well. The only catch is that many methods defined on Vec return Seq, the Scala supertype of Vec which is not a chisel Data. This means you cannot do something like myVec.map(_ === 0.U).asUInt. You can always cast a Seq[T <: Data] (ie. a Seq containing Chisel Data elements) to a Vec via VecInit(mySeq), so you could do VecInit(myVec.map(_ === 0.U)).asUInt