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

Fix Clash.Clocks lock signal #2417

Merged
merged 1 commit into from
Feb 9, 2023
Merged

Fix Clash.Clocks lock signal #2417

merged 1 commit into from
Feb 9, 2023

Conversation

DigitalBrains1
Copy link
Member

@DigitalBrains1 DigitalBrains1 commented Feb 5, 2023

The way we tried to generate the lock signal in Clash.Clocks was very wrong. For instance, a Clash.Intel.ClockGen.alteraPll with two clock outputs would boil down to:

alteraPll ::
  ( KnownDomain domIn
  , KnownDomain c1
  , KnownDomain c2
  ) =>
  SSymbol name ->
  Clock domIn ->
  Reset domIn ->
  ( Clock c1
  , Clock c2
  , Signal pllLock Bool
  )
alteraPll !_ = clocks
 where
  clocks clk@(Clock _ Nothing) rst =
    ( unsafeCoerce clk
    , unsafeCoerce clk
    , unsafeCoerce rst
    )
  clocks _ _ = error "clocks: dynamic clocks unsupported" 

unsafeCoerce rst is wrong in three ways:

  • You can't coerce a Reset into a Signal, it segfaults.
  • The time base is wrong: one input sample becomes one output sample even when the output clock has a different period than the input clock.
  • There is no handling of ResetPolarity. The simulation model is that lock is deasserted when reset is asserted, but this was not effected.

This PR changes the implementation to:

alteraPll ::
  ( KnownDomain domIn
  , KnownDomain c1
  , KnownDomain c2
  , KnownDomain pllLock
  ) =>
  SSymbol name ->
  Clock domIn ->
  Reset domIn ->
  ( Clock c1
  , Clock c2
  , Signal pllLock Bool
  )
alteraPll !_ = clocks
 where
  clocks clk@(Clock _ Nothing) rst =
    ( unsafeCoerce clk
    , unsafeCoerce clk
    , unsafeSynchronizer clockGen clockGen (unsafeToLowPolarity rst)
    )
  clocks _ _ = error "clocks: dynamic clocks unsupported" 

Note that we needed a KnownDomain pllLock as well.

Still TODO:

  • Write a changelog entry (see changelog/README.md)
  • Check copyright notices are up to date in edited files

@DigitalBrains1
Copy link
Member Author

DigitalBrains1 commented Feb 5, 2023

The extra KnownDomain pllLock is an API change. It could be someone wrote:

myPll ::
  (KnownDomain domIn, KnownDomain domOut) =>
  Clock domIn ->
  Reset domIn ->
  (Clock domOut, Signal pllLock Bool)
myPll = altpll (SSymbol @"mypll")

and now needs to add KnownDomain pllLock to that definition. I feel this should still be backported because the advantage of working (non-segfaulting) Haskell simulation outweighs this disadvantage. But I shall add it to the change log.

[edit]
Note that once source is adjusted to add the KnownDomain constraint, it will continue to compile in older Clash versions as well because functions can be overconstrained without issue.
[/edit]

The lock signal is now `False` for the time that the input reset signal
is asserted, and `True` when the input reset signal is not asserted.

Before this commit, the lock signal output was defined in terms of the
reset input as follows:

```
rstIn :: Reset domIn
lockOut :: Signal domOut Bool
lockOut = unsafeCoerce rstIn
```

This is incorrect in three ways:

* You can't coerce a `Reset` into a `Signal`, it segfaults.
* The time base is wrong: one input sample becomes one output sample
  even when the output clock has a different period than the input
  clock.
* There is no handling of `ResetPolarity`; the simulation model is that
  lock is deasserted when reset is asserted.
Copy link
Member

@leonschoorl leonschoorl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the examples now also require an type annotation on the pllLocked signal to type check:

