Clash Shockwaves simulation hang

I’m writing a testbench for the uart module provided by Retroclash to get more familiar with Shockwave. It’s as follow

{-# OPAQUE topEntity #-}
{-# ANN topEntity
  (Synthesize
    { t_name = "topEntity"
    , t_inputs =
      [ PortName "clk"
      , PortName "rst"
      , PortName "uart_rxd"
      ]
    , t_output = PortName "uart_txd"
    }) #-}
topEntity :: Clock System -> Reset System -> Signal System Bit -> Signal System Bit
topEntity clk rst rxD = withClockResetEnable clk rst enableGen $
  let
    input = rx @8 (SNat @115200) rxD
    buf = fifo input txReady
    (txD, txReady) = tx @8 (SNat @115200) buf
  in boolToBit <$> (not . bitToBool <$> txD)

testUART :: IO ()
testUART = do
  let out = topEntity clockGen resetGen (fromList $ [high, high, high, high] <> [low, high, low, high, low, low, low, low] <> Ls.repeat high)

  file <- dumpVCD (0, 10_000_000) (traceSignal "topEntity" out) []

  case file of
    Left msg -> error msg
    Right (vcd, meta) -> do
      writeFile "test.vcd" vcd
      writeFileJSON "test.json" meta

With the class derived as follow

data TxState n = TxIdle | TxBusy Word32 (TxBit n)
  deriving (Show, Eq, Generic, NFDataX)

data TxBit n = TxStartBit (BitVector n) | TxDataBit (BitVector n) (Index n) | TxStopBit
  deriving (Show, Eq, Generic, NFDataX)

data RxState n = RxIdle | RxBusy Word32 (Maybe Bit) (RxBit n)
  deriving (Show, Eq, Generic, NFDataX)

data RxBit n = RxStartBit | RxDataBit (BitVector n) (Index n) | RxStopBit (BitVector n)
  deriving (Show, Eq, Generic, NFDataX)

deriving instance (KnownNat n, 1 <= n) => BitPack (TxBit n)
deriving instance (KnownNat n, 1 <= n) => BitPack (TxState n)
deriving instance (KnownNat n, 1 <= n) => Waveform (TxBit n)
deriving instance (KnownNat n, 1 <= n) => Waveform (TxState n)

deriving instance (KnownNat n, 1 <= n) => BitPack (RxBit n)
deriving instance (KnownNat n, 1 <= n) => BitPack (RxState n)
deriving instance (KnownNat n, 1 <= n) => Waveform (RxBit n)
deriving instance (KnownNat n, 1 <= n) => Waveform (RxState n)

But this will just hang until my laptop run out of memory. Did I misunderstand something and what should I do to get it to work?

I cannot reproduce this myself if I use your definition + copied over retroclash-lib uart.. It finishes fine. Could you upload your project somewhere so I or someone else can check that out?

I am noticing two weird things here:

  • First of all, dumpVCD’s list of trace names to wait for is empty. This should cause it to not evaluate anything, and then error when trying to produce a VCD without signals. I suspect, since it’s apparently not reproducible, something (a debug print statement maybe?) is causing your signal to be evaluated, and thus the trace is getting registered regardless.
  • Secondly, you are trying to trace for 10 million clock cycles. That’s not a timestamp in ps (which would have been 1000 cycles) - its unit is the GCD of the clock periods of all signals being traced (weird, I know, we’re working on completely rewriting dumpVCD and friends) which in a single-domain design amounts to the clock period.

Now, 10 million things should be fine in terms of memory normally, but the system really wasn’t designed for this. Bit in particular uses LUTs in Shockwaves 1.0, which, when evaluated 10 million times, probably takes up a lot of space in memory.

Note that Shockwaves 1.1 (1.1.1 has recently been released) introduces static LUTs i.e. not all values of a signal get translated - the LUT is fully predefined. I doubt you have switched yet, but if you’re creating a large number of Bits, you really should.

(and yes, Bit really doesn’t strictly require a LUT at all, but it’s the easiest way to display undefined as x while also keeping the option to add custom styles for 1 and 0)

Hope this helps!