How to exchange certain bits of the register - chisel

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
}

Related

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))
//...
//...
}

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

chisel-firrtl combinational loop handling

I have met some troubles while simulating design that contains comb-loop. Firrtl throws exception like
"No valid linearization for cyclic graph"
while verilator backend goes normal with warnings.
Is it possible to simulate such design with firrtl backend?
And can we apply --no-check-comb-loops not for all design but for some part of it while elaborating?
Example code here:
import chisel3._
import chisel3.iotesters.PeekPokeTester
import org.scalatest.{FlatSpec, Matchers}
class Xor extends core.ImplicitModule {
val io = IO(new Bundle {
val a = Input(UInt(4.W))
val b = Input(UInt(4.W))
val out = Output(UInt(4.W))
})
io.out <> (io.a ^ io.b)
}
class Reverse extends core.ImplicitModule {
val io = IO(new Bundle {
val in = Input(UInt(4.W))
val out = Output(UInt(4.W))
})
io.out <> util.Reverse(io.in)
}
class Loop extends core.ImplicitModule {
val io = IO(new Bundle {
val a = Input(UInt(4.W))
val b = Input(UInt(4.W))
val mux = Input(Bool())
val out = Output(UInt(4.W))
})
val x = Module(new Xor)
val r = Module(new Reverse)
r.io.in <> Mux(io.mux, io.a, x.io.out)
x.io.a <> Mux(io.mux, r.io.out, io.a)
x.io.b <> io.b
io.out <> Mux(io.mux, x.io.out, r.io.out)
}
class LoopBackExampleTester(cc: Loop) extends PeekPokeTester(cc) {
poke(cc.io.mux, false)
poke(cc.io.a, 0)
poke(cc.io.b, 1)
step(1)
expect(cc.io.out, 8)
}
class LoopBackExample extends FlatSpec with Matchers {
behavior of "Loop"
it should "work" in {
chisel3.iotesters.Driver.execute(Array("--no-check-comb-loops", "--fr-allow-cycles"), () => new Loop) { cc =>
new LoopBackExampleTester(cc)
} should be(true)
}
}
I will start by noting that Chisel is intended to make synchronous, flop-based, digital design easier and more flexible. It is not intended to represent all possible digital circuits. Fundamentally, Chisel exists to make the majority of stuff easier while leaving things that tend to be more closely coupled to implementation technology (like Analog) to Verilog or other languages.
Chisel (well FIRRTL) does not support such apparent combinational loops even if it possible to show that the loop can't occur due to the actual values on the mux selects. Such loops break timing analysis in synthesis and can make it difficult to create a sensible circuit. Furthermore, it isn't really true that the loop "can't occur". Unless there is careful physical design done here, there will likely be brief moments (a tiny fraction of a clock cycle) where there will be shorts which can cause substantial problems in your ASIC. Unless you are building something like a ring oscillator, most physical design teams will ask you not to do this anyway. For the cases where it is necessary, these designs typically are closely tied to the implementation technology (hand designed with standard cells) and as such are not really within the domain of Chisel.
If you need such a loop, you can express it in Verilog and instantiate the design as a BlackBox in your Chisel.

Vector of RegEnable

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)
}

Chisel/FIRRTL constant propagation & optimization across hierarchy

Consider a module that does some simple arithmetic and is controlled by a few parameters. One parameter controls the top level behavior: the module either reads its inputs from its module ports, or from other parameters. Therefore, the result will either be dynamically computed, or statically known at compile (cough, synthesis) time.
The Verilog generated by Chisel has different module names for the various flavors of this module, as expected. For the case where the result is statically known, there is a module with just one output port and a set of internal wires that are assigned constants and then implement the arithmetic to drive that output.
Is it possible to ask Chisel or FIRRTL to go further and completely optimize this away, i.e. in the next level of hierarchy up, just replace the instantiated module with its constant and statically known result? (granted that these constant values should by optimized away during synthesis, but maybe there are complicated use cases where this kind of elaboration time optimization could be useful).
For simple things that Firrtl currently knows how to constant propagate, it already actually does this. The issue is that it currently doesn't const prop arithmetic operators. I am planning to expand what operators can be constant propagated in the Chisel 3.1 release expected around New Years.
Below is an example of 3.0 behavior constant propagating a logical AND and a MUX.
import chisel3._
class OptChild extends Module {
val io = IO(new Bundle {
val a = Input(UInt(32.W))
val b = Input(UInt(32.W))
val s = Input(Bool())
val z = Output(UInt(32.W))
})
when (io.s) {
io.z := io.a & "hffff0000".U
} .otherwise {
io.z := io.b & "h0000ffff".U
}
}
class Optimize extends Module {
val io = IO(new Bundle {
val out = Output(UInt())
})
val child = Module(new OptChild)
child.io.a := "hdeadbeef".U
child.io.b := "hbadcad00".U
child.io.s := true.B
io.out := child.io.z
}
object OptimizeTop extends App {
chisel3.Driver.execute(args, () => new Optimize)
}
The emitted Verilog looks like:
module Optimize(
input clock,
input reset,
output [31:0] io_out
);
assign io_out = 32'hdead0000;
endmodule