hardware-edsl-0.1.5: src/Language/Embedded/Hardware/Interface/AXI.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module Language.Embedded.Hardware.Interface.AXI (axi_light, AXIPred) where
import Language.Embedded.VHDL (Mode(..))
import Language.Embedded.Hardware.Command.CMD
import Language.Embedded.Hardware.Command.Frontend
import Language.Embedded.Hardware.Interface
import Language.Embedded.Hardware.Expression.Frontend
import Language.Embedded.Hardware.Expression.Represent
import Language.Embedded.Hardware.Expression.Represent.Bit (Bits, Bit, bitFromInteger, ni)
import Control.Monad.Identity (Identity)
import Control.Monad.Operational.Higher hiding (when)
import Data.Constraint (Constraint)
import Data.Typeable
import Data.Int
import Data.Word
import Data.Bits ()
import Data.Ix (Ix)
import GHC.TypeLits
import qualified GHC.Exts as GHC (Constraint)
import Prelude hiding (not, and, or, div, null)
import qualified Prelude as P
--------------------------------------------------------------------------------
-- * AXI-light Controller.
--------------------------------------------------------------------------------
-- todo : we make a slight simplification and assume that components which we
-- connect to AXI-lite has a signature of
-- "input -> input -> .. -> input -> output -> ()"
-- this can easily be fixed by inspecting the modes given by the
-- signature.
--------------------------------------------------------------------------------
-- | Short-hand for programs.
type Prog instr exp pred = Program instr (Param2 exp pred)
-- | Short-hand for constraints.
type AXIPred instr exp pred = (
SignalCMD :<: instr
, ArrayCMD :<: instr
, VariableCMD :<: instr
, ConditionalCMD :<: instr
, StructuralCMD :<: instr
, LoopCMD :<: instr
, ComponentCMD :<: instr
, VHDLCMD :<: instr
--
, Expr exp
, Rel exp
, Factor exp
, Primary exp
--
, FreeExp exp
-- todo: this equality might be bad. It should be enough to
-- say that 'PredicateExp' holds, and not that it has
-- to be equal to 'pred'.
, pred ~ PredicateExp exp
, pred (Bit)
, pred (Bits 2)
, pred (Bits 3)
, pred (Bits 4)
, pred (Bits 32)
, pred (Integer)
, Num (exp Integer)
)
--------------------------------------------------------------------------------
-- ** Signature.
--------------------------------------------------------------------------------
axi_light
:: forall instr exp pred sig . AXIPred instr exp pred
=> Comp instr exp pred Identity sig
-> Sig instr exp pred Identity (
Signal Bit -- ^ Global clock signal.
-> Signal Bit -- ^ Global reset signal.
-> Signal (Bits 32) -- ^ Write address.
-> Signal (Bits 3) -- ^ Write channel protection type.
-> Signal Bit -- ^ Write address valid.
-> Signal Bit -- ^ Write address ready.
-> Signal (Bits 32) -- ^ Write data.
-> Signal (Bits 4) -- ^ Write strobes.
-> Signal Bit -- ^ Write valid.
-> Signal Bit -- ^ Write ready.
-> Signal (Bits 2) -- ^ Write response.
-> Signal Bit -- ^ Write response valid.
-> Signal Bit -- ^ Response ready.
-> Signal (Bits 32) -- ^ Read address.
-> Signal (Bits 3) -- ^ Protection type.
-> Signal Bit -- ^ Read address valid.
-> Signal Bit -- ^ Read address ready.
-> Signal (Bits 32) -- ^ Read data.
-> Signal (Bits 2) -- ^ Read response.
-> Signal Bit -- ^ Read valid.
-> Signal Bit -- ^ Read ready.
-> ()
)
axi_light comp =
exactInput "S_AXI_ACLK" $ \s_axi_aclk ->
exactInput "S_AXI_ARESETN" $ \s_axi_aresetn ->
exactInput "S_AXI_AWADDR" $ \s_axi_awaddr ->
exactInput "S_AXI_AWPROT" $ \s_axi_awprot ->
exactInput "S_AXI_AWVALID" $ \s_axi_awvalid ->
exactOutput "S_AXI_AWREADY" $ \s_axi_awready ->
exactInput "S_AXI_WDATA" $ \s_axi_wdata ->
exactInput "S_AXI_WSTRB" $ \s_axi_wstrb ->
exactInput "S_AXI_WVALID" $ \s_axi_wvalid ->
exactOutput "S_AXI_WREADY" $ \s_axi_wready ->
exactOutput "S_AXI_BRESP" $ \s_axi_bresp ->
exactOutput "S_AXI_BVALID" $ \s_axi_bvalid ->
exactInput "S_AXI_BREADY" $ \s_axi_bready ->
exactInput "S_AXI_ARADDR" $ \s_axi_araddr ->
exactInput "S_AXI_ARPROT" $ \s_axi_arprot ->
exactInput "S_AXI_ARVALID" $ \s_axi_arvalid ->
exactOutput "S_AXI_ARREADY" $ \s_axi_arready ->
exactOutput "S_AXI_RDATA" $ \s_axi_rdata ->
exactOutput "S_AXI_RRESP" $ \s_axi_rresp ->
exactOutput "S_AXI_RVALID" $ \s_axi_rvalid ->
exactInput "S_AXI_RREADY" $ \s_axi_rready ->
ret $ axi_light_impl comp
s_axi_aclk s_axi_aresetn
s_axi_awaddr s_axi_awprot s_axi_awvalid s_axi_awready
s_axi_wdata s_axi_wstrb s_axi_wvalid s_axi_wready
s_axi_bresp s_axi_bvalid s_axi_bready
s_axi_araddr s_axi_arprot s_axi_arvalid s_axi_arready s_axi_rdata
s_axi_rresp s_axi_rvalid s_axi_rready
--------------------------------------------------------------------------------
-- ** Implementation.
--------------------------------------------------------------------------------
axi_light_impl
:: forall instr exp pred sig . AXIPred instr exp pred
-- Component to connect:
=> Comp instr exp pred Identity sig
-- AXI signals:
-> Signal Bit -- ^ Global clock signal.
-> Signal Bit -- ^ Global reset signal.
-> Signal (Bits 32) -- ^ Write address.
-> Signal (Bits 3) -- ^ Write channel protection type.
-> Signal Bit -- ^ Write address valid.
-> Signal Bit -- ^ Write address ready.
-> Signal (Bits 32) -- ^ Write data.
-> Signal (Bits 4) -- ^ Write strobes.
-> Signal Bit -- ^ Write valid.
-> Signal Bit -- ^ Write ready.
-> Signal (Bits 2) -- ^ Write response.
-> Signal Bit -- ^ Write response valid.
-> Signal Bit -- ^ Response ready.
-> Signal (Bits 32) -- ^ Read address.
-> Signal (Bits 3) -- ^ Protection type.
-> Signal Bit -- ^ Read address valid.
-> Signal Bit -- ^ Read address ready.
-> Signal (Bits 32) -- ^ Read data.
-> Signal (Bits 2) -- ^ Read response.
-> Signal Bit -- ^ Read valid.
-> Signal Bit -- ^ Read ready.
-> Prog instr exp pred ()
axi_light_impl comp
s_axi_aclk s_axi_aresetn
s_axi_awaddr s_axi_awprot s_axi_awvalid s_axi_awready
s_axi_wdata s_axi_wstrb s_axi_wvalid s_axi_wready
s_axi_bresp s_axi_bvalid s_axi_bready
s_axi_araddr s_axi_arprot s_axi_arvalid s_axi_arready s_axi_rdata
s_axi_rresp s_axi_rvalid s_axi_rready
= do
----------------------------------------
-- AXI Light signals.
--
awaddr <- signal "axi_awaddr" :: Prog instr exp pred (Signal (Bits 32))
awready <- signal "axi_awready" :: Prog instr exp pred (Signal (Bit))
wready <- signal "axi_wready" :: Prog instr exp pred (Signal (Bit))
bresp <- signal "axi_bresp" :: Prog instr exp pred (Signal (Bits 2))
bvalid <- signal "axi_bvalid" :: Prog instr exp pred (Signal (Bit))
araddr <- signal "axi_araddr" :: Prog instr exp pred (Signal (Bits 32))
arready <- signal "axi_arready" :: Prog instr exp pred (Signal (Bit))
rdata <- signal "axi_rdata" :: Prog instr exp pred (Signal (Bits 32))
rresp <- signal "axi_rresp" :: Prog instr exp pred (Signal (Bits 2))
rvalid <- signal "axi_rvalid" :: Prog instr exp pred (Signal (Bit))
----------------------------------------
-- Signals for user logic registers.
--
reg_rden <- signal "slv_reg_rden" :: Prog instr exp pred (Signal (Bit))
reg_wren <- signal "slv_reg_wren" :: Prog instr exp pred (Signal (Bit))
reg_out <- signal "reg_data_out" :: Prog instr exp pred (Signal (Bits 32))
reg_index <- signal "byte_index" :: Prog instr exp pred (Signal (Integer))
registers <- declareRegisters (signatureOf comp)
----------------------------------------
-- Short-hands for ...
--
-- > reset all input registers.
let mReset = resetInputs (signatureOf comp) registers
-- > reload all input registers.
let mReload = reloadInputs (signatureOf comp) registers
-- > fetch the names of all input registers.
let mInputs = identInputs (signatureOf comp) registers
-- > write to output.
let mWrite :: Prog instr exp pred ()
mWrite = loadOutputs araddr reg_out
(signatureOf comp)
(registers)
-- > read from input.
let mRead :: Prog instr exp pred ()
mRead = loadInputs awaddr reg_wren s_axi_wdata s_axi_wstrb
(signatureOf comp)
(registers)
----------------------------------------
-- I/O Connections.
--
s_axi_awready <=- awready
s_axi_wready <=- wready
s_axi_bresp <=- bresp
s_axi_bvalid <=- bvalid
s_axi_arready <=- arready
s_axi_rdata <=- rdata
s_axi_rresp <=- rresp
s_axi_rvalid <=- rvalid
----------------------------------------
-- Mem. mapped register select and write
-- logic generation.
--
u_wr <- unsafeFreezeSignal wready
u_wv <- unsafeFreezeSignal s_axi_wvalid
u_awr <- unsafeFreezeSignal awready
u_awv <- unsafeFreezeSignal s_axi_awvalid
concurrentSetSignal reg_wren
(u_wr `and` u_wv `and` u_awr `and` u_awv)
----------------------------------------
-- Mem. mapped register select and read
-- logic generation.
--
u_arr <- unsafeFreezeSignal arready
u_arv <- unsafeFreezeSignal s_axi_arvalid
u_rv <- unsafeFreezeSignal rvalid
concurrentSetSignal reg_rden
(u_arr `and` u_arv `and` not u_rv)
----------------------------------------
-- AXI_AWREADY generation.
--
process (s_axi_aclk .: []) (do
whenRising s_axi_aclk s_axi_aresetn
(do awready <== low)
(do rdy <- getSignal awready
awv <- getSignal s_axi_awvalid
wv <- getSignal s_axi_wvalid
iff (isLow rdy `and` isHigh awv `and` isHigh wv)
(do awready <== high)
(do awready <== low)))
----------------------------------------
-- AXI_AWADDR latching.
--
process (s_axi_aclk .: []) (do
whenRising s_axi_aclk s_axi_aresetn
(do awaddr <== zeroes)
(do rdy <- getSignal awready
awv <- getSignal s_axi_awvalid
wv <- getSignal s_axi_wvalid
when (isLow rdy `and` isHigh awv `and` isHigh wv)
(awaddr <=- s_axi_awaddr)))
----------------------------------------
-- AXI_WREADY generation.
--
process (s_axi_aclk .: []) (do
whenRising s_axi_aclk s_axi_aresetn
(do wready <== low)
(do rdy <- getSignal awready
awv <- getSignal s_axi_awvalid
wv <- getSignal s_axi_wvalid
iff (isLow rdy `and` isHigh awv `and` isHigh wv)
(wready <== high)
(wready <== low)))
----------------------------------------
-- Slave register logic.
--
process (s_axi_aclk .: []) (do
whenRising s_axi_aclk s_axi_aresetn
mReset
mRead)
----------------------------------------
-- Write response logic.
--
process (s_axi_aclk .: []) (do
whenRising s_axi_aclk s_axi_aresetn
(do bvalid <== low
bresp <== zeroes)
(do awr <- getSignal awready
awv <- getSignal s_axi_awvalid
wr <- getSignal wready
wv <- getSignal s_axi_wvalid
bv <- getSignal bvalid
br <- getSignal s_axi_bready
ifE ((isHigh awr `and` isHigh awv
`and` isHigh wr
`and` isHigh wv
`and` isLow bv),
do bvalid <== high
bresp <== zeroes)
((isHigh br `and` isHigh bv),
do bvalid <== low)))
----------------------------------------
-- AXI_AWREADY generation.
--
process (s_axi_aclk .: []) (do
whenRising s_axi_aclk s_axi_aresetn
(do arready <== low
araddr <== ones)
(do arr <- getSignal arready
arv <- getSignal s_axi_arvalid
iff (isLow arr `and` isHigh arv)
(do arready <== high
araddr <=- s_axi_araddr)
(do arready <== low)))
----------------------------------------
-- AXI_ARVALID generation.
--
process (s_axi_aclk .: []) (do
whenRising s_axi_aclk s_axi_aresetn
(do rvalid <== low
rresp <== zeroes)
(do arr <- getSignal arready
arv <- getSignal s_axi_arvalid
rv <- getSignal rvalid
rr <- getSignal s_axi_rready
ifE ((isHigh arr `and` isHigh arv),
do rvalid <== high
rresp <== zeroes)
((isHigh rv `and` isHigh rr),
do rvalid <== low)))
----------------------------------------
-- Memory mapped rigister select and
-- read logic generaiton.
--
process (araddr .: s_axi_aresetn .: reg_rden .: mInputs) (do
mWrite)
----------------------------------------
-- Output register of memory read data.
--
process (s_axi_aclk .: []) (do
whenRising s_axi_aclk s_axi_aresetn
(do rdata <== zeroes)
(do rden <- getSignal reg_rden
when (isHigh rden)
(do rdata <=- reg_out)))
----------------------------------------
-- User logic.
--
portmap comp registers
--
-- The end.
----------------------------------------
where
-- Application-specific design signals.
addr_lsb, addr_bits :: Integer
addr_lsb = 2
addr_bits = 2 + 1
--addr_lsb + (widthOf comp)
--------------------------------------------------------------------------------
-- ** Helpers.
--------------------------------------------------------------------------------
-- | Declare the registers which will be used by our AXI-lite slave to store
-- values received from the master and, once filled, as input for the comp.
declareRegisters :: forall instr (exp :: * -> *) pred m a . AXIPred instr exp pred
=> Sig instr exp pred Identity a
-> Prog instr exp pred (Argument pred a)
declareRegisters (Ret _) = return Nil
declareRegisters (SSig _ _ sf) =
do s <- newSignal
a <- declareRegisters (sf s)
return (ASig s a)
declareRegisters (SArr _ _ l af) =
do s <- newArray (litE l)
a <- declareRegisters (af s)
return (AArr s a)
--------------------------------------------------------------------------------
-- | Reset the input registers.
resetInputs :: forall instr (exp :: * -> *) pred m a . AXIPred instr exp pred
=> Sig instr exp pred Identity a
-> Argument pred a
-> Prog instr exp pred ()
resetInputs (Ret _) (Nil) = return ()
resetInputs (SSig _ Out sf) (ASig s arg) = resetInputs (sf s) arg
resetInputs (SArr _ Out _ af) (AArr a arg) = resetInputs (af a) arg
resetInputs (SSig _ In sf) (ASig s arg) =
do setSignal s (litE reset)
resetInputs (sf s) arg
resetInputs (SArr _ In _ af) (AArr a arg) =
do resetArray a (litE reset)
resetInputs (af a) arg
--------------------------------------------------------------------------------
-- | Reset the input registers to their previous values.
reloadInputs :: forall instr (exp :: * -> *) pred m a . AXIPred instr exp pred
=> Sig instr exp pred Identity a
-> Argument pred a
-> Prog instr exp pred ()
reloadInputs (Ret _) (Nil) = return ()
reloadInputs (SSig _ Out sf) (ASig s arg) = reloadInputs (sf s) arg
reloadInputs (SArr _ Out _ af) (AArr a arg) = reloadInputs (af a) arg
reloadInputs (SSig _ In sf) (ASig s arg) =
do sv <- unsafeFreezeSignal s
setSignal s sv
reloadInputs (sf s) arg
reloadInputs (SArr _ In l af) (AArr a arg) =
do copyArray (a, litE 0) (a, litE 0) (litE l)
reloadInputs (af a) arg
--------------------------------------------------------------------------------
-- | ...
loadInputs :: forall instr (exp :: * -> *) pred a . AXIPred instr exp pred
=> Signal (Bits 32) -- ^ Address.
-> Signal (Bit) -- ^ Ready.
-> Signal (Bits 32) -- ^ Input.
-> Signal (Bits 4) -- ^ Protected bits.
-> Sig instr exp pred Identity a
-> Argument pred a
-> Prog instr exp pred ()
loadInputs waddr rwren wdata wren sig arg =
do loc <- getBits waddr addr_lsb addr_msb
ready <- getSignal rwren
when (isHigh ready) $
switched loc
(cases 0 sig arg)
(reloadInputs sig arg)
where
cases :: Integer
-> Sig instr exp pred Identity b
-> Argument pred b
-> [When Integer (Prog instr exp pred)]
cases ix (Ret _) (Nil) = []
cases ix (SArr _ _ l af) (AArr a arg) = error "axi-todo: loading arrays."
cases ix (SSig _ Out sf) (ASig s arg) = cases (ix+1) (sf s) arg
cases ix (SSig _ In sf) (ASig s arg) =
is (ix) (loadInputSignal wdata wren s) : cases (ix+1) (sf s) arg
addr_lsb, addr_msb :: exp Integer
addr_lsb = litE 2
addr_msb = litE 3
loadInputSignal :: forall instr (exp :: * -> *) pred a .
(AXIPred instr exp pred, pred a, Sized a)
=> Signal (Bits 32)
-> Signal (Bits 4)
-> Signal a
-> Prog instr exp pred ()
loadInputSignal wdata wren reg = for 0 size $ \byte_index ->
do bit <- getBit wren byte_index
when (isHigh bit) $
copyBits (reg, byte_index*8) (wdata, byte_index*8) (litE 7)
where
size :: exp Integer
size = litE $ (P.div (bits reg) 8) - 1
-- todo: I assume that `a` has a type \width\ that is some multiple of eight,
-- hence the hard-coded seven when copying.
--------------------------------------------------------------------------------
-- | ...
loadOutputs :: forall instr (exp :: * -> *) pred a . AXIPred instr exp pred
=> Signal (Bits 32) -- ^ Address.
-> Signal (Bits 32) -- ^ Output.
-> Sig instr exp pred Identity a
-> Argument pred a
-> Prog instr exp pred ()
loadOutputs araddr rout sig arg =
do loc <- getBits araddr addr_lsb addr_msb
switched loc
(cases 0 sig arg)
(setSignal rout (litE reset))
where
cases :: Integer
-> Sig instr exp pred Identity b
-> Argument pred b
-> [When Integer (Prog instr exp pred)]
cases ix (Ret _) (Nil) = []
cases ix (SArr _ _ l af) (AArr a arg) = error "axi-todo: loading arrays."
cases ix (SSig _ Out sf) (ASig s arg) = cases (ix+1) (sf s) arg
cases ix (SSig _ In sf) (ASig s arg) =
is (ix) (loadOutputSignal rout s) : cases (ix+1) (sf s) arg
addr_lsb, addr_msb :: exp Integer
addr_lsb = litE 2
addr_msb = litE 3
loadOutputSignal :: forall instr (exp :: * -> *) pred a .
(AXIPred instr exp pred, pred a, PrimType a, Integral a)
=> Signal (Bits 32)
-> Signal a
-> Prog instr exp pred ()
loadOutputSignal rout reg =
do r <- unsafeFreezeSignal reg
setSignal rout (toBits r :: exp (Bits 32))
--------------------------------------------------------------------------------
identInputs :: forall instr (exp :: * -> *) pred m a .
Sig instr exp pred m a
-> Argument pred a
-> [Ident]
identInputs (Ret _) (Nil) = []
identInputs (SSig _ In sf) (ASig s arg) = toIdent s : identInputs (sf s) arg
identInputs (SSig _ _ sf) (ASig s arg) = identInputs (sf s) arg
identInputs (SArr _ In _ af) (AArr a arg) = toIdent a : identInputs (af a) arg
identInputs (SArr _ _ _ af) (AArr a arg) = identInputs (af a) arg
--------------------------------------------------------------------------------
signatureOf :: Comp instr exp pred m a -> Sig instr exp pred m a
signatureOf (Component _ sig) = sig
widthOf :: Comp instr exp pred m a -> Integer
widthOf = go . signatureOf
where
go :: Sig instr exp pred m b -> Integer
go (Ret _) = 0
go (SSig _ _ f) = 1 + go (f dummy)
-- go (SArr _ _ l g) = l + go (g dummy)
dummy :: a
dummy = error "todo: evaluated dummy"
high, low :: Expr exp => exp Bit
high = true
low = false
isHigh, isLow :: (Expr exp, Rel exp) => exp Bit -> exp Bit
isHigh e = e `eq` high
isLow e = e `eq` low
zeroes :: (Primary exp, Typeable n, KnownNat n) => exp (Bits n)
zeroes = value 0
ones :: forall exp n. (Primary exp, Typeable n, KnownNat n) => exp (Bits n)
ones = value $ bitFromInteger (read (replicate size '1') :: Integer)
where size = fromIntegral (ni (Proxy::Proxy n)) - 1
--------------------------------------------------------------------------------
-- Program stubs.
--------------------------------------------------------------------------------
{-
loadInputs wdata wren tmp i (SSig _ In sf) (ASig s arg) =
When (Is i) cases : loadInputs wdata wren tmp (i+1) (sf s) arg
where
size :: Integer
size = bits s
loadBit :: Prog instr exp pred ()
loadBit = do
wb <- getBit wren (0 :: exp Integer)
undefined
when (isHigh wb) $
do bit <- getBit wdata (0 :: exp Integer)
setBit s (0 :: exp Integer) bit
loadBits :: Integer -> Integer -> Prog instr exp pred ()
loadBits ix len = do
wb <- getBit wren (value ix)
undefined
when (isHigh wb) $
copyBits (s, value $ ix*8) (wdata, value $ ix*8) (value $ len-1)
cases :: Prog instr exp pred ()
cases | size == 1 = loadBit
| otherwise = sequence_ $ map (uncurry loadBits) $ zip [0..] $ chunk size
loadInputs wdata wren tmp i (SArr _ Out l af) (AArr a arg) =
loadInputs wdata wren tmp (i+(Prelude.toInteger l)) (af a) arg
loadInputs wdata wren tmp i (SArr _ In l af) (AArr (a :: Array i b) arg)
let cs = map (\ix -> When (Is $ i+ix) $ cases ix) [0..l'-1]
in cs ++ loadInputs wdata wren tmp (i+l') (af a) arg
where
l', size :: Integer
l' = Prelude.toInteger l
size = bits a
loadBit :: Integer -> Prog instr exp pred ()
loadBit ax = error "axi-todo: loadBit for array."
loadBits :: Integer -> Integer -> Integer -> Prog instr exp pred ()
loadBits ax ix len = do
wb <- getBit wren (value ix)
when (isHigh wb) $
copyVBits (tmp, value $ ix*8) (wdata, value $ ix*8) (value $ len-1)
cases :: Integer -> Prog instr exp pred ()
cases ax | size == 1 = loadBit ax
| otherwise = do
sequence_ $ map (uncurry $ loadBits ax) $ zip [0..] $ chunk size
val :: exp (Bits 32) <- unsafeFreezeVariable tmp
let ix = litE (fromInteger ax) :: exp i
let b = fromBits val :: exp b
undefined --setArray a ix b
-}
{-
loadOutputs o i (Ret _) (Nil) = []
loadOutputs o i (SSig _ Out sf) (ASig s arg) =
let p = setSignal o . toBits =<< unsafeFreezeSignal s
in When (Is i) p : loadOutputs o (i+1) (sf s) arg
loadOutputs o i (SSig _ _ sf) (ASig s arg) =
loadOutputs o (i+1) (sf s) arg
loadOutputs o i (SArr _ Out l af) (AArr a arg) =
let f ix = When (Is ix) (setSignal o . toBits =<< getArray a (value ix))
in map f [i..i+l-1] ++ loadOutputs o (i+l) (af a) arg
loadOutputs o i (SArr _ _ l af) (AArr a arg) =
loadOutputs o (i+l) (af a) arg
chunk :: Integer -> [Integer]
chunk i | i > 8 = 8 : chunk (i - 8)
| i <= 8 = [i]
-}
--------------------------------------------------------------------------------