Chisel : When-otherwise clause not working in function definition - chisel

I am trying to develop a simple circuit using Chisel 3 to generate the factorial for a number n. Here's my implementation :
class Factorial extends Module{
val io = IO(new Bundle{
val input = Input(UInt(8.W))
val output = Output(UInt(16.W))
})
def factorial(n: UInt): UInt = {
when (n === 0.U) {1.U}
.otherwise {n*factorial(n-1.U)}
}
io.out := factorial(io.in)
}
However, when I try to run it, I get the following error :
cmd26.sc:9: type mismatch;
found : Unit
required: chisel3.UInt
.otherwise {n*factorial(n-1.U)}
^Compilation Failed
Is there any particular reason for this? How do I solve this issue?
Also, I realize that an easy solution is to just have the number n to be of type Int, and have an if-else clause instead. Is there any way to type cast the parameter being passed during function call (i.e. from chisel3.UInt to Int)?

The Chisel when,elsewhen, and otherwise statement do not return a value.
Your design seems to be an attempt to compute the factorial value for an input in a single cycle. This is only going be practical for small input values and would probably be easier to implement via a lookup table.
I think what you are looking for (which would be a good learning exercise) is to build a circuit that given an input will return the factorial value after some number of cycles. This is very very similar to the way the GCD example works, GCD is included as an example in the chisel-template repo as an example. To do this you will need registers and ready and valid ports.
I suggest you figure out how that works and you should have a much easier time making your factorial. Good luck. And as suggested by #FabienM you will need a very large output port to contain the answer for even modest input values.

I thinks you can't do that. when(){}.otherwise{} is an hardware construction that don't return any value (Unit) as we can see in code.
With this construct you want to generate hardware «on the fly», which is impossible.
I think you have generate all solutions directly like it:
class Factorial extends Module{
val io = IO(new Bundle{
val input = Input(UInt(8.W))
val output = Output(UInt(1676.W))
})
def factorial(n: BigInt): BigInt = {
if(n == 0){
1
}else{
n*factorial(n-1)
}
}
io.output := 0.U
for(i <- 0 to 0xFF) {
when(io.input === i.U){
io.output := factorial(i).U
}
}
}
You can keep your recursive scala fonction but just for hardware generation step.
Note that 255! is a really big number you will need more than 16 bits UInt to output the value ;)

Related

How to get the Index of Max element in UInt Vec , Chisel

I'm trying to get the index of the Max element in a UInt vector.
My code looks like this
val pwr = Vec.tabulate(N) {i => energyMeters(i).io.pwr}
val maxPwr = pwr.indexOf(pwr.max)
However this code generate compilation error:
No implicit Ordering Defined for Chisel.UInt.
val maxPwr = pwr.indexOf(pwr.max)
^
I understand that I probably need to implement the max function , can someone give an example how this should be done ?
Edit:
I also tried this:
val pwr = Vec.tabulate(N) {i => energyMeters(i).io.pwr}
val maxPwr = pwr reduceLeft {(x,y) => Mux(x > y,x,y)}
val maxPwridx = pwr.indexOf(maxPwr)
But it fails on elaboration , when I tried to cast maxPwridx to UInt.
I've ended up with this workaround:
val pwr = Vec.tabulate(N) {i => energyMeters(i).io.pwr}
val maxPwr = pwr reduceLeft {(x,y) => Mux(x > y,x,y)}
val maxPwridx = pwr.indexWhere((x : UInt => x === maxPwr))
Chisel's Vec extends Scala's Seq. This means that a Vec has both dynamic access hardware methods that will allow you to generate hardware to search for something in a Vec (e.g., indexWhere, onlyIndexWhere, lastIndexWhere) as well as all the methods available to normal Scala sequences (e.g., indexOf).
For the purposes of doing hardware operations, you want to use the former (as you found in your last edit---which looks great!) as opposed to the latter.
To get some handle on this, the screenshot below shows the Chisel 3.3.0-RC1 API documentation for VecLike, filtered to excluded inherited methods. Notable here are indexWhere, onlyIndexWhere, lastIndexWhere, exists, forall, and contains:
And the documentation for Vec. The only interesting method here would be reduceTree:

