co-feldspar-0.1.0.1: src/Feldspar/Software/Representation.hs
{-# language GADTs #-}
{-# language ConstraintKinds #-}
{-# language TypeOperators #-}
{-# language TypeFamilies #-}
{-# language MultiParamTypeClasses #-}
{-# language FlexibleContexts #-}
{-# language FlexibleInstances #-}
{-# language GeneralizedNewtypeDeriving #-}
{-# language PolyKinds #-}
{-# language DataKinds #-}
module Feldspar.Software.Representation where
import Feldspar.Sugar
import Feldspar.Representation
import Feldspar.Frontend
import Feldspar.Storable
import Feldspar.Array.Buffered (ArraysEq(..))
import Feldspar.Software.Primitive
import Feldspar.Software.Expression hiding (Hint)
import Feldspar.Verify.Monad (Verify)
import qualified Feldspar.Verify.FirstOrder as FO
import qualified Feldspar.Verify.Monad as V
import qualified Feldspar.Verify.SMT as SMT
import qualified Feldspar.Verify.Abstract as A
import Data.Array (Ix)
import Data.Constraint hiding ((\\))
import Data.Function (on)
import Data.Functor.Identity
import Data.Maybe (fromMaybe)
import Data.Ord
import Data.IORef
import Data.Int
import Data.Word
import Data.List (genericTake, (\\), sort, sortBy, group, groupBy, intersect, nub)
import Data.Typeable (Typeable, cast, typeOf)
import Data.Struct
import qualified Data.Map.Strict as Map
import Control.Monad.Reader (ReaderT(..), runReaderT, lift)
-- syntactic.
import Language.Syntactic hiding (Signature, Args)
import Language.Syntactic.Functional hiding (Lam)
import Language.Syntactic.Functional.Tuple
import qualified Language.Syntactic as Syn
-- operational-higher.
import Control.Monad.Operational.Higher as Oper
-- imperative-edsl.
import qualified Language.Embedded.Expression as Imp
import qualified Language.Embedded.Imperative as Imp
import qualified Language.Embedded.Imperative.CMD as Imp
-- hardware-edsl.
import Language.Embedded.Hardware.Command (Signal, Mode)
import qualified Language.Embedded.Hardware.Command as Hard
import qualified Language.Embedded.Hardware.Expression.Represent as Hard
import Prelude hiding ((==))
import qualified Prelude as P
-- hmm!
import Feldspar.Hardware.Frontend (HSig)
--------------------------------------------------------------------------------
-- * Programs.
--------------------------------------------------------------------------------
data AssertCMD fs a
where
Assert :: AssertionLabel
-> exp Bool
-> String
-> AssertCMD (Oper.Param3 prog exp pred) ()
instance Oper.HFunctor AssertCMD
where
hfmap _ (Assert lbl cond msg) = Assert lbl cond msg
instance Oper.HBifunctor AssertCMD
where
hbimap _ g (Assert lbl cond msg) = Assert lbl (g cond) msg
instance Oper.InterpBi AssertCMD IO (Oper.Param1 SoftwarePrimType)
where
interpBi (Assert _ cond msg) = do
cond' <- cond
unless cond' $ error $ "Assertion failed: " ++ msg
instance (Imp.ControlCMD Oper.:<: instr) => Oper.Reexpressible AssertCMD instr env
where
reexpressInstrEnv reexp (Assert lbl cond msg) = do
cond' <- reexp cond
lift $ Imp.assert cond' msg
instance FO.HTraversable AssertCMD
instance FO.Symbol AssertCMD
where
dry (Assert {}) = return ()
--------------------------------------------------------------------------------
data ControlCMD inv fs a
where
If :: exp Bool -> prog () -> prog () ->
ControlCMD inv (Oper.Param3 prog exp pred) ()
While :: Maybe inv -> prog (exp Bool) -> prog () ->
ControlCMD inv (Oper.Param3 prog exp pred) ()
For :: (pred i, Integral i) =>
Maybe inv -> Imp.IxRange (exp i) -> Imp.Val i -> prog () ->
ControlCMD inv (Oper.Param3 prog exp pred) ()
Break :: ControlCMD inv (Oper.Param3 prog exp pred) ()
--
Test :: Maybe (exp Bool) -> String ->
ControlCMD inv (Oper.Param3 prog exp pred) ()
Hint :: pred a => exp a ->
ControlCMD inv (Oper.Param3 prog exp pred) ()
Comment :: String ->
ControlCMD inv (Oper.Param3 prog exp pred) ()
instance Oper.HFunctor (ControlCMD inv)
where
hfmap f ins = runIdentity (FO.htraverse (pure . f) ins)
instance FO.HTraversable (ControlCMD inv)
where
htraverse f (If cond tru fls) = (If cond) <$> f tru <*> f fls
htraverse f (While inv cond body) = (While inv) <$> f cond <*> f body
htraverse f (For inv range val body) = (For inv range val) <$> f body
htraverse _ (Break) = pure Break
htraverse _ (Test cond msg) = pure (Test cond msg)
htraverse _ (Hint val) = pure (Hint val)
htraverse _ (Comment msg) = pure (Comment msg)
--------------------------------------------------------------------------------
-- | Soften the hardware signature of a component into a type that uses the
-- correspoinding data types in software.
type family Soften a where
Soften () = ()
Soften (Hard.Signal a -> b) = Ref (SExp a) -> Soften b
Soften (Hard.Array a -> b) = Arr (SExp a) -> Soften b
-- | Software argument for a hardware component.
data Argument pred a
where
Nil :: Argument pred ()
ARef :: (pred a, Integral a, Hard.PrimType a)
=> Ref (SExp a)
-> Argument pred b
-> Argument pred (Ref (SExp a) -> b)
AArr :: (pred a, Integral a, Hard.PrimType a)
=> Arr (SExp a)
-> Argument pred b
-> Argument pred (Arr (SExp a) -> b)
-- | Software component, consists of a hardware signature and its address.
data Address a = Address String (HSig a)
-- | ...
data MMapCMD fs a
where
MMap :: String
-> HSig a
-> MMapCMD (Param3 prog exp pred) String
Call :: Address a
-> Argument pred (Soften a)
-> MMapCMD (Param3 prog exp pred) ()
instance Oper.HFunctor MMapCMD
where
hfmap f (MMap s sig) = MMap s sig
hfmap f (Call addr arg) = Call addr arg
instance Oper.HBifunctor MMapCMD
where
hbimap g f (MMap s sig) = MMap s sig
hbimap g f (Call addr arg) = Call addr arg
instance (MMapCMD Oper.:<: instr) => Oper.Reexpressible MMapCMD instr env
where
reexpressInstrEnv reexp (MMap s sig) = lift $ singleInj $ MMap s sig
reexpressInstrEnv reexp (Call addr arg) = lift $ singleInj $ Call addr arg
instance Oper.InterpBi MMapCMD IO (Param1 SoftwarePrimType)
where
interpBi = error "todo: interpBi of mmap."
instance FO.HTraversable MMapCMD
instance FO.Symbol MMapCMD
where
dry (MMap s sig) = show <$> FO.fresh
dry (Call addr sig) = return ()
--------------------------------------------------------------------------------
-- | Software instructions.
type SoftwareCMD
-- ^ Computational instructions.
= Imp.RefCMD
Oper.:+: Imp.ControlCMD
Oper.:+: Imp.ArrCMD
-- ^ Software specific instructions.
Oper.:+: Imp.FileCMD
Oper.:+: Imp.PtrCMD
Oper.:+: Imp.C_CMD
-- new stuff
Oper.:+: AssertCMD
Oper.:+: MMapCMD
-- | Monad for building software programs in Feldspar.
newtype Software a = Software { unSoftware :: Program SoftwareCMD (Param2 SExp SoftwarePrimType) a }
deriving (Functor, Applicative, Monad)
--------------------------------------------------------------------------------
-- | Software reference.
newtype Ref a = Ref { unRef :: Struct SoftwarePrimType Imp.Ref (Internal a) }
-- | Software array.
data Arr a = Arr
{ arrOffset :: SExp Index
, arrLength :: SExp Length
, unArr :: Struct SoftwarePrimType (Imp.Arr Index) (Internal a)
}
-- | Immutable software array.
data IArr a = IArr
{ iarrOffset :: SExp Index
, iarrLength :: SExp Length
, unIArr :: Struct SoftwarePrimType (Imp.IArr Index) (Internal a)
}
--------------------------------------------------------------------------------
-- **
--------------------------------------------------------------------------------
instance ArraysEq Arr IArr
where
unsafeArrEq (Arr _ _ arr) (IArr _ _ brr) =
and (zipListStruct sameId arr brr)
where
sameId :: Imp.Arr Index a -> Imp.IArr Index a -> Bool
sameId (Imp.ArrComp a) (Imp.IArrComp b) = a P.== b
sameId _ _ = False
--------------------------------------------------------------------------------
type instance Expr Software = SExp
type instance DomainOf Software = SoftwareDomain
--------------------------------------------------------------------------------
instance (Reference Software ~ Ref, Type SoftwarePrimType a) =>
Storable Software (SExp a)
where
type StoreRep Software (SExp a) = Ref (SExp a)
type StoreSize Software (SExp a) = ()
newStoreRep _ _ = newRef
initStoreRep = initRef
readStoreRep = getRef
unsafeFreezeStoreRep = unsafeFreezeRef
writeStoreRep = setRef
--------------------------------------------------------------------------------