Debugging combinational loops

514 views
Skip to first unread message

Jeff Bush

unread,
Jul 3, 2015, 1:15:57 PM7/3/15
to chisel...@googlegroups.com
I'm getting an error message that there is a combinational loop in my code.  It dumps out a bunch of messages:

[error] Testbench.scala:45: FOUND COMBINATIONAL PATH! in class main$
[error] Rasterizer.scala:139:   (0) in class Rasterizer
[error] Rasterizer.scala:139:   (1) in class Rasterizer
...
[error] Rasterizer.scala:139:   (22) in class Rasterizer
[error] Rasterizer.scala:139:   (23) in class Rasterizer
[error] Rasterizer.scala:104:   (24) in class Rasterizer

Reading the Chisel source code, it sounds like this is actually a combinational loop.

A few questions:
1. What is the significance of the numbers in parenthesis (0-24)? They always seem to be in order. I looked in the Chisel code in Backend.scala, and it looks like it's just the indices of the nodes. Is there any way to use these to debug the issue?  Is there any way to make the output for this error print more useful information (like the names of the signals)?

2. The line numbers just correspond to a for loop and the io for my top level module, which seems odd:

139: for (i <- 0 until 4)
140:     io.outputMask(i) := quad.io.coverageMask(i) && pixelValid

104: val io = new Bundle {

I've spent a bunch of time reviewing my code and can't find any combinational loops. I also tried selectively commenting out assignments to break the loop, but I seem to get the error unless I comment almost everything out.

Any hints on how to debug this issue? I did see this message:

Stack trace suppressed: run last compile:run for the full output.

But I'm not sure what that means or how to do it. Any hints would be appreciated.

Thanks

--Jeff


Jeff Bush

unread,
Jul 3, 2015, 4:52:58 PM7/3/15
to chisel...@googlegroups.com
I've isolated the problem I was having, and it raises an interesting question. Here's test code that reproduces the error message:

class Foo extends Module {

  val io
= new Bundle {

    val
in = UInt(INPUT, 4)
    val
out = UInt(OUTPUT, 4)
    val enable
= Bool(INPUT)
 
}


 
var i = 0
  io
.out := UInt(0)
  for (i <- 0 until 4) {
    io
.out(i) := io.in(i) && io.enable
 
}
}

When I run this, I get the same error:

[error] CombLoop.scala:21: FOUND COMBINATIONAL PATH! in class testbench$
[error] CombLoop.scala:14:   (0) in class Foo
[error] CombLoop.scala:14:   (1) in class Foo
...


I know a previous message on this list mentioned that if you read and write bits from the same signal combinationally, you will trigger the loop error (for example, ripple carry), but in my code, I'm only ever reading from in and writing to out.  


Note that I initially assign a zero to io.out because it gives an error if I don't:


[error] CombLoop.scala:14: Subword assignment requires a default value to have been assigned in class Foo

Is there a different idiom I should be using for this?


--Jeff


Jeff Bush

unread,
Jul 3, 2015, 5:33:41 PM7/3/15
to chisel...@googlegroups.com
This seems to work and is more idiomatic:

io.out := Cat((0 until 4).map(io.in(_) && io.enable))

I'm still curious whether the for loop method I tried should have worked, and what the proper remedy for the 'default value' error is.

Christopher Celio

unread,
Jul 4, 2015, 5:05:17 PM7/4/15
to chisel...@googlegroups.com
A couple of comments.

First, avoid "var". There's no need for it in your code (you don't need to declare it before using it in the for loop).

For reasons that are unnecessary, it looks like Chisel demands a default value for sub-word assignments, since I guess it's afraid you won't declare all of the bits.

There looks to be a bug in the combinational path code. I've found that this still triggers a failure!


    io.out := UInt(0)
    for (i <- 0 until 4) {
       io.out(i) := io.enable
    }

However, I would write your code this way:

    io.out := io.in & Fill(4, io.enable)

It's more clear what your intent is. That, or

    when (io.enable) {
       io.out := io.in 
    } .otherwise {
       io.out := UInt(0)
    }

-Chris

Jeff Bush

unread,
Jul 4, 2015, 9:20:43 PM7/4/15
to chisel...@googlegroups.com
Thanks for the response.  A few questions below:


On Saturday, July 4, 2015 at 2:05:17 PM UTC-7, Christopher Celio wrote:
A couple of comments.

First, avoid "var". There's no need for it in your code (you don't need to declare it before using it in the for loop).

I tried that, but couldn't get it to work. If I do this:

 for (val grantIndex <- 0 until numInputs) {

I get an error:

[error] /Users/jeffbush/src/gpu/hardware/src/main/scala/Arbiter.scala:38: val in for comprehension must be followed by assignment

[error]         for (val grantIndex <- 0 until numInputs) {


I tried switching it to var:


    for (var grantIndex <- 0 until numInputs) {

And I get a different error:

[error] /Users/jeffbush/src/gpu/hardware/src/main/scala/Arbiter.scala:38: illegal start of simple pattern
[error] for (var grantIndex <- 0 until numInputs) {
[error]      ^


It only works if I declare a var outside the for loop. I tried this with Scala 2.10.4 and 2.11.7.

 
There looks to be a bug in the combinational path code. I've found that this still triggers a failure!

Okay, that explains it.

Thanks

--Jeff

Christopher Celio

unread,
Jul 5, 2015, 4:10:53 PM7/5/15
to chisel...@googlegroups.com
You don't need to declare it at all.

for (i <- 0 until 4) println("hi")

-Chris

jayan...@gmail.com

unread,
Sep 4, 2015, 3:09:21 AM9/4/15
to chisel-users
Hi
I am having a similar problem , I tried your approach this way
deqReg         := Cat((0 until ports).map(ownReg === Cat(io.configVal(portBits*(_) + 2),io.configVal(portBits*(_)+ 1), io.configVal(portBits*(_)))))

but I am getting the following error when running the above code

[error] /home/jayant/Dropbox/FIFO/fifo.scala:24: missing parameter type for expanded function ((x$1) => portBits.$times(x$1).$plus(2))
[error]     deqReg         := Cat((0 until ports).map(ownReg === Cat(io.configVal(portBits*(_) + 2),io.configVal(portBits*(_)+ 1), io.configVal(portBits*(_)))))
[error]                                                                                     ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 2 s, completed 4 Sep, 2015 12:31:40 PM



Stephen Tridgell

unread,
Sep 5, 2015, 1:11:05 AM9/5/15
to chisel-users
I think thats a different issue. The way I read that error is that the type for "_" is unknown. How is 'ports' defined?
I am not a fan of the magic "_" syntax anyway. I use (0 until ports).map( x => { ... *x ... } )
Pretty sure there is no difference but I find it more readable.

jayan...@gmail.com

unread,
Sep 7, 2015, 1:08:31 AM9/7/15
to chisel-users
Thank you
I think that will work.
Reply all
Reply to author
Forward
0 new messages