Unexpected Behavior with CLog and SNat?

I ran into an odd problem while writing a simple counter in clash - what I’m trying to do is specify the starting point for a “count down” timer using SNat:

countDown'' :: forall n dom. (HiddenClockResetEnable dom)
            => (1 <= n)
            => KnownNat n
            => SNat n -> Signal dom (Unsigned (CLog 2 n))
countDown'' y = counter
    where start = snatToNum y
          counter = register start (goDown <$> counter)
          goDown 0 = 0
          goDown x = x - 1

This works sometimes:

clashi> sampleN @System 10 $ countDown'' (SNat @10)
[10,10,9,8,7,6,5,4,3,2]
clashi> sampleN @System 10 $ countDown'' (SNat @9)
[9,9,8,7,6,5,4,3,2,1]
clashi> sampleN @System 10 $ countDown'' (SNat @15)
[15,15,14,13,12,11,10,9,8,7]

But not when using a power of 2:

clashi> sampleN @System 10 $ countDown'' (SNat @8)
[0,0,0,0,0,0,0,0,0,0]
clashi> sampleN @System 10 $ countDown'' (SNat @4)
[0,0,0,0,0,0,0,0,0,0]
clashi> sampleN @System 10 $ countDown'' (SNat @16)
[0,0,0,0,0,0,0,0,0,0]

I’m a bit lost! I thought that CLog would be happy that I was using a power of 2.

Oh I get it! It’s a “off by one” type error.

CLog 2 4 = 2 

… but we need 3 bits to represent 4 (0b100). So the MSB is lost, and we get 0 (which is not good).

It would be better to use start = (snatToNum y) - 1 here. Thank you for the help :slight_smile:

Correct! Great, you figured it out :slight_smile:.

For reference: it’s usually easier to use maxBound since it automatically means the maximum value of a type. The number type you are describing also exists as Index n.