packages feed

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]
-}
--------------------------------------------------------------------------------