sylefeb / Silice

Silice is an easy-to-learn, powerful hardware description language, that simplifies designing hardware algorithms with parallelism and pipelines.
Other
1.28k stars 77 forks source link

Strange result from circuit #197

Closed rob-ng15 closed 2 years ago

rob-ng15 commented 2 years ago
// From recursive Verilog module
// https://electronics.stackexchange.com/questions/196914/verilog-synthesize-high-speed-leading-zero-count

// Create a LUA pre-processor function that recursively writes
// circuitries counting the number of leading zeros in variables
// of decreasing width.
// Note: this could also be made in-place without wrapping in a
// circuitry, directly outputting a hierarchical set of trackers (<:)
$$function generate_clz(name,w_in,recurse)
$$ local w_out = clog2(w_in)
$$ local w_h   = w_in//2
$$ if w_in > 2 then generate_clz(name,w_in//2,1) end
circuitry $name$_$w_in$ (input in,output out)
{
$$ if w_in == 2 then
   out = ~in[1,1];
$$ else
   uint$clog2(w_in)-1$ half_count = uninitialized;
   uint$w_h$           lhs        <: in[$w_h$,$w_h$];
   uint$w_h$           rhs        <: in[    0,$w_h$];
   uint$w_h$           select     <: left_empty ? rhs : lhs;
   uint1               left_empty <: ~|lhs;
   (half_count) = $name$_$w_h$(select);
   out          = {left_empty,half_count};
$$ end
}
$$end

// Produce a circuit for 32 bits numbers
$$generate_clz('clz_silice',32)

// Test it (make verilator)
algorithm main(output uint8 leds)
{
  uint32 test(32b00000001000000011110000001001101);
  uint2  test2(2b01);
  uint5  cnt = uninitialized;

  (cnt)      = clz_silice_32(test);
  __display("%b -> %d",test,cnt);
  (cnt)      = clz_silice_2(test2);
  __display("%b -> %d",test2,cnt);
}

algorithm pulse(
    output  uint32  cycles(0)
) <autorun> {
    cycles := cycles + 1;
}

Gives as output:

00000001000000011110000001001101 ->  7
01 -> 31

Would expect 7 and 1.

sylefeb commented 2 years ago

Interesting! The problem lies with this expression: out = ~in[1,1]; Replacing by out = in[1,1] ? 0 : 1; or by !in[1,1] works as expected.

This expression directly translates to its Verilog counterpart, where lhs is 5 bits (cnt) and rhs is 2 bits (test2). The expression is widened to 5 bits before the ~ operator is applied, hence the 31. The ! operator has a different behavior, setting 1 appropriately (logical vs bitwise negation).

Btw, the original (linked at the top) did not have this problem (it does use !), I did introduce this bug 👎 .

rob-ng15 commented 2 years ago

Can confirm that changing to !in[1,1] works. Which, technically is the correct expression ~in[1,1] or !in[1,1] ?

sylefeb commented 2 years ago

!in[1,1] is the correct one, this is the 'bottom' case of the recursion, so we only count 1 is the second bit is set.

rob-ng15 commented 2 years ago

This is fixed, circuit was performing correctly.