How to printf or println UInt in chisel? - chisel

I am trying to execute the following code:
val num1 = 10.U
printf(p"num1 = $num1")
I am getting the following error when running this code in an example class.
[error] (run-main-8) chisel3.internal.ChiselException: Error: No implicit clock and reset.
[error] chisel3.internal.ChiselException: Error: No implicit clock and reset.
I am running the code using test:runMain <package.class>
I tried the other options in https://github.com/freechipsproject/chisel3/wiki/Printing-in-Chisel
using the printf and none of them worked.
Also tried the C style printing printf("num1 = %d",num1) and this results in the same error.

The following ought to work. The withClockAndReset provides the
clock needed to trigger the printf. Its a little picky here, because withClock or withClock and a nested withReset will not work.
class Hello extends RawModule {
val io = IO(new Bundle {
val out = Output(UInt(8.W))
val myClock = Input(Clock())
val myReset = Input(Bool())
})
withClockAndReset(io.myClock, io.myReset) {
printf("out is %d\n", io.out)
}
io.out := 42.U
}

There is a workaround. Printing of UInt type signals from the Chisel PeekPokeTester can be done with the help of the peek() function wrapped in a println().
println(peek(module_name.io.signal_name).toString(16))
Still have not found a way to directly print the actual signal module_name.io.signal_name the UInt type does not even have toString function so I am not sure if this can even be done.

Related

Create a generic Bundle in Chisel3

