2
votes

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

2

2 Answers

2
votes

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.

2
votes

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