Is there an accepted way to get a Gray Code counter in Chisel?

I'm looking to write counters in Chisel3 that will be used to address subunits. If the counter matches some register in a subunit then the subunit fires, otherwise it doesn't.
I would much rather have the addresses cycle in Gray code than in binary. It's easy enough to write a binary counter in Chisel, but I see no provision for a Gray code counter.
I can write a new type akin to Uint and Sint, but I'm reluctant to reinvent it if it's already out there. Yet I don't see anything in the cookbook or other docs about Gray code. Github just turns up a Minecraft-oriented repo (because it matches "chisel") There is existing stuff for VHDL but I want to express this in Chisel.
So have I missed a resource that would provide a Gray counter in Chisel? Failing that, is building a new type akin to Uint a reasonable way to proceed?
I did a quick look around and didn't find anything quite like what you're looking for. The closest thing I could find was a simple Gray counter in rocket-chip (https://github.com/chipsalliance/rocket-chip/blob/29ce00180f2a69947546d6385a1da86cbc584376/src/main/scala/util/AsyncQueue.scala#L49) but it uses regular binary counting and then just returns a UInt in Gray code. It also doesn't take advantage of any Scala type safety.
I think this would be a reasonable thing to build, and if you want you could contribute it to https://github.com/freechipsproject/ip-contributions for increased visibility.
I think if you wanted a proper GrayCode type, it would be reasonable to create a custom type. Unfortunately, there is no way to extend Data for a Bits-like type (all of the types in that hierarchy are sealed), but you could create a custom Bundle that wraps a UInt and then implement your own set of operations, eg.
class GrayCode(private val w: Int) extends Bundle {
val value = UInt(w.W)
def +(that: GrayCode): GrayCode = ???
}
object GrayCode {
// Lets you write GrayCode(4.W)
// Width is defined in chisel3.internal.firrtl though which is awkward...
def apply(width: Width): GrayCode = ???
}
This is just a quick sketch. The DSP Tools library has examples of custom types for DSP: https://github.com/ucb-bar/dsptools
They tend to use Scala Typeclasses a lot which is a more advanced Scala feature. Just mentioning in case some of the syntax in their looks alien.
You might take a look at this link programmersought gray code fifo it seems like it may be relevant but I am not familiar with it otherwise.
As with Jack I'm not familiar with the math needed to actually increment values in Gray code, but something like the following code would convert Gray code to binary, add, then convert it back to Gray code. I'm not sure if the Vec() code below would work correctly but should make the idea clear.
import chisel3._
import chisel3.util._
class GrayCode(private val w: Int) extends Bundle {
val value = UInt(w.W)
def bin2grey(x : UInt) : UInt = {
x ^ (x >> 1.U)
}
def grey2bin(x : UInt, n : Int) : UInt = {
val tmp = Wire(Vec(n, Bool()))
tmp(n-1) := x(n-1)
for (i <- 0 to (n-2)) {
tmp(i) := x(i) ^ tmp(i+1)
}
Cat(tmp.reverse)
}
def +(that: GrayCode): GrayCode = {
val sum = new GrayCode(w)
sum.value := grey2bin(bin2grey(this.value) + bin2grey(that.value), w)
sum
}
}
It seems like all implementations here use binary-to-Gray conversion. For asynchronous FIFOs, this only works if the Gray code is latched just before crossing clock domains. What if you want a counter that actually counts Gray codes instead of converting binary values to Gray codes?
One option is to convert Gray to binary, add, then convert back to Gray and store the result. The other is to use custom arithmetic to calculate the next Gray value in the sequence. The typical sequence is a reflected-binary Gray code, but others exist.
The code below implements a Gray code counter using a reflected-binary Gray code. It was adapted from this blog post. It only counts up. It works like the Chisel Counter object, except it adds support for a synchronous reset and custom register name. It returns the counter and wrap status.
import chisel3._
import chisel3.util._
// a Gray counter counts in Gray code
object GrayCounter {
// Gray unit cell
// b is the current state of this bit
// returns (t, z_o) where t is the next state of this bit
def grayCell(b: Bool, q_i: Bool, z_i: Bool, enable: Bool, parity: Bool): (Bool, Bool) = {
(b ^ (enable && q_i && z_i && parity), (!q_i) && z_i)
}
// cond = counts when true
// n = count value, must be a power of 2
// synchronousReset = resets counter to 0
// name = name for this counter
def apply(cond: Bool, n: Int, synchronousReset: Bool = false.B, name: String = null) = {
require(isPow2(n), s"Gray counter must have power-of-2 length (you asked for $n)")
require(n > 2, s"Gray counter minimum count is 4 (you asked for $n)")
val counter = RegInit(0.U(log2Ceil(n).W))
if (name != null) {
counter.suggestName(name)
}
val counterNext = Wire(Vec(log2Ceil(n), Bool()))
counter := counterNext.asUInt
val z_wires = Wire(Vec(log2Ceil(n), Bool()))
val parity = counter.xorR
for (i <- 0 until log2Ceil(n)) {
if (i == 0) {
val grayCellOut = grayCell(counter(i), true.B, true.B, cond, !parity)
counterNext(i) := grayCellOut._1
z_wires(i) := grayCellOut._2
} else {
val grayCellOut = grayCell(counter(i), counter(i-1) || (i == log2Ceil(n)-1).B,
z_wires(i-1) || (i == 1).B, cond, parity)
counterNext(i) := grayCellOut._1
z_wires(i) := grayCellOut._2
}
}
when (synchronousReset) {
counter := 0.U
}
val wrap = counter === (n/2).U && cond
(counter, wrap)
}
}

Error while passing values using peekpoketester

I am trying to pass some random integers (which I have stored in an array) to my hardware as an Input through the poke method in peekpoketester. But I am getting this error:
chisel3.internal.ChiselException: Error: Not in a UserModule. Likely cause: Missed Module() wrap, bare chisel API call, or attempting to construct hardware inside a BlackBox.
What could be the reason? I don't think I need a module wrap here as this is not hardware.
class TesterSimple (dut: DeviceUnderTest)(parameter1 : Int)(parameter2 : Int) extends
PeekPokeTester (dut) {
var x = Array[Int](parameter1)
var y = Array[Int](parameter2)
var z = 1
poke(dut.io.IP1, z.asUInt)
for(i <- 0 until parameter1){poke(dut.io.IP2(i), x(i).asUInt)}
for(j <- 0 until parameter2){poke(dut.io.IP3(j), y(j).asUInt)}
}
object TesterSimple extends App {
implicit val parameter1 = 2
implicit val parameter2 = 2
chisel3.iotesters.Driver (() => DeviceUnderTest(parameter1 :Int, parameter2 :Int)) { c =>
new TesterSimple (c)(parameter1, parameter2)}
}
I'd suggest a couple of things.
Main problem, I think you are not initializing your arrays properly
Try using Array.fill or Array.tabulate to create and initialize arrays
val rand = scala.util.Random
var x = Array.fill(parameter1)(rand.nextInt(100))
var y = Array.fill(parameter2)(rand.nextInt(100))
You don't need the .asUInt in the poke, it accepts Ints or BigInts
When defining hardware constants, use .U instead of .asUInt, the latter is a way of casting other chisel types, it does work but it a backward compatibility thing.
It's better to not start variables or methods with capital letters
I suggest us class DutName(val parameter1: Int, val parameter2: Int) or class DutName(val parameter1: Int)(val parameter2: Int) if you prefer.
This will allow to use the dut's paremeters when you are writing your test.
E.g. for(i <- 0 until dut.parameter1){poke(dut.io.IP2(i), x(i))}
This will save you have to duplicate parameter objects on your DUT and your Tester
Good luck!
Could you also share your DUT?
I believe the most likely case is your DUT does not extend Module

Examples in Chisel that make use of MuxCase

How do I implement a 4:1 Mux in chisel without using 2:1 Muxes? Is there a way where we can select one of the inputs of the N inputs by having something like Mux(sel, A,B,C,D.......N) where N can be taken in as a parameter? I am aware of the MuxCase in chisel but I am yet to find an example that makes use of MuxCase, any sort of documentation or example regarding this is greatly appreciated. Thank You.
There are a couple of usages in rocket-chip in MultiWidthFifo.scala
It's pretty straightforward. It takes a default value for what happens if none of the supplied conditions is true, otherwise it looks through a sequence of tuples, where each tuple of the form (bool condition, result) often written condition -> result. The return value is the result from the first boolean condition that is true.
Here is a toy example of a module that passes the number of input bools into a module which then uses that value to construct a sequence of mux cases.
class UsesMuxCase(numCases: Int) extends Module {
val io = IO(new Bundle {
val output = Output(UInt(10.W))
val inputs = Input(Vec(numCases, Bool()))
})
val cases = io.inputs.zipWithIndex.map { case (bool, index) =>
bool -> index.U(10.W)
}
io.output := MuxCase(0.U(10.W), cases)
}

def or val for defining Function in Scala

I'm learning Programming Paradigms in my University and reading this course material provided by the lecturer that defined a function this way:
val double = (x: Int) => 2 * x
double: Int => Int = <function1>
But from my own studies I found and got used to defining the same function like this:
def d (x: Int) = 2 * x
d: (x: Int)Int
I'm new to Scala. And both definitions give a result of:
res21: Int = 8
Upon passing 4 as the parameter.
Now my main question is why would the lecturer prefer to use val to define a function? I see it as longer and not really necessary unless using val gives some added advantages that I don't know of. Besides I understand using val makes some name a placeholder so later in the program, I could mistakenly write val double = 5 and the function would be gone!
At this stage I'm quite convinced I learned a better way of defining a function unless someone would tell me otherwise.
Strictly speaking def d (x: Int) = 2 * x is a method, not a Function, however scala can transparently convert (lift) methods into Functions for us. So that means you can use the d method anywhere that requires a Int => Int Function.
There is a small overhead of performing this conversion, as a new Function instance is created every time. We can see this happening here:
val double = (x: Int) => 2 * x
def d (x: Int) = 2 * x
def printFunc(f: Int => Int) = println(f.hashCode())
printFunc(double)
printFunc(double)
printFunc(d)
printFunc(d)
Which results in output like so:
1477986427
1477986427
574533740
1102091268
You can see when explicitly defining a Function using a val, our program only creates a single Function and reuses it when we pass as an argument to printFunc (we see the same hash code). When we use a def, the conversion to a Function happens every time we pass it to printFunc and we create several instances of the Function with different hash codes. Try it
That said, the performance overhead is small and often doesn't make any real difference to our program, so defs are often used to define Functions as many people find them more concise and easier to read.
In Scala, function values are monomorphic (i.e. they can not have type parameters, aka "generics"). If you want a polymorphic function, you have to work around this, for example by defining it using a method:
def headOption[A]: List[A] => Option[A] = {
case Nil => None
case x::xs => Some(x)
}
It would not be valid syntax to write val headOption[A]. Note that this didn't make a polymorphic function value, it is just a polymorphic method, returning a monomorphic function value of the appropriate type.
Because you might have something like the following:
abstract class BaseClass {
val intToIntFunc: Int => Int
}
class A extends BaseClass {
override val intToIntFunc = (i: Int) => i * 2
}
So its purpose might not be obvious with a very simple example. But that Function value could itself be passed to higher order functions: functions that take functions as parameters. If you look in the Scala collections documentation you will see numerous methods that take functions as parameters. Its a very powerful and versatile tool, but you need to get to a certain complexity and familiarity with algorithms before the cost /benefit becomes obvious.
I would also suggest not using "double" as an identifier name. Although legal Scala, it is easy to confuse it with the type Double.