In Chisel3, I want to create a generic Bundle ParamsBus with parameterized type.
Then I follow the example on the Chisel3 website:
class ParamBus[T <: Data](gen: T) extends Bundle {
val dat1 = gen
val dat2 = gen
override def cloneType = (new ParamBus(gen)).asInstanceOf[this.type]
}
class TestMod[T <: Data](gen: T) extends Module {
val io = IO(new Bundle {
val o_out = Output(gen)
})
val reg_d = Reg(new ParamBus(gen))
io.o_out := 0.U
//io.o_out := reg_d.dat1 + reg_d.dat2
dontTouch(reg_d)
}
However, during code generation, I have the following error:
chisel3.AliasedAggregateFieldException: Aggregate ParamBus(Reg in TestMod) contains aliased fields List(UInt<8>)...
at fpga.examples.TestMod.<init>(test.scala:20)
Moreover, if I exchange the two lines to connect io.o_out, another error appears:
/home/escou64/Projects/fpga-io/src/main/scala/examples/test.scala:23:34: type mismatch;
found : T
required: String
io.o_out := reg_d.dat1 + reg_d.dat2
^
Any idea of the issue ?
Thanks for the help!
The issue you're running into is that the argument gen to ParamBus is a single object that is used for both dat1 and dat2. Scala (and thus Chisel) has reference semantics (like Java and Python), and thus dat1 and dat2 are both referring to the exact same object. Chisel needs the fields of Bundles to be different objects, thus the aliasing error you are seeing.
The easiest way to deal with this is to call .cloneType on gen when using it multiple times within a Bundle:
class ParamBus[T <: Data](gen: T) extends Bundle {
val dat1 = gen.cloneType
val dat2 = gen.cloneType
// Also note that you shouldn't need to implement cloneType yourself anymore
}
(Scastie link: https://scastie.scala-lang.org/mJmSdq8xSqayOceSjxHkRQ)
This is definitely a bit of a wart in the Chisel3 API because we try to hide the need to call .cloneType yourself, but least as of v3.4.3, this remains the case.
Alternatively, you could wrap the uses of gen in Output. It may seem weird to use a direction here but if all directions are Output, it's essentially the same as having no directions:
class ParamBus[T <: Data](gen: T) extends Bundle {
val dat1 = Output(gen)
val dat2 = Output(gen)
}
(Scastie link: https://scastie.scala-lang.org/TWajPNItRX6qOKDGDPnMmw)
A third (and slightly more advanced) technique is to make gen a 0-arity function (ie. a function that takes no arguments). Instead of gen being an object to use as a type template, it's instead a function that will create fresh types for you when called. Scala is a functional programming language so functions can be passed around as values just like objects can:
class ParamBus[T <: Data](gen: () => T) extends Bundle {
val dat1 = gen()
val dat2 = gen()
}
// You can call it like so:
// new ParamBus(() => UInt(8.W))
(Scastie link: https://scastie.scala-lang.org/JQ7D8VZsSCWP2i6DWJ4cLA)
I tend to prefer this final version, but I understand it can be more daunting for new users. Eventually I'd like to fix the issue you're seeing with a more direct use of gen, but these are ways to deal with the issue for the time being.

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)

Chisel3 REPL Vec assignment into module only works after eval

If we run the following Chisel3 code
class Controller extends Module {
val io = IO(new Bundle {
})
val sff = Module(new SFF)
val frame: Vec[UInt] = Reg(Vec(ProcedureSpaceSize, Integer32Bit))
for(i <- 0 until ProcedureSpaceSize)
frame(i) := 99.U
sff.io.inputDataVector := frame
}
class SFF extends Module {
val io = IO(new Bundle {
val inputDataVector: Vec[UInt] = Input(Vec(ProcedureSpaceSize, Integer32Bit))
})
}
in REPL debug mode. First do
reset;step
peek sff.io_inputDataVector_0;peek sff.io_inputDataVector_1;peek sff.io_inputDataVector_2
The REPL returns
Error: exception Error: getValue(sff.io_inputDataVector_0) returns value not found
Error: exception Error: getValue(sff.io_inputDataVector_1) returns value not found
Error: exception Error: getValue(sff.io_inputDataVector_2) returns value not found
Then do
eval sff.io_inputDataVector_0
which will be a success, yielding
...
resolve dependencies
evaluate sff.io_inputDataVector_0 <= frame_0
evaluated sff.io_inputDataVector_0 <= 99.U<32>
Then perform the above peek again
peek sff.io_inputDataVector_0;peek sff.io_inputDataVector_1;peek sff.io_inputDataVector_2;
This time, it returns
peek sff.io_inputDataVector_0 99
peek sff.io_inputDataVector_1 99
peek sff.io_inputDataVector_2 99
which is more expected.
Why does the REPL act in this way? Or was there something I missed? Thanks!
*chisel-iotesters is in version 1.4.2, and chiseltest is in version 0.2.2. Both should be the newest version.
The firrtl interpreter REPL does not necessarily compute or store values that on a branch of a mux that is not used. This can lead to problems noted above like
Error: exception Error: getValue(sff.io_inputDataVector_0) returns value not found.
eval can be used to force unused branches to be evaluated anyway. The REPL is an experimental feature that has not had a lot of use.
treadle is the more modern chisel scala-based simulator. It is better supported and faster than the interpreter. It has a REPL of its own, but does not have an executeFirrtlRepl equivalent.
It must be run from the command line via the ./treadle.sh script in the root directory. One can also run sbt assembly to create a much faster launching jar that is placed in utils/bin. This REPL also has not been used a lot but I am interested on feedback that will make it better and easier to use.
I think the problem that you are seeing is that all your wires are being eliminated due to dead code elimination. There are a couple of things you should try to fix this.
Make sure you have meaningful connections of your wires. Hardware that does not ultimately affect an output is likely to get eliminated. In your example you do not have anything driving a top level output
You probably need your circuit to compute something with those registers. If the registers are initialized to 99 then constant propagation will likely eliminate them. I'm not sure what you are trying to get the circuit to do so it is hard to make a specific recommendation.
If you get the above done I think the repl will work as expected. I do have a question about which repl you are using (there are two: firrtl-interpreter and treadle) I recommend using the latter. It is more modern and better supported. It also has two commands that would be useful
show lofirrtl will show you the lowered firrtl, this is how you can see that lots of stuff from the high firrtl emitted by chisel3 has been changed.
symbol . shows you all symbols in circuit (. is a regex that matches everything.
Here is a somewhat random edit of your circuit that drives and output based on your frame Vec. This circuit will generate firrtl that will not eliminated the wires you are trying to see.
class Controller extends Module {
val io = IO(new Bundle {
val out = Output(UInt(32.W))
})
val sff = Module(new SFF)
val frame: Vec[UInt] = Reg(Vec(ProcedureSpaceSize, Integer32Bit))
when(reset.asBool()) {
for (i <- 0 until ProcedureSpaceSize) {
frame(i) := 99.U
}
}
frame.zipWithIndex.foreach { case (element, index) => element := element + index.U }
sff.io.inputDataVector := frame
io.out := sff.io.outputDataVector.reduce(_ + _)
}
class SFF extends Module {
val io = IO(new Bundle {
val inputDataVector: Vec[UInt] = Input(Vec(ProcedureSpaceSize, Integer32Bit))
val outputDataVector: Vec[UInt] = Output(Vec(ProcedureSpaceSize, Integer32Bit))
})
io.outputDataVector <> io.inputDataVector
}

Chisel test - internal signals

I would like to test my code, so I'm doing a testbench. I wanted to know if it was possible to check the internal signals -like the value of the state register in this example- or if the peek was available only for the I/O
class MatrixMultiplier(matrixSize : UInt, cellSize : Int) extends Module {
val io = IO(new Bundle {
val writeEnable = Input(Bool())
val bufferSel = Input(Bool())
val writeAddress = Input(UInt(14.W)) //(matrixSize * matrixSize)
val writeData = Input(SInt(cellSize.W))
val readEnable = Input(Bool())
val readAddress = Input(UInt(14.W)) //(matrixSize * matrixSize)
val readReady = Output(Bool())
val readData = Output(SInt((2 * cellSize).W))
})
val s_idle :: s_writeMemA :: s_writeMemB :: s_multiplier :: s_ready :: s_readResult :: Nil = Enum(6)
val state = RegInit(s_idle)
...
and for the testbench :
class MatrixUnitTester(matrixMultiplier: MatrixMultiplier) extends PeekPokeTester(matrixMultiplier) { //(5.asUInt(), 32.asSInt())
println("State is: " + peek(matrixMultiplier.state).toString) // is it possible to have access to state ?
poke(matrixMultiplier.io.writeEnable, true.B)
poke(matrixMultiplier.io.bufferSel, false.B)
step(1)
...
EDIT : Ok, with VCD + GTKWave it is possible to graphically see these variables ;)
Good question. There's several parts to this answer
The Chisel supplied unit testing frameworks older chisel-testers and the newer chiseltest. Do not provide a mechanism to look into the wires directly.
Currently the chisel team is looking into ways of doing that.
Both provide indirect ways of doing it. Writing VCD output and using printf to see internal values
The Treadle firrtl simulator, which can directly simulate a firrtl (the direct output of the Chisel compiler) does allow for peek, and poking any signal directly. There are lots of examples of how its use in Treadle's unit tests. Treadle also provides a REPL shell which can be useful for exploring a circuit with manual peeks and pokes
The older chiseltesters (io-testers) and current chiseltest frameworks allow debugging the signal values with .peek() function that works well for the interface signals.
I haven't found a way to peek() an internal signal while debugging a testcase. However, Treadle simulator can dump the values of internal signals when it is running in verbose mode:
Add the annotation treadle.VerboseAnnotation to the test:
`test(new DecoupledGcd(16)).withAnnotations(Seq(WriteVcdAnnotation, treadle.VerboseAnnotation))`
When debugging in the IDEA and the test stops at breakpoint, the changes in the values of all internal signals up to this point are dumped to the Console.
This example will also generate the VCD wave file for further debugging.

How to generate code to RTL with blackbox?

When I want to convert code chisel to verilog with black box, I have error. How can I fix it?
[error] /data/workspace/chisel/chisel3-3.1.8/src/main/scala/tap/dti_bypass_register.scala:45:18: overloaded method value execute with alternatives:
import chisel3._
import chisel3.util._
class dti_bypass_register extends BlackBox with HasBlackBoxResource {
val io = IO(new Bundle {
val clk_DR = Input (Clock())// Bypass register clock
val TDI = Input (UInt(1.W))// data in
val bypass_en = Input (Bool())// enable signal
val captureDR = Input (Bool())// captureDR signal
val TDO_bypass = Output (UInt(1.W))// Serial data out
})
setResource("/dti_bypass_register.v")
}
object dti_bypass_registerDriver extends App {
chisel3.Driver.execute(args, () => new dti_bypass_register)
}
Chisel does not accept BlackBoxes as the top Module. Since BlackBoxes are simply interfaces that we emit a Verilog instantiation for, there's not really anything for Chisel to do with them.