Automatically adding proper delay to DSignal dom n type functions.

18 views
Skip to first unread message

L Bollen

unread,
Jun 28, 2021, 4:35:17 AMJun 28
to Clash - Hardware Description Language
Dear community,

I've been working with functions for a while that require multiple inputs in the DSignal dom n context and produce results with DSignal dom (n+d) context. In cases where I want to apply these functions to arguments with a different amount of accumulated delay
(e.g DSignal dom 0 and DSignal dom 3), I have to explicitly delay the argument with the lower amount of delay such that both delays are the same. I'm trying to find a way to automatically match the amount of delays without introducing unnecessary delays. 

Consider the following toy example:
multiply :: (Num a, HiddenClockResetEnable dom, NFDataX a) => DSignal dom n a -> DSignal dom n a -> DSignal dom (n + 3) a
multiply a b = delayN d3 0 ((*) <$> a <*> b)

I'm trying to find a way to delay a or b based on which has a lower delay.  I found that delaying both input arguments with delayedI causes problems where Clash can not properly derive the amount of delay.
Is there a way to do this in a clean way? Perhaps by creating a constraint that forces d1 or d2 to be 0 in the following type example? 

multiply :: (Num a, HiddenClockResetEnable dom, NFDataX a, (n1+d1) ~ (n2+d2)) => DSignal dom (n1 +  d1) a -> DSignal dom (n2 + d2) a -> DSignal dom ((n2 + d2) + 3) a

Kind regards,
Lucas

Rowan Goemans

unread,
Jun 28, 2021, 4:44:19 AMJun 28
to clash-l...@googlegroups.com

Hello Lucas,

Doesn't delayedI work?

Best regards,

Rowan Goemans

--
You received this message because you are subscribed to the Google Groups "Clash - Hardware Description Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clash-languag...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clash-language/2dfa7773-f988-4ec4-8581-3296272443adn%40googlegroups.com.

L Bollen

unread,
Jun 28, 2021, 5:00:32 AMJun 28
to Clash - Hardware Description Language
Hello Rowan,

When adding delayedI to one of the inputs as follows:  multiply a b = delayN d3 0 ((*) <$> a <*> (delayedI 0 b)), I can ofcourse delay the second input to match the first, but this only works when the second input has a lower delay than the first.
Ideally I would add delayedI to both inputs as follows: multiply a b = delayN d3 0 ((*) <$>  (delayedI 0 a)   <*> (delayedI 0 b))
However, this makes the delays ambiguous.

Kind regards,
Lucas
Op maandag 28 juni 2021 om 10:44:19 UTC+2 schreef goeman...@gmail.com:

Christiaan Baaij

unread,
Jun 28, 2021, 6:12:50 AMJun 28
to clash-l...@googlegroups.com
If I understand you correctly, I think you want:

multiply ::
  forall m n dom a .
  (Num a, HiddenClockResetEnable dom, NFDataX a, KnownNat m, KnownNat n) =>
  DSignal dom m a ->

  DSignal dom n a ->
  DSignal dom (Max m n + 3) a
multiply a b =
  delayN d3 0 ((*) <$> delayI @(Max m n - m) 0 a <*> delayI @(Max m n - n) 0 b)

Then the most delayed arguments, is delayed by zero, while the least delayed argument is delayed by the difference.
As you can see, for differently delayed arguments, you get:

topEntity ::
  HiddenClockResetEnable dom =>
  DSignal dom 1 Int ->
  DSignal dom 2 Int ->
  DSignal dom 5 Int
topEntity a b = multiply a b

i.e. it's delayed by 3 compared to the most delayed argument

L Bollen

unread,
Jun 28, 2021, 6:22:54 AMJun 28
to Clash - Hardware Description Language
Thank you Christiaan!

This is exactly the type of behaviour I was hoping to achieve.
I'm not familiar with the @( ) you applied in the code, could you point me in the right direction to read more about how this works?

Thank you again.

Kind regards,
Lucas 

Op maandag 28 juni 2021 om 12:12:50 UTC+2 schreef christia...@gmail.com:

Christiaan Baaij

unread,
Jun 28, 2021, 6:28:23 AMJun 28
to clash-l...@googlegroups.com
Another way I could have written `multiply` would be:


multiply ::
  forall m n dom a .
  (Num a, HiddenClockResetEnable dom, NFDataX a, KnownNat m, KnownNat n) =>
  DSignal dom m a ->
  DSignal dom n a ->
  DSignal dom (Max m n + 3) a
multiply a b =
  delayN d3 0 ((*) <$> delayN (SNat :: SNat (Max m n - m)) 0 a
                   <*> delayN (SNat :: SNat (Max m n - n)) 0 b)

which perhaps makes it more clear what the `@` syntax is doing.

Reply all
Reply to author
Forward
0 new messages