Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clash.Signal.Delayed.feedback is wrong #2718

Open
christiaanb opened this issue May 13, 2024 · 1 comment
Open

Clash.Signal.Delayed.feedback is wrong #2718

christiaanb opened this issue May 13, 2024 · 1 comment
Labels

Comments

@christiaanb
Copy link
Member

accumX :: DSignal dom d Bool -> DSignal dom d Int -> DSignal dom d Int
accumX restart x = feedback $ \q -> 
  let d = x + mux restart 0 q
      z = delayN d1 0 d
  in (q, z)

and

accumY :: DSignal dom d Bool -> DSignal dom d Int -> DSignal dom d Int
accumY restart x = feedback $ \q -> 
  let d = x + mux restart 0 q
      z = delayN d1 0 d
   in (d, z)

have the same delay signature (no delay), while accumX one outputs x + 0 when restart is True after one cycle; while accumY outputs it immediately.

With antiDelay we can see this distinction in the type signature:

accumD1 :: DSignal dom d Bool -> DSignal dom d Int -> DSignal dom (d + 1) Int
accumD1 restart x =
  let d = x + mux restart 0 (antiDelay d1 q)
      q = delayN d1 0 d
   in q

and

accumD0 :: DSignal dom d Bool -> DSignal dom d Int -> DSignal dom d Int
accumD0 restart x =
  let d = x + mux restart 0 (antiDelay d1 q)
      q = delayN d1 0 d
   in d

We should deprecate feedback and move antiDelay from the "experimental" bracket, as it is clearly the better function for making feedback loops in a context where we want to keep track of delay at the type level.

@kleinreact
Copy link
Contributor

The feedback function definitely is broken. I tried to create a DSignal version of register, as I can't use register in a DSignal environment and delayedI causes a type mismatch on recursive bindings, using feedback as follows:

registerD v = feedback @_ @_ @_ @0 . \x -> (x, ) . delayedI @1 v
           -- antiDelay d1 . delayedI @1 v

but the definition creates a combinational loop, as it can be tested with

let r = registerD False $ not <$> r in sampleN @System 10 $ toSignal r

The alternative implementation of the comment above using antiDelay just works fine. I initially went with feedback, as that one is not marked as experimental, although the interface is much less intuitive than the one for antiDelay.

To be honest, the antiDelay implementation also looks kind of strange, as the naming suggests that both operations basically should cancel each other out. I'd suggest that we actively drop the current feedback implementation and rename antiDelay to feedback (keeping the type signature antiDelay). Users that are using the current version of feedback are in a danger zone already and a change of the type signature will actively notify them that they need to update their code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants