packages feed

retroclash-lib-0.1.2.2: src/RetroClash/Delayed.hs

{-# LANGUAGE RecordWildCards, RankNTypes #-}
module RetroClash.Delayed
    ( delayVGA

    , delayedRom
    , delayedRam
    , delayedBlockRam1
    , sharedDelayed
    , sharedDelayedRW

    , delayedRegister
    , liftD
    , liftD2
    , matchDelay
    )
    where

import Clash.Prelude
import qualified Clash.Signal.Delayed.Bundle as D
import RetroClash.VGA
import RetroClash.Utils (enable, guardA, muxA, (.<|))
import Data.Maybe
import Control.Monad (mplus)

delayVGA
    :: (KnownNat d, KnownNat r, KnownNat g, KnownNat b)
    => (HiddenClockResetEnable dom)
    => VGASync dom
    -> DSignal dom d (Unsigned r, Unsigned g, Unsigned b)
    -> VGAOut dom r g b
delayVGA VGASync{..} rgb = vgaOut vgaSync' (toSignal rgb)
  where
    vgaSync' = VGASync
        { vgaHSync = matchDelay rgb undefined vgaHSync
        , vgaVSync = matchDelay rgb undefined vgaVSync
        , vgaDE = matchDelay rgb False vgaDE
        }

matchDelay
    :: (KnownNat d, NFDataX a, HiddenClockResetEnable dom)
    => DSignal dom d any
    -> a
    -> Signal dom a
    -> Signal dom a
matchDelay ref x0 = toSignal . (ref *>) . delayI x0 . fromSignal

delayedRam
    :: (HiddenClockResetEnable dom)
    => (forall dom'. (HiddenClockResetEnable dom') => Signal dom' addr -> Signal dom' wr -> Signal dom' a)
    -> DSignal dom d addr
    -> DSignal dom d wr
    -> DSignal dom (d + 1) a
delayedRam syncRam addr write = unsafeFromSignal $ syncRam (toSignal addr) (toSignal write)

delayedRom
    :: (HiddenClockResetEnable dom)
    => (forall dom'. (HiddenClockResetEnable dom') => Signal dom' addr -> Signal dom' a)
    -> DSignal dom d addr
    -> DSignal dom (d + 1) a
delayedRom syncRom addr = unsafeFromSignal $ syncRom (toSignal addr)

delayedBlockRam1
    :: (1 <= n, Enum addr, NFDataX addr, NFDataX a, HiddenClockResetEnable dom)
    => ResetStrategy r
    -> SNat n
    -> a
    -> DSignal dom d addr
    -> DSignal dom d (Maybe (addr, a))
    -> DSignal dom (d + 1) a
delayedBlockRam1 resetStrat size content = delayedRam (blockRam1 resetStrat size content)

delayedRegister
    :: (NFDataX a, HiddenClockResetEnable dom)
    => a
    -> (DSignal dom d a -> DSignal dom d a)
    -> DSignal dom (d + 1) a
delayedRegister initial feedback = r
  where
    r = unsafeFromSignal $ register initial $ toSignal new
    old = antiDelay (SNat @1) r
    new = feedback old

liftD
    :: (HiddenClockResetEnable dom)
    => (forall dom'. (HiddenClockResetEnable dom') => Signal dom' a -> Signal dom' b)
    -> DSignal dom d a -> DSignal dom d b
liftD f = unsafeFromSignal . f . toSignal

liftD2
    :: (HiddenClockResetEnable dom)
    => (forall dom'. (HiddenClockResetEnable dom') => Signal dom' a -> Signal dom' b -> Signal dom' c)
    -> DSignal dom d a -> DSignal dom d b -> DSignal dom d c
liftD2 f x y = unsafeFromSignal $ f (toSignal x) (toSignal y)

sharedDelayed
    :: (KnownNat k, KnownNat n, HiddenClockResetEnable dom)
    => (DSignal dom d (Maybe addr) -> DSignal dom (d + k) a)
    -> Vec (n + 1) (DSignal dom d (Maybe addr))
    -> Vec (n + 1) (DSignal dom (d + k) (Maybe a))
sharedDelayed mem reqs = reads
  where
    addrs = snd $ mapAccumL step (pure True) reqs
      where
        step en addr = (en .&&. isNothing <$> addr, guardA en addr)

    addr = muxA addrs

    read = mem addr
    reads = map (\addr -> enable (delayI False $ isJust <$> addr) read) addrs

sharedDelayedRW
    :: (KnownNat k, KnownNat n, HiddenClockResetEnable dom)
    => (DSignal dom d addr -> DSignal dom d (Maybe wr) -> DSignal dom (d + k) a)
    -> Vec (n + 1) (DSignal dom d (Maybe (addr, Maybe wr)))
    -> Vec (n + 1) (DSignal dom (d + k) (Maybe a))
sharedDelayedRW ram = sharedDelayed $ uncurry ram . D.unbundle . (.<| (undefined, Nothing))