-- (clk100 :: 'Clock' Dom100MHz, pllLocked) =
-- 'alteraPll' ('SSymbol' \@\"alterapll50to100\") clk50 rst50

-- (clk100 :: 'Clock' Dom100MHz, clk150 :: 'Clock' Dom150MHz, pllLocked) =
-- 'alteraPll' ('SSymbol' \@\"alterapllmulti\") clk50 rst50

This next one already has all the type annotations, but is missing the = between the pattern and the alteraPll. Maybe you can fix that while you're in there.

-- (clk :: 'Clock' 'Clash.Signal.System', pllStable :: 'Signal' 'Clash.Signal.System' 'Bool')
-- 'alteraPll' ('SSymbol' \@\"alterapll50to100\") clkInp
-- ('Clash.Signal.unsafeFromLowPolarity' rstInp)

And the Xilinx prims clockWizard and clockWizardDifferential don't have the same crashing issues, but do a similar unsafeCoerce between domains with (potentially) different periods.

clockWizard !_ clk@(Clock _ Nothing) rst =
(unsafeCoerce clk, unsafeCoerce (toEnable (unsafeToHighPolarity rst)))

@DigitalBrains1
Copy link
Member Author

We've talked about the points Leon raises. The documentation now is not incorrect (modulo the missing =) but it can definitely be improved, and I will tackle this in another PR. The Xilinx clockWizard stuff is being worked on by Hidde for Clash master / 1.8, but for 1.6, we're going to keep it as it is but write an issue report that it is... well... basically very weird. It will also not be part of this PR.

@DigitalBrains1 DigitalBrains1 merged commit c60353e into master Feb 9, 2023
@DigitalBrains1 DigitalBrains1 deleted the clocks-lock branch February 9, 2023 15:42
mergify bot pushed a commit that referenced this pull request Feb 9, 2023
The lock signal is now `False` for the time that the input reset signal
is asserted, and `True` when the input reset signal is not asserted.

Before this commit, the lock signal output was defined in terms of the
reset input as follows:

```
rstIn :: Reset domIn
lockOut :: Signal pllOut Bool
lockOut = unsafeCoerce rstIn
```

This is incorrect in three ways:

* You can't coerce a `Reset` into a `Signal`, it segfaults.
* The timebase is wrong: one input sample becomes one output sample even
  when the output clock has a different period than the input clock.
* There is no handling of `ResetPolarity`; the simulation model is that
  lock is deasserted when reset is asserted.

(cherry picked from commit c60353e)

# Conflicts:
#	clash-prelude/src/Clash/Clocks/Deriving.hs
DigitalBrains1 added a commit that referenced this pull request Feb 10, 2023
The lock signal is now `False` for the time that the input reset signal
is asserted, and `True` when the input reset signal is not asserted.

Before this commit, the lock signal output was defined in terms of the
reset input as follows:

```
rstIn :: Reset domIn
lockOut :: Signal pllOut Bool
lockOut = unsafeCoerce rstIn
```

This is incorrect in three ways:

* You can't coerce a `Reset` into a `Signal`, it segfaults.
* The timebase is wrong: one input sample becomes one output sample even
  when the output clock has a different period than the input clock.
* There is no handling of `ResetPolarity`; the simulation model is that
  lock is deasserted when reset is asserted.

(cherry picked from commit c60353e)
DigitalBrains1 added a commit that referenced this pull request Feb 10, 2023
The lock signal is now `False` for the time that the input reset signal
is asserted, and `True` when the input reset signal is not asserted.

Before this commit, the lock signal output was defined in terms of the
reset input as follows:

```
rstIn :: Reset domIn
lockOut :: Signal pllOut Bool
lockOut = unsafeCoerce rstIn
```

This is incorrect in three ways:

* You can't coerce a `Reset` into a `Signal`, it segfaults.
* The timebase is wrong: one input sample becomes one output sample even
  when the output clock has a different period than the input clock.
* There is no handling of `ResetPolarity`; the simulation model is that
  lock is deasserted when reset is asserted.

(cherry picked from commit c60353e)

Co-authored-by: Peter Lebbing <peter@digitalbrains.com>
DigitalBrains1 added a commit that referenced this pull request Oct 5, 2023
PR #2417 caused a bug in the generation of the `qsys` file: it generated
a spurious extra output clock which was completely unused otherwise.
@DigitalBrains1 DigitalBrains1 mentioned this pull request Oct 5, 2023
2 tasks
DigitalBrains1 added a commit that referenced this pull request Oct 5, 2023
PR #2417 caused a bug in the generation of the `qsys` file: it generated
a spurious extra output clock which was completely unused otherwise.
mergify bot pushed a commit that referenced this pull request Oct 5, 2023
PR #2417 caused a bug in the generation of the `qsys` file: it generated
a spurious extra output clock which was completely unused otherwise.

(cherry picked from commit 5b055fb)

# Conflicts:
#	clash-lib/src/Clash/Primitives/Intel/ClockGen.hs
DigitalBrains1 added a commit that referenced this pull request Oct 6, 2023
PR #2417 caused a bug in the generation of the `qsys` file: it generated
a spurious extra output clock which was completely unused otherwise.

(cherry picked from commit 5b055fb)
DigitalBrains1 added a commit that referenced this pull request Oct 6, 2023
PR #2417 caused a bug in the generation of the `qsys` file: it generated
a spurious extra output clock which was completely unused otherwise.

(cherry picked from commit 5b055fb)

Co-authored-by: Peter Lebbing <peter@digitalbrains.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants