{-# LANGUAGE ApplicativeDo #-}
{-# OPTIONS_GHC -fconstraint-solver-iterations=10 #-}
module Protocols.Experimental.Wishbone.Standard where
import Clash.Prelude
import Data.Bifunctor qualified as B
import Protocols
import Protocols.Experimental.Wishbone
import Prelude hiding (head, not, repeat, (!!), (&&), (||))
roundrobin ::
forall n dom addressBits dataBytes.
( KnownNat n
, HiddenClockResetEnable dom
, KnownNat addressBits
, KnownNat dataBytes
, 1 <= n
) =>
Circuit
(Wishbone dom 'Standard addressBits dataBytes)
(Vec n (Wishbone dom 'Standard addressBits dataBytes))
roundrobin = Circuit $ \(m2s, s2ms) -> B.first head $ fn (singleton m2s, s2ms)
where
Circuit fn = sharedBus selectFn
selectFn (unbundle -> (mIdx, sIdx, _)) =
liftA2 (,) mIdx (satSucc SatWrap <$> sIdx)
sharedBus ::
forall n m dom addressBits dataBytes.
( KnownNat n
, KnownNat m
, HiddenClockResetEnable dom
, KnownNat addressBits
, KnownNat dataBytes
) =>
( Signal
dom
( Index n
, Index m
, Vec n (WishboneM2S addressBits dataBytes)
) ->
Signal dom (Index n, Index m)
) ->
Circuit
(Vec n (Wishbone dom 'Standard addressBits dataBytes))
(Vec m (Wishbone dom 'Standard addressBits dataBytes))
sharedBus selectFn = Circuit go
where
go (bundle -> m2ss0, bundle -> s2ms0) = (unbundle s2ms1, unbundle m2ss1)
where
mIdx0 = regEn (0 :: Index n) acceptIds mIdx1
sIdx0 = regEn (0 :: Index m) acceptIds sIdx1
(mIdx1, sIdx1) = unbundle $ selectFn (liftA3 (,,) mIdx0 sIdx0 m2ss0)
m2s = liftA2 (!!) m2ss0 mIdx0
s2m = liftA2 (!!) s2ms0 sIdx0
acceptIds = (not . busCycle <$> m2s) .&&. (not . lock <$> m2s)
m2ss1 = liftA3 replace sIdx0 m2s $ pure (repeat emptyWishboneM2S)
s2ms1 = liftA3 replace mIdx0 s2m $ pure (repeat emptyWishboneS2M)
crossbarSwitch ::
forall n m dom addressBits dataBytes.
( KnownNat n
, KnownNat m
, KnownDomain dom
, KnownNat addressBits
, KnownNat dataBytes
) =>
Circuit
( CSignal dom (Vec n (Index m))
, Vec n (Wishbone dom 'Standard addressBits dataBytes)
)
(Vec m (Wishbone dom 'Standard addressBits dataBytes))
crossbarSwitch = Circuit go
where
go ((route, bundle -> m2ss0), bundle -> s2ms0) =
(((), unbundle s2ms1), unbundle m2ss1)
where
m2ss1 = scatter @_ @_ @_ @_ @0 (repeat emptyWishboneM2S) <$> route <*> m2ss0
s2ms1 = gather <$> s2ms0 <*> route
data MemoryDelayState = Wait | AckRead
deriving (Generic, NFDataX)
memoryWb ::
forall dom addressBits dataBytes.
( KnownDomain dom
, KnownNat addressBits
, KnownNat dataBytes
, HiddenClockResetEnable dom
) =>
( Signal dom (BitVector addressBits) ->
Signal dom (Maybe (BitVector addressBits, BitVector (dataBytes * 8))) ->
Signal dom (BitVector (dataBytes * 8))
) ->
Circuit (Wishbone dom 'Standard addressBits dataBytes) ()
memoryWb ram = Circuit go
where
go (m2s, ()) = (s2m1, ())
where
(readAddr, write, s2m0) = unbundle $ mealy fsm Wait m2s
s2m1 = (\s2m dat -> s2m{readData = dat}) <$> s2m0 <*> readValue
readValue = ram readAddr write
fsm st (m2s :: WishboneM2S addressBits dataBytes)
| AckRead <- st = (Wait, (0, Nothing, noS2M{acknowledge = True}))
| isError = (Wait, (0, Nothing, noS2M{err = True}))
| isWrite = (Wait, (0, write, noS2M{acknowledge = True}))
| isRead = (AckRead, (m2s.addr, Nothing, noS2M))
| otherwise = (Wait, (0, Nothing, noS2M))
where
noS2M = emptyWishboneS2M :: WishboneS2M dataBytes
managerActive = m2s.busCycle && m2s.strobe
isError = managerActive && (m2s.busSelect /= maxBound)
isWrite = managerActive && m2s.writeEnable
isRead = managerActive && not (m2s.writeEnable)
write = Just (m2s.addr, m2s.writeData)