Fixes the Xilinx clock generation primitives and adds support for
clock primitive instantiation on Xilinx without manually going
through the Vivado Clocking Wizard. The updated black boxes generate
Tcl code to instantiate an MMCM through the Clocking Wizard. The
clock primitives are limited to 1 output clock, and either a
single-ended or a differential input clock. The generated Tcl script
conforms with the Clash<->Tcl API.
Fixes the following:
- Broken Haskell simulation
The Haskell simulation of the Xilinx clock primitives was incorrect
due to a polarity mismatch in the lock output of Xilinx `clockWizard`
and `clockWizardDifferential`: Haskell simulation was the inverse of
HDL simulation and hardware. In Haskell simulation, the primitives
had an `Enable` as their output, which was _asserted_ when the PLL
lock was _deasserted_. This corresponds to an _asserted_ reset input
to the primitive in the simulation model, meaning the `Enable`
output was asserted iff the PLL reset input was asserted. HDL
simulation and hardware meanwhile had an active high lock signal
output (which is usually used as an active low reset signal to the
circuit). Finally, the simulation model did not account for different
frequencies of the input and output domains, instead treating
individual input samples as individual output samples without
resampling.
This has been fixed by changing the type to `Signal Bool` and
asserting it when the PLL has locked.
- Wrong port names of blackbox primitives
The blackbox primitives for `clockWizard` and
`clockWizardDifferential` had capitalized port names. Also, the
`clockWizardDifferential` primitive had 2 identical port names for
the differential input clock signals.
- Remove `Asynchronous` constraint from Xilinx `clockWizard` and
`clockWizardDifferential`. Originally intended to signal that these
functions react synchronously to the incoming reset and that the
outgoing lock signal is an asynchronous signal. Since synchronous
reset signals are a subset of asynchronous reset signals this
constraint on the input is vacuous. The constraint on the lock output
does not convey this information at all and is wrong. Note that it is
still necessary to synchronize the lock output in your design.
Known problems:
- The `locked` signal is asynchronous. Therefore, this function is
unsafe.
- The Clocking Wizard uses input and output frequencies to determine
the multiplier and divider for the MMCM, but Clash uses periods
instead. The conversion from period (picoseconds, Natural) to
frequency (MHz, Double) is not exact. This is already not exact when
using `hzToPeriod`, e.g. `hzToPeriod 300e6` translates to a period
of `3333` ps, which becomes `300.03000300030004` in Tcl.