hardware-edsl 0.1.0.1 → 0.1.2
raw patch · 18 files changed
+3299/−967 lines, 18 filesdep +deepseqdep ~basedep ~language-vhdldep ~operational-alacarte
Dependencies added: deepseq
Dependency ranges changed: base, language-vhdl, operational-alacarte, syntactic
Files
- hardware-edsl.cabal +17/−12
- src/Language/Embedded/Hardware.hs +0/−1
- src/Language/Embedded/Hardware/Command.hs +85/−17
- src/Language/Embedded/Hardware/Command/Backend/VHDL.hs +582/−175
- src/Language/Embedded/Hardware/Command/CMD.hs +521/−114
- src/Language/Embedded/Hardware/Command/Frontend.hs +442/−115
- src/Language/Embedded/Hardware/Expression.hs +4/−1
- src/Language/Embedded/Hardware/Expression/Backend/VHDL.hs +43/−19
- src/Language/Embedded/Hardware/Expression/Frontend.hs +156/−60
- src/Language/Embedded/Hardware/Expression/Represent.hs +148/−115
- src/Language/Embedded/Hardware/Expression/Represent/Bit.hs +338/−0
- src/Language/Embedded/Hardware/Expression/Syntax.hs +62/−57
- src/Language/Embedded/Hardware/Interface.hs +24/−15
- src/Language/Embedded/VHDL.hs +2/−0
- src/Language/Embedded/VHDL/Monad.hs +461/−208
- src/Language/Embedded/VHDL/Monad/Expression.hs +115/−40
- src/Language/Embedded/VHDL/Monad/Type.hs +108/−18
- src/Language/Embedded/VHDL/Monad/Util.hs +191/−0
hardware-edsl.cabal view
@@ -1,5 +1,5 @@ name: hardware-edsl-version: 0.1.0.1+version: 0.1.2 synopsis: Deep embedding of hardware descriptions with code generation. description: Deep embedding of hardware descriptions with code generation. license: BSD3@@ -21,22 +21,25 @@ exposed-modules: Language.Embedded.Hardware, Language.Embedded.Hardware.Expression,- Language.Embedded.Hardware.Expression.Syntax,- Language.Embedded.Hardware.Expression.Represent,+ Language.Embedded.Hardware.Expression.Backend.VHDL, Language.Embedded.Hardware.Expression.Frontend,+ Language.Embedded.Hardware.Expression.Hoist,+ Language.Embedded.Hardware.Expression.Represent,+ Language.Embedded.Hardware.Expression.Represent.Bit,+ Language.Embedded.Hardware.Expression.Syntax,+ Language.Embedded.Hardware.Interface, Language.Embedded.Hardware.Command,+ Language.Embedded.Hardware.Command.Backend.VHDL, Language.Embedded.Hardware.Command.CMD, Language.Embedded.Hardware.Command.Frontend,- Language.Embedded.Hardware.Interface Language.Embedded.VHDL, Language.Embedded.VHDL.Monad, Language.Embedded.VHDL.Monad.Type, Language.Embedded.VHDL.Monad.Expression+ Language.Embedded.VHDL.Monad.Util+-- Language.Embedded.Hardware.Common.AXI - other-modules:- Language.Embedded.Hardware.Expression.Hoist,- Language.Embedded.Hardware.Expression.Backend.VHDL,- Language.Embedded.Hardware.Command.Backend.VHDL+ --other-modules: other-extensions: GADTs,@@ -46,6 +49,7 @@ FlexibleContexts, FlexibleInstances, MultiParamTypeClasses,+ PolyKinds, ScopedTypeVariables, GeneralizedNewtypeDeriving, ConstraintKinds,@@ -54,16 +58,17 @@ UndecidableInstances build-depends:- base >=4.8 && <4.9,+ base >=4.8 && <5, mtl >=2.2 && <2.3, array >=0.5 && <0.6, containers >=0.5 && <0.6, pretty >=1.1 && <1.2, bytestring >=0.10 && <0.11,+ deepseq >=1.4, constraints >=0.6,- syntactic >=3.2,- operational-alacarte >=0.1.1,- language-vhdl >=0.1.2.5+ syntactic >=3.6.1,+ operational-alacarte >=0.2,+ language-vhdl >=0.1.3 hs-source-dirs: src
src/Language/Embedded/Hardware.hs view
@@ -7,4 +7,3 @@ import Language.Embedded.Hardware.Expression import Language.Embedded.Hardware.Command import Language.Embedded.Hardware.Interface-
src/Language/Embedded/Hardware/Command.hs view
@@ -1,12 +1,20 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ConstraintKinds #-} module Language.Embedded.Hardware.Command ( compile , icompile , runIO - , wcompile+ , compileWrap+ , icompileWrap+ , runIOWrap + , VHDL.Mode(..)+ , module CMD , module Language.Embedded.Hardware.Command.CMD , module Language.Embedded.Hardware.Command.Frontend@@ -17,6 +25,7 @@ import Language.Embedded.Hardware.Command.CMD hiding (Signal, Variable, Array) import Language.Embedded.Hardware.Command.Frontend import Language.Embedded.Hardware.Command.Backend.VHDL+import Language.Embedded.Hardware.Interface import Language.Embedded.VHDL (VHDL, prettyVHDL) @@ -25,34 +34,93 @@ import Control.Monad.Operational.Higher +import qualified GHC.Exts as GHC (Constraint)+ -------------------------------------------------------------------------------- -- * Compilation and evaluation. -------------------------------------------------------------------------------- -- | Compile a program to VHDL code represented as a string.-compile :: (Interp instr VHDL, HFunctor instr) => Program instr a -> String+compile :: forall instr (exp :: * -> *) (pred :: * -> GHC.Constraint) a.+ ( Interp instr VHDL (Param2 exp pred)+ , HFunctor instr+ )+ => Program instr (Param2 exp pred) a+ -> String compile = show . prettyVHDL . interpret -- | Compile a program to VHDL code and print it on the screen.-icompile :: (Interp instr VHDL, HFunctor instr) => Program instr a -> IO ()+icompile :: forall instr (exp :: * -> *) (pred :: * -> GHC.Constraint) a.+ ( Interp instr VHDL (Param2 exp pred)+ , HFunctor instr+ )+ => Program instr (Param2 exp pred) a+ -> IO () icompile = putStrLn . compile -- | Run a program in 'IO'.-runIO :: (Interp instr IO, HFunctor instr) => Program instr a -> IO a-runIO = interpret+runIO :: forall instr (exp :: * -> *) (pred :: * -> GHC.Constraint) a+ . ( InterpBi instr IO (Param1 pred)+ , HBifunctor instr+ , EvaluateExp exp+ )+ => Program instr (Param2 exp pred) a+ -> IO a+runIO = interpretBi (return . evalE) -------------------------------------------------------------------------------- --- | Temp.-wcompile :: (Interp instr VHDL, HFunctor instr) => Program instr () -> IO ()-wcompile = putStrLn . show . prettyVHDL . wrap . interpret- where- wrap :: VHDL () -> VHDL ()- wrap v = do- VHDL.entity (VHDL.Ident "empty") (return ())- VHDL.architecture (VHDL.Ident "empty") (VHDL.Ident "behavioural") $- do l <- VHDL.newLabel- s <- snd <$> VHDL.inProcess l [] v- VHDL.addConcurrent $ VHDL.ConProcess s+compileWrap :: forall instr (exp :: * -> *) (pred :: * -> GHC.Constraint) a .+ ( Interp instr VHDL (Param2 exp pred)+ , HFunctor instr+ , ComponentCMD :<: instr+ , StructuralCMD :<: instr+ , SignalCMD :<: instr+ , pred Bool+ )+ => (Signal Bool -> Signal Bool -> Program instr (Param2 exp pred) ())+ -> String+compileWrap = compile . wrap++icompileWrap :: forall instr (exp :: * -> *) (pred :: * -> GHC.Constraint) a.+ ( Interp instr VHDL (Param2 exp pred)+ , HFunctor instr+ , ComponentCMD :<: instr+ , StructuralCMD :<: instr+ , SignalCMD :<: instr+ , pred Bool+ )+ => (Signal Bool -> Signal Bool -> Program instr (Param2 exp pred) ())+ -> IO ()+icompileWrap = icompile . wrap++runIOWrap :: forall instr (exp :: * -> *) (pred :: * -> GHC.Constraint) a+ . ( InterpBi instr IO (Param1 pred)+ , HBifunctor instr+ , EvaluateExp exp+ , ComponentCMD :<: instr+ , StructuralCMD :<: instr+ , SignalCMD :<: instr+ , pred Bool+ )+ => (Signal Bool -> Signal Bool -> Program instr (Param2 exp pred) ())+ -> IO ()+runIOWrap = runIO . wrap++--------------------------------------------------------------------------------++-- | Wrap a hardware program in a architecture/entity pair.+wrap :: forall instr (exp :: * -> *) (pred :: * -> GHC.Constraint) a .+ ( ComponentCMD :<: instr+ , StructuralCMD :<: instr+ , SignalCMD :<: instr+ , pred Bool+ )+ => (Signal Bool -> Signal Bool -> Program instr (Param2 exp pred) ())+ -> Program instr (Param2 exp pred) ()+wrap sf = void $ component $+ namedInput "clk" $ \c ->+ namedInput "rst" $ \r ->+ ret $ process (c .: r .: []) $ sf c r --------------------------------------------------------------------------------
src/Language/Embedded/Hardware/Command/Backend/VHDL.hs view
@@ -1,301 +1,708 @@ {-# LANGUAGE GADTs #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ConstraintKinds #-} -module Language.Embedded.Hardware.Command.Backend.VHDL () where+module Language.Embedded.Hardware.Command.Backend.VHDL (CompileType(..)) where import Control.Monad.Operational.Higher import Language.Embedded.Hardware.Interface import Language.Embedded.Hardware.Expression.Hoist+import Language.Embedded.Hardware.Expression.Represent+import Language.Embedded.Hardware.Expression.Represent.Bit (Bits, ni) import Language.Embedded.Hardware.Command.CMD import Language.Embedded.VHDL (VHDL) import qualified Language.VHDL as V import qualified Language.Embedded.VHDL as V +import Data.Array.IO (freeze)+import Data.List (genericTake)+import Data.Proxy+import Data.Word (Word8) import qualified Data.IORef as IR import qualified Data.Array.IO as IA +import GHC.TypeLits (KnownNat)+ -------------------------------------------------------------------------------- -- * Translation of hardware commands into VHDL. -------------------------------------------------------------------------------- -class ToIdent a- where- toIdent :: a -> V.Identifier+--------------------------------------------------------------------------------+-- ** ... -instance ToIdent String where toIdent = V.Ident-instance ToIdent (Signal a) where toIdent (SignalC i) = V.Ident $ 's' : show i-instance ToIdent (Variable a) where toIdent (VariableC i) = V.Ident $ 'v' : show i-instance ToIdent (Array i a) where toIdent (ArrayC i) = V.Ident $ 'a' : show i+evalEM :: forall exp a . EvaluateExp exp => Maybe (exp a) -> a+evalEM e = maybe (error "empty value") id $ fmap evalE e -compEM :: forall exp a. (PredicateExp exp a, CompileExp exp) => Maybe (exp a) -> VHDL (Maybe V.Expression)+compEM :: forall exp a . CompileExp exp => Maybe (exp a) -> VHDL (Maybe V.Expression) compEM e = maybe (return Nothing) (>>= return . Just) $ fmap compE e -compTM :: forall exp a. (PredicateExp exp a, CompileExp exp) => Maybe (exp a) -> VHDL V.Type-compTM _ = compT (undefined :: exp a)+--------------------------------------------------------------------------------+-- ** ... -evalEM :: forall exp a. (PredicateExp exp a, EvaluateExp exp) => Maybe (exp a) -> a-evalEM e = maybe (error "empty value") (id) $ fmap evalE e+class CompileType ct+ where+ compileType :: ct a => proxy1 ct -> proxy2 a -> VHDL V.Type+ compileLit :: ct a => proxy1 ct -> a -> VHDL V.Expression+ compileBits :: ct a => proxy1 ct -> a -> VHDL V.Expression -freshVar :: forall exp a. (CompileExp exp, PredicateExp exp a) => VHDL (exp a, V.Identifier)-freshVar = do- i <- varE <$> V.freshUnique :: VHDL (exp a)- n <- dig <$> compE i- t <- compT (undefined :: exp a)- V.addLocal $ V.declareVariable n t Nothing- return (i, n)+instance CompileType HType where- -- diggity dig!- dig :: V.Expression -> V.Identifier- dig (V.ENand (V.Relation (V.ShiftExpression (V.SimpleExpression _ (V.Term (V.FacPrim (V.PrimName (V.NSimple i)) _)_)_)_)_)_) = i+ compileType _ = compT+ compileLit _ = return . literal . printVal+ compileBits _ = return . literal . printBits --------------------------------------------------------------------------------++compT :: HType a => proxy a -> VHDL V.Type+compT = declare++compTM :: forall proxy ct exp a . (CompileType ct, ct a) => proxy ct -> Maybe (exp a) -> VHDL V.Type+compTM _ _ = compileType (Proxy::Proxy ct) (Proxy::Proxy a)++compTF :: forall proxy ct exp a b . (CompileType ct, ct a) => proxy ct -> (exp a -> b) -> VHDL V.Type+compTF _ _ = compileType (Proxy::Proxy ct) (Proxy::Proxy a)++compTA :: forall proxy ct array i a . (CompileType ct, ct a) => proxy ct -> V.Range -> array a -> VHDL V.Type+compTA _ range _ =+ do i <- newSym (Base "array")+ t <- compileType (Proxy::Proxy ct) (Proxy::Proxy a)+ let array = V.constrainedArray (ident' i) t range+ s <- V.findType array+ case s of+ Just n -> do return (named n)+ Nothing -> do V.addType array+ return (typed array)+ where+ typed :: V.TypeDeclaration -> V.SubtypeIndication+ typed (V.TDFull (V.FullTypeDeclaration i _)) = named i+ typed (V.TDPartial (V.IncompleteTypeDeclaration i)) = named i++ named :: V.Identifier -> V.SubtypeIndication+ named i = V.SubtypeIndication Nothing (V.TMType (V.NSimple i)) Nothing++--------------------------------------------------------------------------------++proxyE :: exp a -> Proxy a+proxyE _ = Proxy++proxyM :: Maybe (exp a) -> Proxy a+proxyM _ = Proxy++proxyF :: (exp a -> b) -> Proxy a+proxyF _ = Proxy++--------------------------------------------------------------------------------+-- ** ...++newSym :: Name -> VHDL String+newSym (Base n) = V.newSym n+newSym (Exact n) = return n++freshVar :: forall proxy ct exp a . (CompileType ct, ct a)+ => proxy ct -> Name -> VHDL (Val a)+freshVar _ prefix =+ do i <- newSym prefix+ t <- compileType (Proxy::Proxy ct) (Proxy::Proxy a)+ V.variable (ident' i) t Nothing+ return (ValC i)++-------------------------------------------------------------------------------- -- ** Signals. -instance CompileExp exp => Interp (SignalCMD exp) VHDL+instance (CompileExp exp, CompileType ct) => Interp SignalCMD VHDL (Param2 exp ct) where interp = compileSignal -instance EvaluateExp exp => Interp (SignalCMD exp) IO+instance InterpBi SignalCMD IO (Param1 pred) where- interp = runSignal+ interpBi = runSignal -compileSignal :: forall exp a. CompileExp exp => SignalCMD exp VHDL a -> VHDL a-compileSignal (NewSignal clause scope mode exp) =- do v <- compEM exp- t <- compTM exp- i <- SignalC <$> V.freshUnique- let block = V.declareSignal (toIdent i) t v- interface = V.interfaceSignal (toIdent i) mode t v- case scope of- SProcess -> V.addLocal block- SArchitecture -> V.addGlobal block- SEntity -> case clause of- Port -> V.addPort interface- Generic -> V.addGeneric interface+-- todo: is concurrent... really necessary? I think the VHDL monad handle that.+compileSignal :: forall exp ct a. (CompileExp exp, CompileType ct) => SignalCMD (Param3 VHDL exp ct) a -> VHDL a+compileSignal (NewSignal base mode exp) =+ do i <- newSym base+ v <- compEM exp+ t <- compTM (Proxy::Proxy ct) exp+ V.signal (ident' i) mode t v+ return (SignalC i)+compileSignal (GetSignal (SignalC s)) =+ do i <- freshVar (Proxy::Proxy ct) (Base "v")+ V.assignVariable (simple $ ident i) (simple' s) return i-compileSignal (GetSignal s) =- do (v, i) <- freshVar :: VHDL (a, V.Identifier)- e <- compE v- V.addSequential $ V.assignVariable i (lift $ V.PrimName $ V.NSimple $ toIdent s)- return v-compileSignal (SetSignal s exp) =- do V.addSequential =<< V.assignSignalS (toIdent s) <$> compE exp+compileSignal (SetSignal (SignalC s) exp) =+ do e' <- compE exp+ t <- compileType (Proxy::Proxy ct) (proxyE exp)+ V.assignSignal (simple $ ident s) (V.uType e' t) compileSignal (UnsafeFreezeSignal (SignalC s)) =- do return $ varE s+ do return $ ValC s+compileSignal (ConcurrentSetSignal (SignalC s) exp) =+ do e <- compE exp+ V.concurrentSignal (simple $ ident s) e -runSignal :: forall exp prog a. EvaluateExp exp => SignalCMD exp prog a -> IO a-runSignal (NewSignal _ _ _ exp) = fmap SignalE $ IR.newIORef $ evalEM exp-runSignal (GetSignal (SignalE r)) = fmap litE $ IR.readIORef r-runSignal (SetSignal (SignalE r) exp) = IR.writeIORef r $ evalE exp-runSignal (UnsafeFreezeSignal r) = runSignal (GetSignal r)+runSignal :: SignalCMD (Param3 IO IO pred) a -> IO a+runSignal (NewSignal _ _ Nothing) = fmap SignalE $ IR.newIORef (error "uninitialized signal")+runSignal (NewSignal _ _ (Just a)) = fmap SignalE . IR.newIORef =<< a+runSignal (GetSignal (SignalE r)) = fmap ValE $ IR.readIORef r+runSignal (SetSignal (SignalE r) exp) = IR.writeIORef r =<< exp+runSignal x@(UnsafeFreezeSignal r) = runSignal (GetSignal r `asTypeOf` x)+runSignal (ConcurrentSetSignal (SignalE r) exp) =+ error "hardware-edsl.todo: run concurrent signals." -------------------------------------------------------------------------------- -- ** Variables. -instance CompileExp exp => Interp (VariableCMD exp) VHDL+instance (CompileExp exp, CompileType ct) => Interp VariableCMD VHDL (Param2 exp ct) where interp = compileVariable -instance EvaluateExp exp => Interp (VariableCMD exp) IO+instance InterpBi VariableCMD IO (Param1 pred) where- interp = runVariable+ interpBi = runVariable -compileVariable :: forall exp a. CompileExp exp => VariableCMD exp VHDL a -> VHDL a-compileVariable (NewVariable exp) =- do v <- compEM exp- t <- compTM exp- i <- VariableC <$> V.freshUnique- V.addLocal $ V.declareVariable (toIdent i) t v+-- todo: why not initialize variable?+compileVariable :: forall ct exp a. (CompileExp exp, CompileType ct) => VariableCMD (Param3 VHDL exp ct) a -> VHDL a+compileVariable (NewVariable base exp) =+ do i <- newSym base+ v <- compEM exp+ t <- compTM (Proxy::Proxy ct) exp+ V.variable (ident' i) t (Nothing)+ case v of+ Nothing -> return ()+ Just v' -> V.assignVariable (simple $ ident i) (V.uType v' t)+ return (VariableC i)+compileVariable (GetVariable (VariableC var)) =+ do i <- freshVar (Proxy::Proxy ct) (Base "v")+ V.assignVariable (simple $ ident i) (simple' var) return i-compileVariable (GetVariable var) =- do (v, i) <- freshVar :: VHDL (a, V.Identifier)- e <- compE v- V.addSequential $ V.assignVariable i (lift $ V.PrimName $ V.NSimple $ toIdent var)- return v-compileVariable (SetVariable var exp) =- do V.addSequential =<< V.assignVariable (toIdent var) <$> compE exp+compileVariable (SetVariable (VariableC var) exp) =+ do e' <- compE exp+ t <- compileType (Proxy::Proxy ct) (proxyE exp)+ V.assignVariable (simple var) (V.uType e' t) compileVariable (UnsafeFreezeVariable (VariableC v)) =- do return $ varE v+ do return $ ValC v -runVariable :: forall exp prog a. EvaluateExp exp => VariableCMD exp prog a -> IO a-runVariable (NewVariable exp) = fmap VariableE $ IR.newIORef $ evalEM exp-runVariable (GetVariable (VariableE v)) = fmap litE $ IR.readIORef v-runVariable (SetVariable (VariableE v) exp) = IR.writeIORef v $ evalE exp-runVariable (UnsafeFreezeVariable v) = runVariable (GetVariable v)+runVariable :: VariableCMD (Param3 IO IO pred) a -> IO a+runVariable (NewVariable _ Nothing) = fmap VariableE $ IR.newIORef (error "uninitialized variable")+runVariable (NewVariable _ (Just a)) = fmap VariableE . IR.newIORef =<< a+runVariable (GetVariable (VariableE v)) = fmap ValE $ IR.readIORef v+runVariable (SetVariable (VariableE v) exp) = IR.writeIORef v =<< exp+runVariable x@(UnsafeFreezeVariable v) = runVariable (GetVariable v `asTypeOf` x) --------------------------------------------------------------------------------+-- ** Constants.++instance (CompileExp exp, CompileType ct) => Interp ConstantCMD VHDL (Param2 exp ct)+ where+ interp = compileConstant++instance InterpBi ConstantCMD IO (Param1 pred)+ where+ interpBi = runConstant++compileConstant :: forall ct exp a. (CompileExp exp, CompileType ct) => ConstantCMD (Param3 VHDL exp ct) a -> VHDL a+compileConstant (NewConstant base (exp :: exp c)) =+ do i <- newSym base+ v <- compE exp+ t <- compileType (Proxy::Proxy ct) (Proxy::Proxy c)+ V.constant (ident' i) t v+ return (ConstantC i)+compileConstant (GetConstant (ConstantC c)) =+ do return $ ValC c++runConstant :: ConstantCMD (Param3 IO IO pred) a -> IO a+runConstant (NewConstant _ exp) = return . ConstantE =<< exp+runConstant (GetConstant (ConstantE exp)) = return $ ValE exp++-------------------------------------------------------------------------------- -- ** Arrays. -instance (CompileExp exp, EvaluateExp exp, CompArrayIx exp) => Interp (ArrayCMD exp) VHDL+instance (CompileExp exp, CompileType ct) => Interp ArrayCMD VHDL (Param2 exp ct) where interp = compileArray -instance EvaluateExp exp => Interp (ArrayCMD exp) IO+instance InterpBi ArrayCMD IO (Param1 pred) where- interp = runArray+ interpBi = runArray --- *** Signal commands can be both sequential and parallel and I shouldn't--- depend on them always being sequential.-compileArray :: forall exp a. (CompileExp exp, EvaluateExp exp, CompArrayIx exp) => ArrayCMD exp VHDL a -> VHDL a-compileArray (NewArray len) =- do n <- compE len- t <- compTA len (undefined :: a)- a <- freshA- i <- ArrayC <$> V.freshUnique- let range = V.range (lift n) V.downto zero- array = V.constrainedArray a t range- V.addType array- V.addLocal $ V.declareVariable (toIdent i) (typed array) Nothing- return i-compileArray (InitArray is) =- do t <- compTA (undefined :: exp i) (undefined :: a)- a <- freshA- i <- ArrayC <$> V.freshUnique- x <- sequence [compE (litE a :: exp b) | (a :: b) <- is]- let len = V.lit (length is)- range = V.range (lift len) V.downto zero- array = V.constrainedArray a t range- V.addType array- V.addLocal $ V.declareVariable (toIdent i) (typed array) (Just $ lift $ V.aggregate x)- return i-compileArray (GetArray ix arr) =- do (v, i) <- freshVar :: VHDL (a, V.Identifier)+compileArray :: forall ct exp a. (CompileExp exp, CompileType ct) => ArrayCMD (Param3 VHDL exp ct) a -> VHDL a+compileArray (NewArray base len) =+ do i <- newSym base+ l <- compE len+ t <- compTA (Proxy::Proxy ct) (rangeZero l) (undefined :: a)+ V.array (ident' i) V.InOut t Nothing+ return (ArrayC i)+compileArray (InitArray base is) =+ do i <- newSym base+ t <- compTA (Proxy::Proxy ct) (rangePoint (length is - 1)) (undefined :: a)+ x <- mapM (compileBits (Proxy::Proxy ct)) is+ let v = V.aggregate $ V.aggregated x+ V.array (ident' i) V.InOut t (Just $ lift v)+ return (ArrayC i)+compileArray (GetArray (ArrayC s) ix) =+ do i <- freshVar (Proxy::Proxy ct) (Base "a") e <- compE ix- V.addSequential $ V.assignVariable i (lift $ V.PrimName $ V.indexed (toIdent arr) e)- return v-compileArray (SetArray i e arr) =- do i' <- compE i- e' <- compE e- -- this could be concurrent as well.- V.addSequential $ V.assignArray (V.indexed (toIdent arr) i') e'-compileArray (UnsafeGetArray ix arr) =- case compArrayIx ix arr of- Just e -> return e- Nothing -> do- (v, i) <- freshVar :: VHDL (a, V.Identifier)- e <- compE ix- V.addSequential $ V.assignVariable i (lift $ V.PrimName $ V.indexed (toIdent arr) e)- return v+ V.assignVariable (simple $ ident i) (indexed' s e)+ return i+compileArray (SetArray (ArrayC s) ix e) =+ do ix' <- compE ix+ e' <- compE e+ t <- compileType (Proxy::Proxy ct) (proxyE e)+ V.assignArray (indexed s ix') (V.uType e' t)+compileArray (CopyArray (ArrayC a, oa) (ArrayC b, ob) l) =+ do oa' <- compE oa+ ob' <- compE ob+ len <- compE l+ let lower_a = V.add [unpackTerm len, unpackTerm oa']+ lower_b = V.add [unpackTerm len, unpackTerm ob']+ dest = slice a $ range oa' V.downto $ lift $ lower_a+ src = slice' b $ range ob' V.downto $ lift $ lower_b+ V.assignSignal dest src+compileArray (ResetArray (ArrayC a) rst) =+ do rst' <- compE rst+ t <- compileType (Proxy::Proxy ct) (proxyE rst)+ let others = V.aggregate $ V.others (V.uType rst' t)+ V.assignArray (simple a) (lift others) -runArray :: forall exp prog a. EvaluateExp exp => ArrayCMD exp prog a -> IO a-runArray (NewArray len) = fmap ArrayE . IR.newIORef =<< IA.newArray_ (0, evalE len)-runArray (InitArray is) = fmap ArrayE . IR.newIORef =<< IA.newListArray (0, fromIntegral $ length is) is-runArray (GetArray i (ArrayE a)) = do r <- IR.readIORef a; fmap litE $ IA.readArray r (evalE i)-runArray (SetArray i e (ArrayE a)) = do r <- IR.readIORef a; IA.writeArray r (evalE i) (evalE e)-runArray (UnsafeGetArray i a) = runArray (GetArray i a)+runArray :: ArrayCMD (Param3 IO IO pred) a -> IO a+runArray = error "hardware-edsl.todo: run arrays" ------------------------------------------------------------------------------------ | Fresh array type identifier-freshA :: VHDL V.Identifier-freshA = toIdent . ('t' :) . show <$> V.freshUnique+-- ** Virtual Arrays. --- | Compile type of array.-compTA :: forall exp i a. (PredicateExp exp a, CompileExp exp) => exp i -> Array i a -> VHDL V.Type-compTA _ _ = compT (undefined :: exp a)+instance (CompileExp exp, CompileType ct) => Interp VArrayCMD VHDL (Param2 exp ct)+ where+ interp = compileVArray -zero :: V.SimpleExpression-zero = lift (V.lit 0)+instance InterpBi VArrayCMD IO (Param1 pred)+ where+ interpBi = runVArray -typed :: V.TypeDeclaration -> V.SubtypeIndication-typed (V.TDFull (V.FullTypeDeclaration i _)) = named i-typed (V.TDPartial (V.IncompleteTypeDeclaration i)) = named i+compileVArray :: forall ct exp a. (CompileExp exp, CompileType ct) => VArrayCMD (Param3 VHDL exp ct) a -> VHDL a+compileVArray (NewVArray base len) =+ do l <- compE len+ t <- compTA (Proxy::Proxy ct) (rangeZero l) (undefined :: a)+ i <- newSym base+ V.variable (ident' i) t Nothing+ return (VArrayC i)+compileVArray (InitVArray base is) =+ do let r = rangePoint (length is - 1)+ t <- compTA (Proxy::Proxy ct) r (undefined :: a)+ i <- newSym base+ x <- mapM (compileBits (Proxy::Proxy ct)) is+ let v = V.aggregate $ V.aggregated x+ V.variable (ident' i) t (Just $ lift v)+ return (VArrayC i)+compileVArray (GetVArray (VArrayC arr) ix) =+ do i <- freshVar (Proxy::Proxy ct) (Base "a")+ e <- compE ix+ V.assignVariable (simple $ ident i) (indexed' arr e)+ return i+compileVArray (SetVArray a@(VArrayC arr) i e) =+ do i' <- compE i+ e' <- compE e+ t <- compileType (Proxy::Proxy ct) (proxyE e)+ V.assignVariable (indexed arr i') (V.uType e' t)+compileVArray (CopyVArray (VArrayC a, oa) (VArrayC b, ob) l) =+ do oa' <- compE oa+ ob' <- compE ob+ len <- compE l+ let lower_a = V.add [unpackTerm len, unpackTerm oa']+ lower_b = V.add [unpackTerm len, unpackTerm ob']+ dest = slice a $ range oa' V.downto $ lift $ lower_a+ src = slice' b $ range ob' V.downto $ lift $ lower_b+ V.assignVariable dest src+compileVArray (UnsafeFreezeVArray (VArrayC arr)) = return $ IArrayC arr+compileVArray (UnsafeThawVArray (IArrayC arr)) = return $ VArrayC arr -named :: V.Identifier -> V.SubtypeIndication-named i = V.SubtypeIndication Nothing (V.TMType (V.NSimple i)) Nothing+runVArray :: VArrayCMD (Param3 IO IO pred) a -> IO a+runVArray (NewVArray _ len) =+ do len' <- len+ arr <- IA.newArray_ (0, len')+ return (VArrayE arr)+runVArray (InitVArray _ is) =+ do arr <- IA.newListArray (0, fromIntegral $ length is - 1) is+ return (VArrayE arr)+runVArray (GetVArray (VArrayE arr) i) =+ do (l, h) <- IA.getBounds arr+ ix <- i+ if (ix < l || ix > h)+ then error "getArr out of bounds"+ else do v <- IA.readArray arr ix+ return (ValE v)+runVArray (SetVArray (VArrayE arr) i e) =+ do (l, h) <- IA.getBounds arr+ ix <- i+ e' <- e+ if (ix < l || ix > h)+ then error "setArr out of bounds"+ else IA.writeArray arr (fromIntegral ix) e'+runVArray (CopyVArray (VArrayE arr, oa) (VArrayE brr, ob) l) =+ do oa' <- oa+ ob' <- ob+ l' <- l+ (0, ha) <- IA.getBounds arr+ (0, hb) <- IA.getBounds brr+ if (l' > hb + 1 - oa' || l' > ha + 1 - ob')+ then error "copyArr out of bounts"+ else sequence_ [ IA.readArray brr (i+ob') >>= IA.writeArray arr (i+oa')+ | i <- genericTake l' [0..] ]+runVArray (UnsafeFreezeVArray (VArrayE arr)) = IA.freeze arr >>= return . IArrayE+runVArray (UnsafeThawVArray (IArrayE arr)) = IA.thaw arr >>= return . VArrayE -------------------------------------------------------------------------------- -- ** Loops. -instance CompileExp exp => Interp (LoopCMD exp) VHDL+instance (CompileExp exp, CompileType ct) => Interp LoopCMD VHDL (Param2 exp ct) where interp = compileLoop -instance EvaluateExp exp => Interp (LoopCMD exp) IO+instance InterpBi LoopCMD IO (Param1 pred) where- interp = runLoop+ interpBi = runLoop -compileLoop :: forall exp a. CompileExp exp => LoopCMD exp VHDL a -> VHDL a-compileLoop (For r step) =- do hi <- compE r- (v, i) <- freshVar- loop <- V.inFor i (V.range zero V.to (lift hi)) (step v)+compileLoop :: forall ct exp a. (CompileExp exp, CompileType ct) => LoopCMD (Param3 VHDL exp ct) a -> VHDL a+compileLoop (For l u step) =+ do -- *** todo: temp solution, should check if signed and size.+ i <- newSym (Base "l")+ l' <- compE l+ u' <- compE u+ loop <- V.inFor (ident' i) (range l' V.to u') (step (ValC i)) V.addSequential $ V.SLoop $ loop compileLoop (While cont step) = do l <- V.newLabel- loop <- V.inWhile l (Nothing) $+ loop <- V.inWhile l Nothing $ do b <- cont exit <- compE b V.exit l exit step V.addSequential $ V.SLoop $ loop -runLoop :: forall exp prog a. EvaluateExp exp => LoopCMD exp IO a -> IO a-runLoop (For r step) = loop (evalE r)+runLoop :: LoopCMD (Param3 IO IO pred) a -> IO a+runLoop (For l u step) =+ do l' <- l+ u' <- u+ loop l' u' where- loop i | i > 0 = step (litE i) >> loop (i - 1)- | otherwise = return ()+ loop l u | l <= u = step (ValE l) >> loop (l + 1) u+ | otherwise = return () runLoop (While b step) = loop where- loop = b >>= flip when (step >> loop) . evalE+ loop = do e <- join b+ when e (step >> loop) -------------------------------------------------------------------------------- -- ** Conditional. -instance CompileExp exp => Interp (ConditionalCMD exp) VHDL+instance (CompileExp exp, CompileType ct) => Interp ConditionalCMD VHDL (Param2 exp ct) where interp = compileConditional -instance EvaluateExp exp => Interp (ConditionalCMD exp) IO+instance InterpBi ConditionalCMD IO (Param1 pred) where- interp = runConditional+ interpBi = runConditional -compileConditional :: forall exp a. CompileExp exp => ConditionalCMD exp VHDL a -> VHDL a+compileConditional :: forall ct exp a. (CompileExp exp, CompileType ct) => ConditionalCMD (Param3 VHDL exp ct) a -> VHDL a compileConditional (If (a, b) cs em) = do let (es, ds) = unzip cs- el = maybe (return ()) id em+ el = maybe (return ()) id em ae <- compE a ese <- mapM compE es s <- V.inConditional (ae, b) (zip ese ds) el V.addSequential $ V.SIf s+compileConditional (Case e cs d) =+ do let el = maybe (return ()) id d+ ae <- compE e+ ce <- mapM compC cs+ s <- V.inCase ae ce el+ V.addSequential $ V.SCase s+ where+ compC :: ct b => When b VHDL -> VHDL (V.Choices, VHDL ())+ compC (When (Is e) p) = do+ e' <- compileLit (Proxy::Proxy ct) e+ return $ (V.Choices [V.is $ unpackSimple e'], p)+ compC (When (To l h) p) = do+ l' <- compileLit (Proxy::Proxy ct) l+ h' <- compileLit (Proxy::Proxy ct) h+ return $ (V.Choices [V.between $ range l' V.to h'], p)+compileConditional (Null) = V.null -runConditional :: forall exp a. EvaluateExp exp => ConditionalCMD exp IO a -> IO a-runConditional (If (a, b) cs em) = if (evalE a) then b else loop cs+runConditional :: ConditionalCMD (Param3 IO IO pred) a -> IO a+runConditional (If (a, b) cs em) =+ do c <- a+ if c then b else loop cs where- loop [] = maybe (return ()) id em- loop ((c, p):xs) = if (evalE c) then p else (loop xs)+ loop [] = maybe (return ()) id em+ loop ((c, p):xs) = do+ b <- c+ if b then p else (loop xs)+runConditional (Case e cs d) =+ do c <- e+ loop c cs+ where+ loop v [] = maybe (return ()) id d+ loop v ((When (Is u) p):cs) = if v == u then p else loop v cs+ loop v ((When (To l h) p):cs) = if v > l && v < h then p else loop v cs+runConditional (Null) = return () --------------------------------------------------------------------------------+-- ** Components.++instance (CompileExp exp, CompileType ct) => Interp ComponentCMD VHDL (Param2 exp ct)+ where+ interp = compileComponent++instance InterpBi ComponentCMD IO (Param1 pred)+ where+ interpBi = runComponent++compileComponent :: forall ct exp a. (CompileExp exp, CompileType ct) => ComponentCMD (Param3 VHDL exp ct) a -> VHDL a+compileComponent (StructComponent base sig) =+ do comp <- newSym base+ V.component $+ do p <- V.entity (ident' comp) (traverseSig sig)+ V.architecture (ident' comp) (V.Ident "imp") p+ return comp+compileComponent (PortMap (Component name sig) as) =+ do let i = ident' name+ l <- V.newLabel+ vs <- applySig sig as+ V.inheritContext i+ V.declareComponent i vs+ V.portMap l i (assocSig sig as)++runComponent :: ComponentCMD (Param3 IO IO pred) a -> IO a+runComponent = error "hardware-edsl-todo: run components."++--------------------------------------------------------------------------------++traverseSig :: forall ct exp a . (CompileExp exp, CompileType ct) => Signature (Param3 VHDL exp ct) a -> VHDL (VHDL ())+traverseSig (Ret prog) = return prog+traverseSig (SSig n m sf) = + do i <- newSym n+ t <- compTF (Proxy::Proxy ct) sf+ V.signal (ident' i) m t Nothing+ traverseSig (sf (SignalC i))+traverseSig (SArr n m l af) =+ do i <- newSym n+ t <- compTA (Proxy::Proxy ct) (rangePoint l) (proxyF af)+ V.array (ident' i) m t Nothing+ traverseSig (af (ArrayC i))++applySig :: forall ct exp a . (CompileExp exp, CompileType ct)+ => Signature (Param3 VHDL exp ct) a -> Argument ct a+ -> VHDL [V.InterfaceDeclaration]+applySig (Ret _) (Nil) = return []+applySig (SSig n m sf) (ASig s@(SignalC i) v) =+ do t <- compTF (Proxy::Proxy ct) sf+ is <- applySig (sf s) v+ let i = V.InterfaceSignalDeclaration [ident' n] (Just m) t False Nothing+ return (i : is)+applySig (SArr n m l af) (AArr a@(ArrayC i) v) =+ do t <- compTA (Proxy::Proxy ct) (rangePoint l) (proxyF af)+ is <- applySig (af a) v+ let i = V.InterfaceSignalDeclaration [ident' n] (Just m) t False Nothing+ return (i : is)++assocSig :: forall ct exp a . (CompileExp exp, CompileType ct)+ => Signature (Param3 VHDL exp ct) a -> Argument ct a+ -> [(V.Identifier, V.Identifier)]+assocSig (Ret _) (Nil) = []+assocSig (SSig n _ sf) (ASig s@(SignalC i) v) =+ (ident' n, ident' i) : assocSig (sf s) v+assocSig (SArr n _ _ af) (AArr a@(ArrayC i) v) =+ (ident' n, ident' i) : assocSig (af a) v++-------------------------------------------------------------------------------- -- ** Structural. -instance CompileExp exp => Interp (StructuralCMD exp) VHDL+instance (CompileExp exp, CompileType ct) => Interp StructuralCMD VHDL (Param2 exp ct) where interp = compileStructural -instance EvaluateExp exp => Interp (StructuralCMD exp) IO+instance InterpBi StructuralCMD IO (Param1 pred) where- interp = runStructural+ interpBi = runStructural -compileStructural :: forall exp a. CompileExp exp => StructuralCMD exp VHDL a -> VHDL a-compileStructural (Entity e prog) = V.entity (toIdent e) prog-compileStructural (Architecture e a prog) = V.architecture (toIdent e) (toIdent a) prog-compileStructural (Process xs prog) =+compileStructural :: forall ct exp a. (CompileExp exp, CompileType ct) => StructuralCMD (Param3 VHDL exp ct) a -> VHDL a+compileStructural (StructEntity (Exact e) prog) =+ do V.entity (V.Ident e) prog+compileStructural (StructArchitecture (Exact e) (Exact a) prog) =+ do V.architecture (V.Ident e) (V.Ident a) prog+compileStructural (StructProcess xs prog) = do label <- V.newLabel- (a, c) <- V.inProcess label (fmap reveal xs) prog+ (a, c) <- V.inProcess label (fmap (\(Ident i) -> V.Ident i) xs) prog V.addConcurrent (V.ConProcess c) return a++runStructural :: StructuralCMD (Param3 IO IO pred) a -> IO a+runStructural (StructEntity _ prog) = prog+runStructural (StructArchitecture _ _ prog) = prog+runStructural (StructProcess xs prog) =+ do error "hardware-edsl-todo: figure out how to simulate processes in Haskell."++--------------------------------------------------------------------------------+-- ** VHDL.++instance (CompileExp exp, CompileType ct) => Interp VHDLCMD VHDL (Param2 exp ct) where- reveal :: SignalX -> V.Identifier- reveal (SignalX s) = toIdent s+ interp = compileVHDL -runStructural :: forall exp a. EvaluateExp exp => StructuralCMD exp IO a -> IO a-runStructural (Entity _ prog) = prog-runStructural (Architecture _ _ prog) = prog-runStructural (Process xs prog) = error "todo: run process"+instance InterpBi VHDLCMD IO (Param1 pred)+ where+ interpBi = runVHDL +compileVHDL :: forall ct exp a. (CompileExp exp, CompileType ct) => VHDLCMD (Param3 VHDL exp ct) a -> VHDL a+compileVHDL (Rising (SignalC clk) (SignalC rst) tru fls) =+ do let condC = V.function (simple "rising_edge") [simple' clk]+ condR = V.eq (unpackShift $ simple' rst) (unpackShift $ literal "'0'")+ clock <- V.inConditional (lift condC,+ do reset <- V.inConditional (lift condR, tru) [] (fls)+ V.addSequential $ V.SIf $ reset+ ) [] (return ())+ V.addSequential $ V.SIf $ clock+compileVHDL (CopyBits ((SignalC a), oa) ((SignalC b), ob) l) =+ do oa' <- compE oa+ ob' <- compE ob+ len <- compE l+ let lower_a = V.add [unpackTerm len, unpackTerm oa']+ lower_b = V.add [unpackTerm len, unpackTerm ob']+ dest = slice a $ range oa' V.downto $ lift $ lower_a+ src = slice' b $ range ob' V.downto $ lift $ lower_b+ V.assignSignal dest src+compileVHDL (CopyVBits ((VariableC a), oa) ((SignalC b), ob) l) =+ do oa' <- compE oa+ ob' <- compE ob+ len <- compE l+ let lower_a = V.add [unpackTerm len, unpackTerm oa']+ lower_b = V.add [unpackTerm len, unpackTerm ob']+ dest = slice a $ range oa' V.downto $ lift $ lower_a+ src = slice' b $ range ob' V.downto $ lift $ lower_b+ V.assignVariable dest src+compileVHDL (GetBit (SignalC bits) ix) =+ do i <- freshVar (Proxy::Proxy ct) (Base "b")+ ix' <- compE ix+ V.assignVariable (simple $ ident i) (indexed' bits ix')+ return i+compileVHDL (SetBit s@(SignalC bits) ix bit) =+ do ix' <- compE ix+ bit' <- compE bit+ t <- compileType (Proxy::Proxy ct) (proxyE s)+ case V.isBit t of+ True -> V.assignSignal (simple bits) (bit')+ False -> V.assignArray (indexed bits ix') (bit')+compileVHDL (GetBits (SignalC bits) l u) =+ do i <- freshVar (Proxy::Proxy ct) (Base "b")+ l' <- compE l+ u' <- compE u+ -- todo: this wrap around.+ V.assignVariable (simple $ ident i)+ ( lift $ V.toInteger $+ lift $ V.asSigned $+ slice' bits $+ range l' V.downto u')+ return i++runVHDL :: VHDLCMD (Param3 IO IO pred) a -> IO a+runVHDL = error "hardware-edsl.runVHDL: todo."++--------------------------------------------------------------------------------+-- Helpers.+--+-- todo : make a lift that first tries to go backwards. If that's not possible,+-- perform a regular lift. This should get rid of most extra parenthesis.++ident :: ToIdent a => a -> String+ident a = let (Ident s) = toIdent a in s++ident' :: ToIdent a => a -> V.Identifier+ident' a = V.Ident $ ident a++-- todo: this... why does this work?+instance ToIdent String where toIdent = Ident+instance ToIdent Ident where toIdent = id+instance ToIdent Name where+ toIdent (Base s) = Ident s+ toIdent (Exact s) = Ident s++--------------------------------------------------------------------------------++simple :: String -> V.Name+simple s = V.simple s++simple' :: String -> V.Expression+simple' s = lift $ V.name $ simple s++indexed :: String -> V.Expression -> V.Name+indexed s = V.indexed $ V.simple s++indexed' :: String -> V.Expression -> V.Expression+indexed' s = lift . V.name . indexed s++slice :: String -> V.Range -> V.Name+slice s = V.slice $ V.simple s++slice' :: String -> V.Range -> V.Expression+slice' s = lift . V.name . slice s++--------------------------------------------------------------------------------++literal :: String -> V.Expression+literal s = lift $ V.literal $ V.number s++--------------------------------------------------------------------------------++range :: V.Expression -> V.Direction -> V.Expression -> V.Range+range l dir r = V.range (unpackSimple l) dir (unpackSimple r)++rangeZero :: V.Expression -> V.Range+rangeZero l = V.range (unpackSimple l) V.downto (V.point 0)++rangePoint :: Integral a => a -> V.Range+rangePoint a = V.range (V.point $ toInteger a) V.downto (V.point 0)++--------------------------------------------------------------------------------+-- ...++unpackShift :: V.Expression -> V.ShiftExpression+unpackShift (V.ENand (V.Relation s Nothing) Nothing) = s+unpackShift e = lift e++unpackSimple :: V.Expression -> V.SimpleExpression+unpackSimple (V.ENand (V.Relation (V.ShiftExpression s Nothing) Nothing) Nothing) = s+unpackSimple e = lift e++unpackTerm :: V.Expression -> V.Term+unpackTerm (V.ENand (V.Relation (V.ShiftExpression (V.SimpleExpression Nothing t []) Nothing) Nothing) Nothing) = t+unpackTerm e = lift e++--------------------------------------------------------------------------------+++--------------------------------------------------------------------------------+{-+ident :: String -> V.Identifier+ident s = V.Ident s++ident' :: Name -> V.Identifier+ident' (Base n) = ident n+ident' (Exact n) = ident n++name :: String -> V.Primary+name = V.PrimName . V.NSimple . ident+-}+--------------------------------------------------------------------------------+{-+fromIdent :: ToIdent a => a -> V.Identifier+fromIdent a = let (Ident i) = toIdent a in ident i+-} --------------------------------------------------------------------------------
src/Language/Embedded/Hardware/Command/CMD.hs view
@@ -1,213 +1,620 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ScopedTypeVariables #-} module Language.Embedded.Hardware.Command.CMD where -import Language.Embedded.VHDL (Mode)-import Language.Embedded.Hardware.Interface (PredicateExp)+import Language.Embedded.VHDL (Mode)+import Language.Embedded.Hardware.Interface+import Language.Embedded.Hardware.Expression.Represent (Inhabited, Sized)+import Language.Embedded.Hardware.Expression.Represent.Bit (Bit, Bits) +import Control.Monad.Reader (ReaderT(..), runReaderT, lift) import Control.Monad.Operational.Higher +import Data.Typeable (Typeable) import Data.Ix (Ix) import Data.IORef (IORef) import Data.Array.IO (IOArray)+import qualified Data.Array as Arr +import qualified Language.VHDL as V (Expression, Name, Identifier)++import GHC.TypeLits (KnownNat)+import qualified GHC.Exts as GHC (Constraint)+ -------------------------------------------------------------------------------- -- * Hardware commands. -------------------------------------------------------------------------------- +data Name = None | Base VarId | Exact VarId ++-- | ...+swapM :: Monad m => Maybe (m a) -> m (Maybe a)+swapM = maybe (return Nothing) (>>= return . Just)+ ----------------------------------------------------------------------------------- ** Signals.+-- ** Values. --- | If a signal is declared with a scope of 'Entity' its classified as either a--- port or generic signal.-data Clause = Port | Generic- deriving (Show)+-- | Value representation.+data Val a = ValC String | ValE a --- | Scope of a signal.-data Scope = SProcess | SArchitecture | SEntity- deriving (Show)+-- | ...+valToExp :: (PredicateExp exp a, FreeExp exp) => Val a -> exp a+valToExp (ValC i) = varE i+valToExp (ValE a) = litE a +--------------------------------------------------------------------------------+-- ** Signals.+ -- | Signal representation.-data Signal a = SignalC Integer | SignalE (IORef a)+data Signal a = SignalC VarId | SignalE (IORef a) -- | Commands for signals.-data SignalCMD (exp :: * -> *) (prog :: * -> *) a+data SignalCMD fs a where -- ^ Create a new signal.- NewSignal :: PredicateExp exp a => Clause -> Scope -> Mode -> Maybe (exp a) -> SignalCMD exp prog (Signal a)+ NewSignal :: pred a => Name -> Mode -> Maybe (exp a) -> SignalCMD (Param3 prog exp pred) (Signal a) -- ^ Fetch the contents of a signal.- GetSignal :: PredicateExp exp a => Signal a -> SignalCMD exp prog (exp a)+ GetSignal :: pred a => Signal a -> SignalCMD (Param3 prog exp pred) (Val a) -- ^ Write the value to a signal.- SetSignal :: PredicateExp exp a => Signal a -> exp a -> SignalCMD exp prog ()+ SetSignal :: pred a => Signal a -> exp a -> SignalCMD (Param3 prog exp pred) () -- ^ Unsafe version of fetching a signal.- UnsafeFreezeSignal :: PredicateExp exp a => Signal a -> SignalCMD exp prog (exp a)--type instance IExp (SignalCMD e) = e-type instance IExp (SignalCMD e :+: i) = e+ UnsafeFreezeSignal :: pred a => Signal a -> SignalCMD (Param3 prog exp pred) (Val a)+ -- *** todo: maybe this should be part of a set for concurrent instructions?+ ConcurrentSetSignal :: pred a => Signal a -> exp a -> SignalCMD (Param3 prog exp pred) ()+ -- *** todo: is this dangerous?+ ToArray :: (pred a, Integral i, Ix i) => Signal a -> SignalCMD (Param3 prog exp pred) (Array i Bit) -instance HFunctor (SignalCMD exp)+instance HFunctor SignalCMD where- hfmap _ (NewSignal c s m e) = NewSignal c s m e- hfmap _ (GetSignal s) = GetSignal s- hfmap _ (SetSignal s e) = SetSignal s e+ hfmap _ (NewSignal n m e) = NewSignal n m e+ hfmap _ (GetSignal s) = GetSignal s+ hfmap _ (SetSignal s e) = SetSignal s e hfmap _ (UnsafeFreezeSignal s) = UnsafeFreezeSignal s+ -- ...+ hfmap _ (ConcurrentSetSignal s e) = ConcurrentSetSignal s e+ hfmap _ (ToArray s) = ToArray s +instance HBifunctor SignalCMD+ where+ hbimap _ f (NewSignal n m e) = NewSignal n m (fmap f e)+ hbimap _ _ (GetSignal s) = GetSignal s+ hbimap _ f (SetSignal s e) = SetSignal s (f e)+ hbimap _ _ (UnsafeFreezeSignal s) = UnsafeFreezeSignal s+ -- ...+ hbimap _ f (ConcurrentSetSignal s e) = ConcurrentSetSignal s (f e)+ hbimap _ _ (ToArray s) = ToArray s++instance (SignalCMD :<: instr) => Reexpressible SignalCMD instr env+ where+ reexpressInstrEnv reexp (NewSignal n m e) = lift . singleInj . NewSignal n m =<< swapM (fmap reexp e)+ reexpressInstrEnv reexp (GetSignal s) = lift $ singleInj $ GetSignal s+ reexpressInstrEnv reexp (SetSignal s e) = lift . singleInj . SetSignal s =<< reexp e+ reexpressInstrEnv reexp (UnsafeFreezeSignal s) = lift $ singleInj $ UnsafeFreezeSignal s+ -- ...+ reexpressInstrEnv reexp (ConcurrentSetSignal s e) = lift . singleInj . ConcurrentSetSignal s =<< reexp e+ reexpressInstrEnv reexp (ToArray s) = lift $ singleInj $ ToArray s+ -------------------------------------------------------------------------------- -- ** Variables. -- | Variable representation.-data Variable a = VariableC Integer | VariableE (IORef a)+data Variable a = VariableC VarId | VariableE (IORef a) -- | Commands for variables.-data VariableCMD (exp :: * -> *) (prog :: * -> *) a+data VariableCMD fs a where -- ^ Create a new variable.- NewVariable :: PredicateExp exp a => Maybe (exp a) -> VariableCMD exp prog (Variable a)+ NewVariable :: pred a => Name -> Maybe (exp a) -> VariableCMD (Param3 prog exp pred) (Variable a) -- ^ Fetch the contents of a variable.- GetVariable :: PredicateExp exp a => Variable a -> VariableCMD exp prog (exp a)+ GetVariable :: pred a => Variable a -> VariableCMD (Param3 prog exp pred) (Val a) -- ^ Write the value to a variable.- SetVariable :: PredicateExp exp a => Variable a -> exp a -> VariableCMD exp prog ()+ SetVariable :: pred a => Variable a -> exp a -> VariableCMD (Param3 prog exp pred) () -- ^ Unsafe version of fetching a variable.- UnsafeFreezeVariable :: PredicateExp exp a => Variable a -> VariableCMD exp prog (exp a)--type instance IExp (VariableCMD e) = e-type instance IExp (VariableCMD e :+: i) = e+ UnsafeFreezeVariable :: pred a => Variable a -> VariableCMD (Param3 prog exp pred) (Val a) -instance HFunctor (VariableCMD exp)+instance HFunctor VariableCMD where- hfmap _ (NewVariable e) = NewVariable e- hfmap _ (GetVariable s) = GetVariable s- hfmap _ (SetVariable s e) = SetVariable s e+ hfmap _ (NewVariable n e) = NewVariable n e+ hfmap _ (GetVariable s) = GetVariable s+ hfmap _ (SetVariable s e) = SetVariable s e hfmap _ (UnsafeFreezeVariable s) = UnsafeFreezeVariable s +instance HBifunctor VariableCMD+ where+ hbimap _ f (NewVariable n e) = NewVariable n (fmap f e)+ hbimap _ _ (GetVariable v) = GetVariable v+ hbimap _ f (SetVariable v e) = SetVariable v (f e)+ hbimap _ _ (UnsafeFreezeVariable v) = UnsafeFreezeVariable v++instance (VariableCMD :<: instr) => Reexpressible VariableCMD instr env+ where+ reexpressInstrEnv reexp (NewVariable n e) = lift . singleInj . NewVariable n =<< swapM (fmap reexp e)+ reexpressInstrEnv reexp (GetVariable v) = lift $ singleInj $ GetVariable v+ reexpressInstrEnv reexp (SetVariable v e) = lift . singleInj . SetVariable v =<< reexp e+ reexpressInstrEnv reexp (UnsafeFreezeVariable v) = lift $ singleInj $ UnsafeFreezeVariable v+ --------------------------------------------------------------------------------+-- ** Constants.++-- | Constant representation.+data Constant a = ConstantC VarId | ConstantE a++-- | Commands for constants.+data ConstantCMD fs a+ where+ -- ^ Create a new constant.+ NewConstant :: pred a => Name -> exp a -> ConstantCMD (Param3 prog exp pred) (Constant a)+ -- ^ Fetch the value of a constant.+ GetConstant :: pred a => Constant a -> ConstantCMD (Param3 prog exp pred) (Val a)++instance HFunctor ConstantCMD+ where+ hfmap _ (NewConstant n e) = NewConstant n e+ hfmap _ (GetConstant c) = GetConstant c++instance HBifunctor ConstantCMD+ where+ hbimap _ f (NewConstant n e) = NewConstant n (f e)+ hbimap _ _ (GetConstant c) = GetConstant c++instance (ConstantCMD :<: instr) => Reexpressible ConstantCMD instr env+ where+ reexpressInstrEnv reexp (NewConstant n e) = lift . singleInj . NewConstant n =<< reexp e+ reexpressInstrEnv reexp (GetConstant c) = lift $ singleInj $ GetConstant c++-------------------------------------------------------------------------------- -- ** Arrays. -- | Expression types that support compilation of array indexing class CompArrayIx exp where -- | Generate code for an array indexing operation- compArrayIx :: PredicateExp exp a => exp i -> Array i a -> Maybe (exp a)+ compArrayIx :: (PredicateExp exp a, Integral i, Ix i) => exp i -> Array i a -> Maybe (exp a) compArrayIx _ _ = Nothing -- | Array reprensentation.-data Array i a = ArrayC Integer | ArrayE (IORef (IOArray i a))+data Array i a = ArrayC VarId | ArrayE (IOArray i a) --- | Commands for arrays.-data ArrayCMD (exp :: * -> *) (prog :: * -> *) a+-- | Commands for signal arrays.+data ArrayCMD fs a where -- ^ Creates an array of given length.- NewArray- :: ( PredicateExp exp a- , PredicateExp exp i- , Integral i- , Ix i )- => exp i -> ArrayCMD exp prog (Array i a)+ NewArray :: (pred a, Integral i, Ix i) => Name -> exp i -> ArrayCMD (Param3 prog exp pred) (Array i a) -- ^ Creates an array from the given list of elements.- InitArray- :: ( PredicateExp exp a- , PredicateExp exp i- , Integral i- , Ix i )- => [a] -> ArrayCMD exp prog (Array i a)+ InitArray :: (pred a, Integral i, Ix i) => Name -> [a] -> ArrayCMD (Param3 prog exp pred) (Array i a)+ -- ^ Fetches the array's value at the specified index.+ GetArray :: (pred a, Integral i, Ix i) => Array i a -> exp i -> ArrayCMD (Param3 prog exp pred) (Val a)+ -- ^ Writes a value to an array at some specified index.+ SetArray :: (pred a, Integral i, Ix i) => Array i a -> exp i -> exp a -> ArrayCMD (Param3 prog exp pred) ()+ -- ^ Copies a slice from the second array into the first.+ CopyArray :: (pred a, Integral i, Ix i) => (Array i a, exp i) -> (Array i a, exp i) -> exp i -> ArrayCMD (Param3 prog exp pred) ()+ -- ^ Writes a value to all indicies of the array.+ ResetArray :: (pred a, Integral i, Ix i) => Array i a -> exp a -> ArrayCMD (Param3 prog exp pred) ()++instance HFunctor ArrayCMD+ where+ hfmap _ (NewArray n i) = NewArray n i+ hfmap _ (InitArray n is) = InitArray n is+ hfmap _ (GetArray a i) = GetArray a i+ hfmap _ (SetArray a i e) = SetArray a i e+ hfmap _ (CopyArray a b l) = CopyArray a b l+ -- ...+ hfmap _ (ResetArray a r) = ResetArray a r++instance HBifunctor ArrayCMD+ where+ hbimap _ f (NewArray n i) = NewArray n (f i)+ hbimap _ _ (InitArray n is) = InitArray n is+ hbimap _ f (GetArray a i) = GetArray a (f i)+ hbimap _ f (SetArray a i e) = SetArray a (f i) (f e)+ hbimap _ f (CopyArray (a, oa) (b, ob) l) = CopyArray (a, f oa) (b, f ob) (f l)+ -- ...+ hbimap _ f (ResetArray a r) = ResetArray a (f r)++instance (ArrayCMD :<: instr) => Reexpressible ArrayCMD instr env+ where+ reexpressInstrEnv reexp (NewArray n i)+ = lift . singleInj . NewArray n =<< reexp i+ reexpressInstrEnv reexp (InitArray n is)+ = lift $ singleInj $ InitArray n is+ reexpressInstrEnv reexp (GetArray a i)+ = do i' <- reexp i; lift $ singleInj $ GetArray a i'+ reexpressInstrEnv reexp (SetArray a i e)+ = do i' <- reexp i; e' <- reexp e; lift $ singleInj $ SetArray a i' e'+ reexpressInstrEnv reexp (CopyArray (a, oa) (b, ob) l)+ = do oa' <- reexp oa; ob' <- reexp ob; l' <- reexp l+ lift $ singleInj $ CopyArray (a, oa') (b, ob') l'+ -- ...+ reexpressInstrEnv reexp (ResetArray a r)+ = do r' <- reexp r; lift $ singleInj $ ResetArray a r'++--------------------------------------------------------------------------------+-- ** Virtual arrays.++-- | Virtual array reprensentation.+data VArray i a = VArrayC VarId | VArrayE (IOArray i a)+ deriving (Eq, Typeable)++-- | Immutable arrays.+data IArray i a = IArrayC VarId | IArrayE (Arr.Array i a)+ deriving (Show, Typeable)++-- | Commands for variable arrays.+data VArrayCMD fs a+ where+ -- ^ Creates an array of given length.+ NewVArray :: (pred a, Integral i, Ix i) => Name -> exp i -> VArrayCMD (Param3 prog exp pred) (VArray i a)+ -- ^ Creates an array from the given list of elements.+ InitVArray :: (pred a, Integral i, Ix i) => Name -> [a] -> VArrayCMD (Param3 prog exp pred) (VArray i a) -- ^ Fetches the array's value at a specified index.- GetArray- :: ( PredicateExp exp a- , PredicateExp exp i- , Integral i- , Ix i )- => exp i -> Array i a -> ArrayCMD exp prog (exp a)+ GetVArray :: (pred a, Integral i, Ix i) => VArray i a -> exp i -> VArrayCMD (Param3 prog exp pred) (Val a) -- ^ Writes a value to an array at some specified index.- SetArray- :: ( PredicateExp exp a- , PredicateExp exp i- , Integral i- , Ix i )- => exp i -> exp a -> Array i a -> ArrayCMD exp prog ()- -- ^ Unsafe version of fetching an array's value.- UnsafeGetArray- :: ( PredicateExp exp a- , PredicateExp exp i- , Integral i- , Ix i )- => exp i -> Array i a -> ArrayCMD exp prog (exp a)+ SetVArray :: (pred a, Integral i, Ix i) => VArray i a -> exp i -> exp a -> VArrayCMD (Param3 prog exp pred) ()+ -- ^ ...+ CopyVArray:: (pred a, Integral i, Ix i) => (VArray i a, exp i) -> (VArray i a, exp i) -> exp i -> VArrayCMD (Param3 prog exp pred) ()+ -- ^ ...+ UnsafeFreezeVArray :: (pred a, Integral i, Ix i) => VArray i a -> VArrayCMD (Param3 prog exp pred) (IArray i a)+ -- ^ ...+ UnsafeThawVArray :: (pred a, Integral i, Ix i) => IArray i a -> VArrayCMD (Param3 prog exp pred) (VArray i a) -type instance IExp (ArrayCMD e) = e-type instance IExp (ArrayCMD e :+: i) = e+instance HFunctor VArrayCMD+ where+ hfmap _ (NewVArray n i) = NewVArray n i+ hfmap _ (InitVArray n is) = InitVArray n is+ hfmap _ (GetVArray a i) = GetVArray a i+ hfmap _ (SetVArray a i e) = SetVArray a i e+ hfmap _ (CopyVArray a b l) = CopyVArray a b l+ hfmap _ (UnsafeFreezeVArray a) = UnsafeFreezeVArray a+ hfmap _ (UnsafeThawVArray a) = UnsafeThawVArray a -instance HFunctor (ArrayCMD exp)+instance HBifunctor VArrayCMD where- hfmap _ (NewArray i) = NewArray i- hfmap _ (InitArray is) = InitArray is- hfmap _ (GetArray i a) = GetArray i a- hfmap _ (SetArray i e a) = SetArray i e a- hfmap _ (UnsafeGetArray i a) = UnsafeGetArray i a+ hbimap _ f (NewVArray n i) = NewVArray n (f i)+ hbimap _ _ (InitVArray n is) = InitVArray n is+ hbimap _ f (GetVArray a i) = GetVArray a (f i)+ hbimap _ f (SetVArray a i e) = SetVArray a (f i) (f e)+ hbimap _ f (CopyVArray (a, oa) (b, ob) l) = CopyVArray (a, f oa) (b, f ob) (f l)+ hbimap _ _ (UnsafeFreezeVArray a) = UnsafeFreezeVArray a+ hbimap _ _ (UnsafeThawVArray a) = UnsafeThawVArray a +instance (VArrayCMD :<: instr) => Reexpressible VArrayCMD instr env+ where+ reexpressInstrEnv reexp (NewVArray n i)+ = lift . singleInj . NewVArray n =<< reexp i+ reexpressInstrEnv reexp (InitVArray n is)+ = lift $ singleInj $ InitVArray n is+ reexpressInstrEnv reexp (GetVArray a i)+ = do i' <- reexp i; lift $ singleInj $ GetVArray a i'+ reexpressInstrEnv reexp (SetVArray a i e)+ = do i' <- reexp i; e' <- reexp e; lift $ singleInj $ SetVArray a i' e'+ reexpressInstrEnv reexp (CopyVArray (a, oa) (b, ob) l)+ = do oa' <- reexp oa; ob' <- reexp ob; l' <- reexp l+ lift $ singleInj $ CopyVArray (a, oa') (b, ob') l'+ reexpressInstrEnv reexp (UnsafeFreezeVArray a)+ = lift $ singleInj $ UnsafeFreezeVArray a+ reexpressInstrEnv reexp (UnsafeThawVArray a)+ = lift $ singleInj $ UnsafeThawVArray a+ -------------------------------------------------------------------------------- -- ** Looping. -- | Commands for looping constructs.-data LoopCMD (exp :: * -> *) (prog :: * -> *) a+data LoopCMD fs a where -- ^ Creates a new for loop.- For :: (PredicateExp exp n, Integral n) => exp n -> (exp n -> prog ()) -> LoopCMD exp prog ()+ For :: (pred i, Integral i) => exp i -> exp i -> (Val i -> prog ()) -> LoopCMD (Param3 prog exp pred) () -- ^ Creates a new while loop.- While :: PredicateExp exp Bool => prog (exp Bool) -> prog () -> LoopCMD exp prog ()--type instance IExp (LoopCMD e) = e-type instance IExp (LoopCMD e :+: i) = e+ While :: prog (exp Bool) -> prog () -> LoopCMD (Param3 prog exp pred) () -instance HFunctor (LoopCMD exp)+instance HFunctor LoopCMD where- hfmap f (For r step) = For r (f . step)+ hfmap f (For l u step) = For l u (f . step) hfmap f (While cont step) = While (f cont) (f step) +instance HBifunctor LoopCMD+ where+ hbimap g f (For l u step) = For (f l) (f u) (g . step)+ hbimap g f (While cont step) = While (g $ fmap f cont) (g step)++instance (LoopCMD :<: instr) => Reexpressible LoopCMD instr env+ where+ reexpressInstrEnv reexp (For l u step) = do+ l' <- reexp l+ u' <- reexp u+ ReaderT $ \env -> singleInj $+ For l' u' (flip runReaderT env . step)+ reexpressInstrEnv reexp (While cont step) = do+ ReaderT $ \env -> singleInj $+ While (runReaderT (cont >>= reexp) env)+ (runReaderT step env)+ -------------------------------------------------------------------------------- -- ** Conditional statements. +-- | ...+data When a prog = When (Constraint a) (prog ())++-- | ...+data Constraint a where+ Is :: Eq a => a -> Constraint a+ To :: Ord a => a -> a -> Constraint a+ -- | Commnads for conditional statements.-data ConditionalCMD (exp :: * -> *) (prog :: * -> *) a+data ConditionalCMD fs a where- If :: PredicateExp exp Bool- => (exp Bool, prog ()) -- if- -> [(exp Bool, prog ())] -- else-if- -> Maybe (prog ()) -- else- -> ConditionalCMD exp prog ()+ -- ^ ...+ If :: (exp Bool, prog ()) -> [(exp Bool, prog ())] -> Maybe (prog ()) -> ConditionalCMD (Param3 prog exp pred) ()+ -- ^ ...+ Case :: pred a => exp a -> [When a prog] -> Maybe (prog ()) -> ConditionalCMD (Param3 prog exp pred) ()+ -- ^ ...+ Null :: ConditionalCMD (Param3 prog exp pred) () -type instance IExp (ConditionalCMD e) = e-type instance IExp (ConditionalCMD e :+: i) = e+instance HFunctor ConditionalCMD+ where+ hfmap f (If a cs b) = If (fmap f a) (fmap (fmap f) cs) (fmap f b)+ hfmap f (Case e xs d) = Case e (fmap (wmap f) xs) (fmap f d)+ where wmap f (When a p) = When a (f p)+ hfmap _ (Null) = Null -instance HFunctor (ConditionalCMD exp)+instance HBifunctor ConditionalCMD where- hfmap f (If a cs b) = If (fmap f a) (fmap (fmap f) cs) (fmap f b)+ hbimap g f (If a cs b) = If (pmap a) (fmap pmap cs) (fmap g b)+ where pmap (x, y) = (f x, g y)+ hbimap g f (Case e xs d) = Case (f e) (fmap wmap xs) (fmap g d)+ where wmap (When a p) = When a (g p)+ hbimap _ _ (Null) = Null +instance (ConditionalCMD :<: instr) => Reexpressible ConditionalCMD instr env+ where+ reexpressInstrEnv reexp (If (c, a) cs b) =+ do let (xs, ys) = unzip cs+ c' <- reexp c+ xs' <- mapM reexp xs+ ReaderT $ \env ->+ let ys' = fmap (flip runReaderT env) ys+ in singleInj $+ If (c', runReaderT a env)+ (zip xs' ys')+ (fmap (flip runReaderT env) b)+ reexpressInstrEnv reexp (Case c cs d) =+ do let (xs, ys) = unzipWhen cs+ c' <- reexp c+ ReaderT $ \env ->+ let ys' = fmap (flip runReaderT env) ys+ in singleInj $+ Case c'+ (zipWhen xs ys')+ (fmap (flip runReaderT env) d)+ reexpressInstrEnv reexp (Null) = lift $ singleInj $ Null++unzipWhen :: [When a p] -> ([Constraint a], [p ()])+unzipWhen = unzip . fmap (\(When a p) -> (a, p))++zipWhen :: [Constraint a] -> [p ()] -> [When a p]+zipWhen x y = fmap (\(a, p) -> When a p) $ zip x y+ --------------------------------------------------------------------------------+-- ** Components.++-- | Signature description.+data Signature fs a+ where+ Ret :: prog () -> Signature (Param3 prog exp pred) ()+ SSig :: (pred a, Inhabited a, Sized a)+ => Name -> Mode+ -> (Signal a -> Signature (Param3 prog exp pred) b)+ -> Signature (Param3 prog exp pred) (Signal a -> b)+ SArr :: (pred a, Inhabited a, Sized a, pred i, Integral i, Ix i)+ => Name -> Mode -> i+ -> (Array i a -> Signature (Param3 prog exp pred) b)+ -> Signature (Param3 prog exp pred) (Array i a -> b)++instance HFunctor Signature+ where+ hfmap f (Ret m) = Ret (f m)+ hfmap f (SSig n m sig) = SSig n m (hfmap f . sig)+ hfmap f (SArr n m l arr) = SArr n m l (hfmap f . arr)++instance HBifunctor Signature+ where+ hbimap g f (Ret m) = Ret (g m)+ hbimap g f (SSig n m sig) = SSig n m (hbimap g f . sig)+ hbimap g f (SArr n m l sig) = SArr n m l (hbimap g f . sig)++reexpressSignature :: env+ -> Signature (Param3 (ReaderT env (ProgramT instr (Param2 exp2 pred) m)) exp1 pred) a+ -> Signature (Param3 (ProgramT instr (Param2 exp2 pred) m) exp2 pred) a+reexpressSignature env (Ret prog) = Ret (runReaderT prog env)+reexpressSignature env (SSig n m sf) = SSig n m (reexpressSignature env . sf)+reexpressSignature env (SArr n m l af) = SArr n m l (reexpressSignature env . af)++-- | Signature arguments.+data Argument pred a+ where+ Nil :: Argument pred ()+ ASig :: (pred a, Inhabited a, Sized a)+ => Signal a+ -> Argument pred b+ -> Argument pred (Signal a -> b)+ AArr :: (pred a, Inhabited a, Sized a, Integral i, Ix i)+ => Array i a+ -> Argument pred b+ -> Argument pred (Array i a -> b)++-- | Named components.+data Component fs a = Component String (Signature fs a)++-- | Commands for generating stand-alone components and calling them.+data ComponentCMD fs a+ where+ -- ^ Wraps the given signature in a named component.+ StructComponent+ :: Name+ -> Signature (Param3 prog exp pred) a+ -> ComponentCMD (Param3 prog exp pred) String+ -- ^ Call for interfacing with a component.+ PortMap+ :: Component (Param3 prog exp pred) a+ -> Argument pred a+ -> ComponentCMD (Param3 prog exp pred) ()++instance HFunctor ComponentCMD+ where+ hfmap f (StructComponent n sig) = StructComponent n (hfmap f sig)+ hfmap f (PortMap (Component m sig) as) = PortMap (Component m (hfmap f sig)) as++instance HBifunctor ComponentCMD+ where+ hbimap g f (StructComponent n sig) = StructComponent n (hbimap g f sig)+ hbimap g f (PortMap (Component m sig) as) = PortMap (Component m (hbimap g f sig)) as++instance (ComponentCMD :<: instr) => Reexpressible ComponentCMD instr env+ where+ reexpressInstrEnv reexp (StructComponent n sig) = ReaderT $ \env ->+ singleInj $ StructComponent n (reexpressSignature env sig)+ reexpressInstrEnv reexp (PortMap (Component m sig) as) = ReaderT $ \env ->+ singleInj $ PortMap (Component m (reexpressSignature env sig)) as++-------------------------------------------------------------------------------- -- ** Structural entities. --- | Untyped signals.-data SignalX = forall a. SignalX (Signal a)+data Ident = Ident VarId +class ToIdent a where toIdent :: a -> Ident+instance ToIdent (Val a) where toIdent (ValC i) = Ident i+instance ToIdent (Signal a) where toIdent (SignalC i) = Ident i+instance ToIdent (Variable a) where toIdent (VariableC i) = Ident i+instance ToIdent (Constant a) where toIdent (ConstantC i) = Ident i+instance ToIdent (Array i a) where toIdent (ArrayC i) = Ident i+instance ToIdent (VArray i a) where toIdent (VArrayC i) = Ident i+ -- | Commands for structural entities.-data StructuralCMD (exp :: * -> *) (prog :: * -> *) a+data StructuralCMD fs (a :: *) where -- ^ Wraps the program in an entity.- Entity :: String -> prog a -> StructuralCMD exp prog a+ StructEntity+ :: Name -> prog a -> StructuralCMD (Param3 prog exp pred) a -- ^ Wraps the program in an architecture.- Architecture :: String -> String -> prog a -> StructuralCMD exp prog a+ StructArchitecture+ :: Name -> Name -> prog a -> StructuralCMD (Param3 prog exp pred) a -- ^ Wraps the program in a process.- Process :: [SignalX] -> prog () -> StructuralCMD exp prog ()+ StructProcess+ :: [Ident] -> prog () -> StructuralCMD (Param3 prog exp pred) () -type instance IExp (StructuralCMD e) = e-type instance IExp (StructuralCMD e :+: i) = e+-- todo: make sure entity and architectures always share a name. -instance HFunctor (StructuralCMD exp)+instance HFunctor StructuralCMD where- hfmap f (Entity e p) = Entity e (f p)- hfmap f (Architecture e a p) = Architecture e a (f p)- hfmap f (Process xs p) = Process xs (f p)+ hfmap f (StructEntity e p) = StructEntity e (f p)+ hfmap f (StructArchitecture e a p) = StructArchitecture e a (f p)+ hfmap f (StructProcess xs p) = StructProcess xs (f p)++instance HBifunctor StructuralCMD+ where+ hbimap g _ (StructEntity e p) = StructEntity e (g p)+ hbimap g _ (StructArchitecture e a p) = StructArchitecture e a (g p)+ hbimap g _ (StructProcess xs p) = StructProcess xs (g p)++instance (StructuralCMD :<: instr) => Reexpressible StructuralCMD instr env+ where+ reexpressInstrEnv reexp (StructEntity n p) =+ ReaderT $ \env -> singleInj $ StructEntity n $ runReaderT p env+ reexpressInstrEnv reexp (StructArchitecture e n p) =+ ReaderT $ \env -> singleInj $ StructArchitecture e n $ runReaderT p env+ reexpressInstrEnv reexp (StructProcess is p) =+ ReaderT $ \env -> singleInj $ StructProcess is $ runReaderT p env++--------------------------------------------------------------------------------++data VHDLCMD fs a+ where+ -- todo: When we have external function calls we can replace this.+ -- For now, its a handy short-hand for a common pattern in VHDL.+ Rising :: pred Bit+ => Signal Bit -- ^ clock.+ -> Signal Bit -- ^ reset.+ -> prog () -- ^ program for when clock & reset.+ -> prog () -- ^ program for when clock & not reset.+ -> VHDLCMD (Param3 prog exp pred) ()+ -- todo: We should allow for base types to be treated as arrays of bits instead.+ -- todo: The second argument should be over a variable.+ CopyBits :: (pred a, pred b, Integral i, Ix i)+ => (Signal a, exp i)+ -> (Signal b, exp i)+ -> exp i+ -> VHDLCMD (Param3 prog exp pred) ()+ CopyVBits :: (pred a, pred b, Integral i, Ix i)+ => (Variable a, exp i)+ -> (Signal b, exp i)+ -> exp i+ -> VHDLCMD (Param3 prog exp pred) ()+ -- todo: These two should be expressions instead.+ GetBit :: (pred a, pred Bit, Integral i, Ix i)+ => Signal a+ -> exp i+ -> VHDLCMD (Param3 prog exp pred) (Val Bit)+ SetBit :: (pred a, pred Bit, Integral i, Ix i)+ => Signal a+ -> exp i+ -> exp Bit+ -> VHDLCMD (Param3 prog exp pred) ()+ -- todo: same as above two?...+ -- todo: result should be i?...+ GetBits :: (pred i, Integral i, Ix i)+ => Signal (Bits n)+ -> exp i+ -> exp i+ -> VHDLCMD (Param3 prog exp pred) (Val i)++instance HFunctor VHDLCMD+ where+ hfmap f (Rising clk rst tru fls) = Rising clk rst (f tru) (f fls)+ hfmap _ (CopyBits a b l) = CopyBits a b l+ hfmap _ (CopyVBits a b l) = CopyVBits a b l+ hfmap _ (GetBit s i) = GetBit s i+ hfmap _ (SetBit s i b) = SetBit s i b+ hfmap _ (GetBits s l u) = GetBits s l u++instance HBifunctor VHDLCMD+ where+ hbimap g _ (Rising clk rst tru fls) = Rising clk rst (g tru) (g fls)+ hbimap _ f (CopyBits (a, oa) (b, ob) l) = CopyBits (a, f oa) (b, f ob) (f l)+ hbimap _ f (CopyVBits (a, oa) (b, ob) l) = CopyVBits (a, f oa) (b, f ob) (f l)+ hbimap _ f (GetBit s i) = GetBit s (f i)+ hbimap _ f (SetBit s i b) = SetBit s (f i) (f b)+ hbimap _ f (GetBits s l u) = GetBits s (f l) (f u)++instance (VHDLCMD :<: instr) => Reexpressible VHDLCMD instr env+ where+ reexpressInstrEnv reexp (Rising clk rst tru fls) =+ ReaderT $ \env -> singleInj $ Rising clk rst+ (runReaderT tru env)+ (runReaderT fls env)+ reexpressInstrEnv reexp (CopyBits (a, oa) (b, ob) l)+ = do oa' <- reexp oa; ob' <- reexp ob; l' <- reexp l+ lift $ singleInj $ CopyBits (a, oa') (b, ob') l'+ reexpressInstrEnv reexp (CopyVBits (a, oa) (b, ob) l)+ = do oa' <- reexp oa; ob' <- reexp ob; l' <- reexp l+ lift $ singleInj $ CopyVBits (a, oa') (b, ob') l'+ reexpressInstrEnv reexp (GetBit s i)+ = do i' <- reexp i+ lift $ singleInj $ GetBit s i'+ reexpressInstrEnv reexp (SetBit s i b)+ = do i' <- reexp i; b' <- reexp b+ lift $ singleInj $ SetBit s i' b'+ reexpressInstrEnv reexp (GetBits s l u)+ = do l' <- reexp l; u' <- reexp u+ lift $ singleInj $ GetBits s l' u' --------------------------------------------------------------------------------
src/Language/Embedded/Hardware/Command/Frontend.hs view
@@ -1,199 +1,526 @@-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE PolyKinds #-} module Language.Embedded.Hardware.Command.Frontend where -import Language.Embedded.VHDL (Mode(..))-import Language.Embedded.Hardware.Interface (PredicateExp)+import Language.Embedded.VHDL (Mode(..))+import Language.Embedded.Hardware.Interface import Language.Embedded.Hardware.Command.CMD +import Language.Embedded.Hardware.Expression.Represent+import Language.Embedded.Hardware.Expression.Represent.Bit+ import Control.Monad.Operational.Higher -import Data.Ix (Ix)+import Data.Ix (Ix)+import Data.IORef (readIORef)+import Data.Int+import Data.Word +import System.IO.Unsafe -- used for `veryUnsafeFreezeVariable`.++import GHC.TypeLits (KnownNat)+ --------------------------------------------------------------------------------+-- * Hardware frontend.+--------------------------------------------------------------------------------++-------------------------------------------------------------------------------- -- ** Signals. +-- | Declare a named signal.+initNamedSignal :: (SignalCMD :<: instr, pred a) => String -> exp a -> ProgramT instr (Param2 exp pred) m (Signal a)+initNamedSignal name = singleInj . NewSignal (Base name) InOut . Just+ -- | Declare a signal.-newSignal :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => IExp i a -> ProgramT i m (Signal a)-newSignal = singleE . NewSignal Port SArchitecture InOut . Just+initSignal :: (SignalCMD :<: instr, pred a) => exp a -> ProgramT instr (Param2 exp pred) m (Signal a)+initSignal = initNamedSignal "s" +-- | Declare an uninitialized named signal.+newNamedSignal :: (SignalCMD :<: instr, pred a) => String -> ProgramT instr (Param2 exp pred) m (Signal a)+newNamedSignal name = singleInj $ NewSignal (Base name) InOut Nothing+ -- | Declare an uninitialized signal.-newSignal_ :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => ProgramT i m (Signal a)-newSignal_ = singleE $ NewSignal Port SArchitecture InOut Nothing+newSignal :: (SignalCMD :<: instr, pred a) => ProgramT instr (Param2 exp pred) m (Signal a)+newSignal = newNamedSignal "s" -- | Fetches the current value of a signal.-getSignal :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Signal a -> ProgramT i m (IExp i a)-getSignal = singleE . GetSignal+getSignal :: (SignalCMD :<: instr, pred a, FreeExp exp, PredicateExp exp a, Monad m)+ => Signal a -> ProgramT instr (Param2 exp pred) m (exp a)+getSignal = fmap valToExp . singleInj . GetSignal -- | Update the value of a signal.-setSignal :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Signal a -> IExp i a -> ProgramT i m ()-setSignal s = singleE . SetSignal s+setSignal :: (SignalCMD :<: instr, pred a) => Signal a -> exp a -> ProgramT instr (Param2 exp pred) m ()+setSignal s = singleInj . SetSignal s -- | Unsafe version of fetching the contents of a signal.-unsafeFreezeSignal :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Signal a -> ProgramT i m (IExp i a)-unsafeFreezeSignal = singleE . UnsafeFreezeSignal+unsafeFreezeSignal :: (SignalCMD :<: instr, pred a, FreeExp exp, PredicateExp exp a, Monad m)+ => Signal a -> ProgramT instr (Param2 exp pred) m (exp a)+unsafeFreezeSignal = fmap valToExp . singleInj . UnsafeFreezeSignal +-- | Concurrent update of a signals value.+concurrentSetSignal :: (SignalCMD :<: instr, pred a) => Signal a -> exp a -> ProgramT instr (Param2 exp pred) m ()+concurrentSetSignal s = singleInj . ConcurrentSetSignal s++--------------------------------------------------------------------------------+-- ports.+ -- | Declare port signals of the given mode and assign it initial value.-newPort :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Mode -> IExp i a -> ProgramT i m (Signal a)-newPort m = singleE . NewSignal Port SEntity m . Just+initNamedPort, initExactPort :: (SignalCMD :<: instr, pred a)+ => String -> Mode -> exp a -> ProgramT instr (Param2 exp pred) m (Signal a)+initNamedPort name m = singleInj . NewSignal (Base name) m . Just+initExactPort name m = singleInj . NewSignal (Exact name) m . Just +initPort :: (SignalCMD :<: instr, pred a) => Mode -> exp a -> ProgramT instr (Param2 exp pred) m (Signal a)+initPort = initNamedPort "p"+ -- | Declare port signals of the given mode.-newPort_ :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Mode -> ProgramT i m (Signal a)-newPort_ m = singleE $ NewSignal Port SEntity m Nothing+newNamedPort, newExactPort :: (SignalCMD :<: instr, pred a)+ => String -> Mode -> ProgramT instr (Param2 exp pred) m (Signal a)+newNamedPort name m = singleInj $ NewSignal (Base name) m Nothing+newExactPort name m = singleInj $ NewSignal (Exact name) m Nothing --- | Declare generic signals of the given mode and assign it initial value.-newGeneric :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Mode -> IExp i a -> ProgramT i m (Signal a)-newGeneric m = singleE . NewSignal Generic SEntity m . Just+newPort :: (SignalCMD :<: instr, pred a) => Mode -> ProgramT instr (Param2 exp pred) m (Signal a)+newPort = newNamedPort "p" --- | Declare generic signals of the given mode.-newGeneric_ :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Mode -> ProgramT i m (Signal a)-newGeneric_ m = singleE $ NewSignal Generic SEntity m Nothing+--------------------------------------------------------------------------------+-- short-hands. --- | Short-hand for 'setSignal'.-(<==) :: (SignalCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Signal a -> IExp i a -> ProgramT i m ()-(<==) = setSignal+signal :: (SignalCMD :<: instr, pred a) => String -> ProgramT instr (Param2 exp pred) m (Signal a)+signal = newNamedSignal +(<--) :: (SignalCMD :<: instr, pred a, PredicateExp exp a, FreeExp exp, Monad m)+ => Signal a+ -> a+ -> ProgramT instr (Param2 exp pred) m ()+(<--) s e = s <== (litE e)++(<==) :: (SignalCMD :<: instr, pred a)+ => Signal a+ -> exp a+ -> ProgramT instr (Param2 exp pred) m ()+(<==) s e = setSignal s e++(<=-) :: (SignalCMD :<: instr, pred a, PredicateExp exp a, FreeExp exp, Monad m)+ => Signal a+ -> Signal a+ -> ProgramT instr (Param2 exp pred) m ()+(<=-) s v = do v' <- unsafeFreezeSignal v; s <== v'+ -------------------------------------------------------------------------------- -- ** Variables. +-- | Declare a named variable.+initNamedVariable :: (VariableCMD :<: instr, pred a)+ => String -> exp a -> ProgramT instr (Param2 exp pred) m (Variable a)+initNamedVariable name = singleInj . NewVariable (Base name) . Just+ -- | Declare a variable.-newVariable :: (VariableCMD (IExp i) :<: i, PredicateExp (IExp i) a) => IExp i a -> ProgramT i m (Variable a)-newVariable = singleE . NewVariable . Just+initVariable :: (VariableCMD :<: instr, pred a) => exp a -> ProgramT instr (Param2 exp pred) m (Variable a)+initVariable = initNamedVariable "v" +-- | Declare an uninitialized named variable.+newNamedVariable :: (VariableCMD :<: instr, pred a)+ => String -> ProgramT instr (Param2 exp pred) m (Variable a)+newNamedVariable name = singleInj $ NewVariable (Base name) Nothing+ -- | Declare an uninitialized variable.-newVariable_ :: (VariableCMD (IExp i) :<: i, PredicateExp (IExp i) a) => ProgramT i m (Variable a)-newVariable_ = singleE $ NewVariable Nothing+newVariable :: (VariableCMD :<: instr, pred a) => ProgramT instr (Param2 exp pred) m (Variable a)+newVariable = newNamedVariable "v" -- | Fetches the current value of a variable.-getVariable :: (VariableCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Variable a -> ProgramT i m (IExp i a)-getVariable = singleE . GetVariable+getVariable :: (VariableCMD :<: instr, pred a, PredicateExp exp a, FreeExp exp, Monad m)+ => Variable a -> ProgramT instr (Param2 exp pred) m (exp a)+getVariable = fmap valToExp . singleInj . GetVariable -- | Updates the value of a variable.-setVariable :: (VariableCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Variable a -> IExp i a -> ProgramT i m ()-setVariable v = singleE . SetVariable v+setVariable :: (VariableCMD :<: instr, pred a) => Variable a -> exp a -> ProgramT instr (Param2 exp pred) m ()+setVariable v = singleInj . SetVariable v -- | Unsafe version of fetching the contents of a variable.-unsafeFreezeVariable :: (VariableCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Variable a -> ProgramT i m (IExp i a)-unsafeFreezeVariable = singleE . UnsafeFreezeVariable+unsafeFreezeVariable :: (VariableCMD :<: instr, pred a, PredicateExp exp a, FreeExp exp, Monad m)+ => Variable a -> ProgramT instr (Param2 exp pred) m (exp a)+unsafeFreezeVariable = fmap valToExp . singleInj . UnsafeFreezeVariable +-- | Read the value of a reference without the monad in a very unsafe fashion.+veryUnsafeFreezeVariable :: (PredicateExp exp a, FreeExp exp) => Variable a -> exp a+veryUnsafeFreezeVariable (VariableE r) = litE $! unsafePerformIO $! readIORef r+veryUnsafeFreezeVariable (VariableC v) = varE v++--------------------------------------------------------------------------------+-- short-hands.++variable :: (VariableCMD :<: instr, pred a) => String -> ProgramT instr (Param2 exp pred) m (Variable a)+variable = newNamedVariable+ -- | Short-hand for 'setVariable'.-(==:) :: (VariableCMD (IExp i) :<: i, PredicateExp (IExp i) a) => Variable a -> IExp i a -> ProgramT i m ()+(==:) :: (VariableCMD :<: instr, pred a) => Variable a -> exp a -> ProgramT instr (Param2 exp pred) m () (==:) = setVariable --------------------------------------------------------------------------------+-- ** Constants.++initNamedConstant :: (ConstantCMD :<: instr, pred a)+ => String -> exp a -> ProgramT instr (Param2 exp pred) m (Constant a)+initNamedConstant name = singleInj . NewConstant (Base name)++initConstant :: (ConstantCMD :<: instr, pred a) => exp a -> ProgramT instr (Param2 exp pred) m (Constant a)+initConstant = initNamedConstant "c"++getConstant :: (ConstantCMD :<: instr, pred a, PredicateExp exp a, FreeExp exp, Monad m)+ => Constant a -> ProgramT instr (Param2 exp pred) m (exp a)+getConstant = fmap valToExp . singleInj . GetConstant++--------------------------------------------------------------------------------+-- short-hands.++constant :: (ConstantCMD :<: instr, pred a) => String -> exp a -> ProgramT instr (Param2 exp pred) m (Constant a)+constant = initNamedConstant++-------------------------------------------------------------------------------- -- ** Arrays. --- | Create an uninitialized array.-newArray- :: ( PredicateExp (IExp instr) a- , PredicateExp (IExp instr) i- , Integral i, Ix i- , ArrayCMD (IExp instr) :<: instr )- => IExp instr i -> ProgramT instr m (Array i a)-newArray = singleE . NewArray+-- | Create an initialized named virtual array.+initNamedArray :: (ArrayCMD :<: instr, pred a, Integral i, Ix i)+ => String -> [a] -> ProgramT instr (Param2 exp pred) m (Array i a) +initNamedArray name = singleInj . InitArray (Base name) --- | Create an initialized array.-initArray- :: ( PredicateExp (IExp instr) a- , PredicateExp (IExp instr) i- , Integral i, Ix i- , ArrayCMD (IExp instr) :<: instr )- => [a] -> ProgramT instr m (Array i a) -initArray = singleE . InitArray+-- | Create an initialized virtual array.+initArray :: (ArrayCMD :<: instr, pred a, Integral i, Ix i)+ => [a] -> ProgramT instr (Param2 exp pred) m (Array i a)+initArray = initNamedArray "a" +-- | Create an uninitialized named virtual array.+newNamedArray :: (ArrayCMD :<: instr, pred a, Integral i, Ix i)+ => String -> exp i -> ProgramT instr (Param2 exp pred) m (Array i a)+newNamedArray name = singleInj . NewArray (Base name)++-- | Create an uninitialized virtual array.+newArray :: (ArrayCMD :<: instr, pred a, Integral i, Ix i)+ => exp i -> ProgramT instr (Param2 exp pred) m (Array i a) +newArray = newNamedArray "a"++getArray :: (ArrayCMD :<: instr, pred a, Integral i, Ix i, PredicateExp exp a, FreeExp exp, Monad m)+ => Array i a -> exp i -> ProgramT instr (Param2 exp pred) m (exp a)+getArray a = fmap valToExp . singleInj . GetArray a++-- | Set an element of an array.+setArray :: (ArrayCMD :<: instr, pred a, Integral i, Ix i, PredicateExp exp a, FreeExp exp, Monad m)+ => Array i a -> exp i -> exp a -> ProgramT instr (Param2 exp pred) m ()+setArray a i = singleInj . SetArray a i++-- | Copy a slice of one array to another.+copyArray :: (ArrayCMD :<: instr, pred a, Integral i, Ix i)+ => (Array i a, exp i) -- ^ destination and its offset.+ -> (Array i a, exp i) -- ^ source and its offset.+ -> exp i -- ^ number of elements to copy.+ -> ProgramT instr (Param2 exp pred) m ()+copyArray dest src = singleInj . CopyArray dest src++-- | ...+resetArray :: (ArrayCMD :<: instr, pred a, Integral i, Ix i)+ => Array i a -> exp a -> ProgramT instr (Param2 exp pred) m ()+resetArray a rst = singleInj $ ResetArray a rst++--------------------------------------------------------------------------------+-- ** Virtual arrays.++-- | Create an initialized named virtual array.+initNamedVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i)+ => String -> [a] -> ProgramT instr (Param2 exp pred) m (VArray i a) +initNamedVArray name = singleInj . InitVArray (Base name)++-- | Create an initialized virtual array.+initVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i)+ => [a] -> ProgramT instr (Param2 exp pred) m (VArray i a)+initVArray = initNamedVArray "a"++-- | Create an uninitialized named virtual array.+newNamedVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i)+ => String -> exp i -> ProgramT instr (Param2 exp pred) m (VArray i a)+newNamedVArray name = singleInj . NewVArray (Base name)++-- | Create an uninitialized virtual array.+newVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i)+ => exp i -> ProgramT instr (Param2 exp pred) m (VArray i a)+newVArray = newNamedVArray "a"+ -- | Get an element of an array.-getArray- :: ( PredicateExp (IExp instr) a- , PredicateExp (IExp instr) i- , Integral i, Ix i- , ArrayCMD (IExp instr) :<: instr )- => IExp instr i -> Array i a -> ProgramT instr m (IExp instr a)-getArray i = singleE . GetArray i+getVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i, PredicateExp exp a, FreeExp exp, Monad m)+ => VArray i a -> exp i -> ProgramT instr (Param2 exp pred) m (exp a)+getVArray a = fmap valToExp . singleInj . GetVArray a -- | Set an element of an array.-setArray- :: ( PredicateExp (IExp instr) a- , PredicateExp (IExp instr) i- , Integral i, Ix i- , ArrayCMD (IExp instr) :<: instr )- => IExp instr i -> IExp instr a -> Array i a -> ProgramT instr m ()-setArray i a = singleE . SetArray i a+setVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i)+ => VArray i a -> exp i -> exp a -> ProgramT instr (Param2 exp pred) m ()+setVArray a i = singleInj . SetVArray a i --- | Unsafe version of fetching the contents of an array's index.-unsafeGetArray- :: ( PredicateExp (IExp instr) a- , PredicateExp (IExp instr) i- , Integral i, Ix i- , ArrayCMD (IExp instr) :<: instr )- => IExp instr i -> Array i a -> ProgramT instr m (IExp instr a)-unsafeGetArray i = singleE . UnsafeGetArray i+-- | Copy a slice of one array to another.+copyVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i)+ => (VArray i a, exp i) -- ^ destination and its offset.+ -> (VArray i a, exp i) -- ^ source and its offset.+ -> exp i -- ^ number of elements to copy.+ -> ProgramT instr (Param2 exp pred) m ()+copyVArray dest src = singleInj . CopyVArray dest src +-- | Freeze a mutable array into an immutable one by copying.+freezeVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i, Num (exp i), Monad m)+ => VArray i a -> exp i -> ProgramT instr (Param2 exp pred) m (IArray i a)+freezeVArray array len =+ do copy <- newVArray len+ copyVArray (copy,0) (array,0) len+ unsafeFreezeVArray copy++-- | Thaw an immutable array into a mutable one by copying.+thawVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i, Num (exp i), Monad m)+ => IArray i a -> exp i -> ProgramT instr (Param2 exp pred) m (VArray i a)+thawVArray iarray len =+ do array <- unsafeThawVArray iarray+ copy <- newVArray len+ copyVArray (copy,0) (array,0) len+ return copy++-- | Freeze a mutable array to an immuatable one without making a copy.+unsafeFreezeVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i)+ => VArray i a -> ProgramT instr (Param2 exp pred) m (IArray i a)+unsafeFreezeVArray = singleInj . UnsafeFreezeVArray++-- | Thaw an immutable array to a mutable one without making a copy.+unsafeThawVArray :: (VArrayCMD :<: instr, pred a, Integral i, Ix i)+ => IArray i a -> ProgramT instr (Param2 exp pred) m (VArray i a)+unsafeThawVArray = singleInj . UnsafeThawVArray+ -------------------------------------------------------------------------------- -- ** Looping. -- | For loop.-for- :: (LoopCMD (IExp instr) :<: instr, PredicateExp (IExp instr) n, Integral n)- => IExp instr n- -> (IExp instr n -> ProgramT instr m ())- -> ProgramT instr m ()-for range = singleE . For range+for :: (LoopCMD :<: instr, pred i, Integral i, PredicateExp exp i, FreeExp exp, Monad m)+ => exp i -> exp i -> (exp i -> ProgramT instr (Param2 exp pred) m ()) -> ProgramT instr (Param2 exp pred) m ()+for lower upper body = singleInj $ For lower upper (body . valToExp) -- | While loop.-while- :: (LoopCMD (IExp instr) :<: instr, PredicateExp (IExp instr) Bool)- => ProgramT instr m (IExp instr Bool)- -> ProgramT instr m ()- -> ProgramT instr m ()-while cond = singleE . While cond+while :: (LoopCMD :<: instr, pred Bool)+ => ProgramT instr (Param2 exp pred) m (exp Bool)+ -> ProgramT instr (Param2 exp pred) m ()+ -> ProgramT instr (Param2 exp pred) m ()+while cond = singleInj . While cond -------------------------------------------------------------------------------- -- ** Conditional statements. -- | Conditional statements guarded by if and then clauses with an optional else.-conditional- :: (ConditionalCMD (IExp i) :<: i, PredicateExp (IExp i) Bool)- => (IExp i Bool, ProgramT i m ())- -> [(IExp i Bool, ProgramT i m ())]- -> Maybe (ProgramT i m ())- -> ProgramT i m ()-conditional a bs = singleE . If a bs+conditional :: (ConditionalCMD :<: instr, pred Bool)+ => (exp Bool, ProgramT instr (Param2 exp pred) m ())+ -> [(exp Bool, ProgramT instr (Param2 exp pred) m ())]+ -> Maybe (ProgramT instr (Param2 exp pred) m ())+ -> ProgramT instr (Param2 exp pred) m ()+conditional a bs = singleInj . If a bs -- | Guarded statement.-when- :: (ConditionalCMD (IExp i) :<: i, PredicateExp (IExp i) Bool)- => IExp i Bool- -> ProgramT i m ()- -> ProgramT i m ()+when :: (ConditionalCMD :<: instr, pred Bool)+ => exp Bool+ -> ProgramT instr (Param2 exp pred) m ()+ -> ProgramT instr (Param2 exp pred) m () when e p = conditional (e, p) [] Nothing -- | Standard if-then-else statement.-iff- :: (ConditionalCMD (IExp i) :<: i, PredicateExp (IExp i) Bool)- => IExp i Bool- -> ProgramT i m ()- -> ProgramT i m ()- -> ProgramT i m ()+iff :: (ConditionalCMD :<: instr, pred Bool)+ => exp Bool+ -> ProgramT instr (Param2 exp pred) m ()+ -> ProgramT instr (Param2 exp pred) m ()+ -> ProgramT instr (Param2 exp pred) m () iff b t e = conditional (b, t) [] (Just e) +ifE :: (ConditionalCMD :<: instr, pred Bool)+ => (exp Bool, ProgramT instr (Param2 exp pred) m ())+ -> (exp Bool, ProgramT instr (Param2 exp pred) m ())+ -> ProgramT instr (Param2 exp pred) m ()+ifE a b = conditional a [b] (Nothing)+ --------------------------------------------------------------------------------++switch :: (ConditionalCMD :<: instr, pred a, Eq a, Ord a)+ => exp a+ -> [When a (ProgramT instr (Param2 exp pred) m)]+ -> ProgramT instr (Param2 exp pred) m ()+switch e choices = singleInj (Case e choices Nothing)++switched :: (ConditionalCMD :<: instr, pred a, Eq a, Ord a)+ => exp a+ -> [When a (ProgramT instr (Param2 exp pred) m)]+ -> ProgramT instr (Param2 exp pred) m ()+ -> ProgramT instr (Param2 exp pred) m ()+switched e choices def = singleInj (Case e choices (Just def))++null :: (ConditionalCMD :<: instr) => ProgramT instr (Param2 exp pred) m ()+null = singleInj (Null)++is :: (Eq a, pred a)+ => a+ -> ProgramT instr (Param2 exp pred) m ()+ -> When a (ProgramT instr (Param2 exp pred) m)+is a = When (Is a) ++to :: (Ord a, pred a)+ => a+ -> a+ -> ProgramT instr (Param2 exp pred) m ()+ -> When a (ProgramT instr (Param2 exp pred) m)+to l h = When (To l h)++--------------------------------------------------------------------------------+-- ** Processes.++type Sig instr exp pred m = Signature (Param3 (ProgramT instr (Param2 exp pred) m) exp pred)+type Comp instr exp pred m = Component (Param3 (ProgramT instr (Param2 exp pred) m) exp pred)++-- | Declare a named component.+namedComponent :: (ComponentCMD :<: instr, Monad m)+ => String -> Sig instr exp pred m a+ -> ProgramT instr (Param2 exp pred) m (Comp instr exp pred m a)+namedComponent name sig =+ do n <- singleInj $ StructComponent (Base name) sig+ return $ Component n sig++-- | Declare a component.+component :: (ComponentCMD :<: instr, Monad m)+ => Sig instr exp pred m a+ -> ProgramT instr (Param2 exp pred) m (Comp instr exp pred m a)+component = namedComponent "comp"++-- | Call a component.+portmap :: (ComponentCMD :<: instr)+ => Comp instr exp pred m a+ -> Argument pred a+ -> ProgramT instr (Param2 exp pred) m ()+portmap pro arg = singleInj $ PortMap pro arg++--------------------------------------------------------------------------------++exactInput :: (pred a, Inhabited a, Sized a) => String -> (Signal a -> Sig instr exp pred m b) -> Sig instr exp pred m (Signal a -> b)+exactInput n = SSig (Exact n) In++namedInput :: (pred a, Inhabited a, Sized a) => String -> (Signal a -> Sig instr exp pred m b) -> Sig instr exp pred m (Signal a -> b)+namedInput n = SSig (Base n) In++input :: (pred a, Inhabited a, Sized a) => (Signal a -> Sig instr exp pred m b) -> Sig instr exp pred m (Signal a -> b)+input = namedInput "in"++exactInputArr :: (pred a, Inhabited a, Sized a, pred i, Integral i, Ix i) => String -> i -> (Array i a -> Sig instr exp pred m b) -> Sig instr exp pred m (Array i a -> b)+exactInputArr n l = SArr (Exact n) In l++namedInputArr :: (pred a, Inhabited a, Sized a, pred i, Integral i, Ix i) => String -> i -> (Array i a -> Sig instr exp pred m b) -> Sig instr exp pred m (Array i a -> b)+namedInputArr n l = SArr (Base n) In l++inputArr :: (pred a, Inhabited a, Sized a, pred i, Integral i, Ix i) => i -> (Array i a -> Sig instr exp pred m b) -> Sig instr exp pred m (Array i a -> b)+inputArr = namedInputArr "in"++exactOutput :: (pred a, Inhabited a, Sized a) => String -> (Signal a -> Sig instr exp pred m b) -> Sig instr exp pred m (Signal a -> b)+exactOutput n = SSig (Exact n) Out++namedOutput :: (pred a, Inhabited a, Sized a) => String -> (Signal a -> Sig instr exp pred m b) -> Sig instr exp pred m (Signal a -> b)+namedOutput n = SSig (Base n) Out++output :: (pred a, Inhabited a, Sized a) => (Signal a -> Sig instr exp pred m b) -> Sig instr exp pred m (Signal a -> b)+output = namedOutput "out"++exactOutputArr :: (pred a, Inhabited a, Sized a, pred i, Integral i, Ix i) => String -> i -> (Array i a -> Sig instr exp pred m b) -> Sig instr exp pred m (Array i a -> b)+exactOutputArr n l = SArr (Exact n) Out l++namedOutputArr :: (pred a, Inhabited a, Sized a, pred i, Integral i, Ix i) => String -> i -> (Array i a -> Sig instr exp pred m b) -> Sig instr exp pred m (Array i a -> b)+namedOutputArr n l = SArr (Base n) Out l++outputArr :: (pred a, Inhabited a, pred i, Sized a, Integral i, Ix i) => i -> (Array i a -> Sig instr exp pred m b) -> Sig instr exp pred m (Array i a -> b)+outputArr = namedOutputArr "out"++ret :: (ProgramT instr (Param2 exp pred) m) () -> Signature (Param3 (ProgramT instr (Param2 exp pred) m) exp pred) ()+ret = Ret++-------------------------------------------------------------------------------- -- ** Structural entities. -- | Declare a new entity by wrapping the program to declare ports & generics.-entity :: (StructuralCMD (IExp i) :<: i) => String -> ProgramT i m a -> ProgramT i m a-entity e = singleE . Entity e+entity :: (StructuralCMD :<: instr)+ => String+ -> ProgramT instr (Param2 exp pred) m a+ -> ProgramT instr (Param2 exp pred) m a+entity e = singleInj . StructEntity (Exact e) -- | Declare a new architecture for some entity by wrapping the given program.-architecture :: (StructuralCMD (IExp i) :<: i) => String -> String -> ProgramT i m a -> ProgramT i m a-architecture e a = singleE . Architecture e a+architecture :: (StructuralCMD :<: instr)+ => String -> String+ -> ProgramT instr (Param2 exp pred) m a+ -> ProgramT instr (Param2 exp pred) m a+architecture e a = singleInj . StructArchitecture (Exact e) (Exact a) -- | Declare a new process listening to some signals by wrapping the given program.-process :: (StructuralCMD (IExp i) :<: i) => [SignalX] -> ProgramT i m () -> ProgramT i m ()-process is = singleE . Process is+process :: (StructuralCMD :<: instr)+ => [Ident]+ -> ProgramT instr (Param2 exp pred) m ()+ -> ProgramT instr (Param2 exp pred) m ()+process is = singleInj . StructProcess is +--------------------------------------------------------------------------------++-- | Construct the untyped signal list for processes.+(.:) :: ToIdent a => a -> [Ident] -> [Ident]+(.:) x xs = toIdent x : xs++infixr .:++--------------------------------------------------------------------------------+-- ** VHDL specific instructions.+--+-- todo: these bit operations really do not have to be over just `Bits`, since+-- VHDL treats all of our types as bit vectors anyway.++-- | Short-hand that catures the common pattern:+-- "when (risingEdge clk) (if (not rst) then tru else fls)"+-- assuming reset is triggered on low.+whenRising :: (VHDLCMD :<: instr, pred Bit)+ => Signal Bit -- ^ Clock.+ -> Signal Bit -- ^ Reset.+ -> ProgramT instr (Param2 exp pred) m () -- ^ Reset program.+ -> ProgramT instr (Param2 exp pred) m () -- ^ Normal program.+ -> ProgramT instr (Param2 exp pred) m ()+whenRising clk rst tru fls = singleInj (Rising clk rst tru fls)+ -- | ...-hideSig :: Signal a -> SignalX-hideSig = SignalX+copyBits :: (VHDLCMD :<: instr, pred a, pred b, Integral i, Ix i)+ => (Signal a, exp i)+ -> (Signal b, exp i)+ -> exp i+ -> ProgramT instr (Param2 exp pred) m ()+copyBits a b l = singleInj (CopyBits a b l)++-- | ...+copyVBits :: (VHDLCMD :<: instr, pred a, pred b, Integral i, Ix i)+ => (Variable a, exp i)+ -> (Signal b, exp i)+ -> exp i+ -> ProgramT instr (Param2 exp pred) m ()+copyVBits a b l = singleInj (CopyVBits a b l)++-- | ...+getBit :: (VHDLCMD :<: instr, pred a, Integral i, Ix i, pred Bit, PredicateExp exp Bit, FreeExp exp, Monad m)+ => Signal a -> exp i -> ProgramT instr (Param2 exp pred) m (exp Bit)+getBit bits ix = fmap valToExp $ singleInj $ GetBit bits ix++-- | ...+setBit :: (VHDLCMD :<: instr, pred a, Integral i, Ix i, pred Bit)+ => Signal a -> exp i -> exp Bit -> ProgramT instr (Param2 exp pred) m ()+setBit bits ix bit = singleInj $ SetBit bits ix bit++-- | ...+getBits :: (VHDLCMD :<: instr, pred i, Integral i, Ix i, PredicateExp exp i, FreeExp exp, Monad m)+ => Signal (Bits u)+ -> exp i+ -> exp i+ -> ProgramT instr (Param2 exp pred) m (exp i)+getBits a l u = fmap valToExp $ singleInj $ GetBits a l u --------------------------------------------------------------------------------
src/Language/Embedded/Hardware/Expression.hs view
@@ -2,8 +2,11 @@ ( HExp , HType , module Language.Embedded.Hardware.Expression.Frontend+ , module Language.Embedded.Hardware.Expression.Represent.Bit ) where -import Language.Embedded.Hardware.Expression.Syntax (HExp, HType)+import Language.Embedded.Hardware.Expression.Syntax (HExp) import Language.Embedded.Hardware.Expression.Frontend+import Language.Embedded.Hardware.Expression.Represent (HType)+import Language.Embedded.Hardware.Expression.Represent.Bit import Language.Embedded.Hardware.Expression.Backend.VHDL ()
src/Language/Embedded/Hardware/Expression/Backend/VHDL.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -8,7 +9,7 @@ import Language.Syntactic.Functional (Denotation, evalSym) import Language.Embedded.Hardware.Expression.Syntax-import Language.Embedded.Hardware.Expression.Frontend (value, variable)+import Language.Embedded.Hardware.Expression.Frontend (value, var) import Language.Embedded.Hardware.Expression.Represent import Language.Embedded.Hardware.Expression.Hoist (Kind) import Language.Embedded.Hardware.Interface@@ -18,15 +19,24 @@ import qualified Language.VHDL as VHDL import qualified Language.Embedded.VHDL as VHDL +import Data.Proxy (Proxy(..))+ import Control.Applicative -------------------------------------------------------------------------------- -- * Compilation and evaluation of hardware expressions for VHDL. -------------------------------------------------------------------------------- +instance FreeExp HExp+ where+ type PredicateExp HExp = HType+ litE = value+ varE = var++--------------------------------------------------------------------------------+ instance EvaluateExp HExp where- litE = value evalE = evalHExp evalHExp :: HExp a -> a@@ -40,23 +50,29 @@ instance CompileExp HExp where- varE v = variable ('v' : show v)- compT = compHType compE = compHExp -compHType :: forall a. HType a => HExp a -> VHDL VHDL.Type-compHType _ = declare (undefined :: a) >> return (unTag (typed :: Tagged a VHDL.Type))+compHType :: forall a . HType a => HExp a -> VHDL VHDL.Type+compHType _ = declare (undefined :: proxy a) -compHExp :: forall a. HType a => HExp a -> VHDL VHDL.Expression-compHExp e = Hoist.lift <$> compSimple e+compHTypeFun :: forall a b . (HType a, HType b) => (a -> b) -> VHDL VHDL.Type+compHTypeFun _ = declare (undefined :: proxy a)++compHExp :: forall a . HExp a -> VHDL VHDL.Expression+compHExp e = Hoist.lift <$> compSimple e where compSimple :: HExp b -> VHDL Kind compSimple = simpleMatch (\(T s) -> compDomain s) . unHExp - compLoop :: ASTF T b -> VHDL Kind- compLoop = compSimple . HExp+ compLoop :: ASTF T b -> VHDL Kind+ compLoop = compSimple . HExp - compDomain :: forall sig. HType (DenResult sig) => Dom sig -> Args (AST T) sig -> VHDL Kind+ compDomain+ :: forall sig+ . HType (DenResult sig)+ => Dom sig+ -> Args (AST T) sig+ -> VHDL Kind compDomain expr (x :* y :* _) | Just And <- prj expr = go $ \a b -> VHDL.and [a, b] | Just Or <- prj expr = go $ \a b -> VHDL.or [a, b]@@ -70,6 +86,7 @@ x' <- Hoist.lift <$> compLoop x y' <- Hoist.lift <$> compLoop y return $ Hoist.E $ f x' y'+ compDomain relate (x :* y :* _) | Just Eq <- prj relate = go VHDL.eq | Just Neq <- prj relate = go VHDL.neq@@ -83,6 +100,7 @@ x' <- Hoist.lift <$> compLoop x y' <- Hoist.lift <$> compLoop y return $ Hoist.R $ f x' y'+ compDomain shift (x :* y :* _) | Just Sll <- prj shift = go $ VHDL.sll | Just Srl <- prj shift = go $ VHDL.srl@@ -96,6 +114,7 @@ x' <- Hoist.lift <$> compLoop x y' <- Hoist.lift <$> compLoop y return $ Hoist.Sh $ f x' y'+ compDomain simple (x :* y :* _) | Just Add <- prj simple = go VHDL.add | Just Sub <- prj simple = go VHDL.sub@@ -113,6 +132,7 @@ | Just Pos <- prj simple = do x' <- Hoist.lift <$> compLoop x return $ Hoist.Si x'+ compDomain term (x :* y :* _) | Just Mul <- prj term = go VHDL.mul | Just Div <- prj term = go VHDL.div@@ -124,6 +144,7 @@ x' <- Hoist.lift <$> compLoop x y' <- Hoist.lift <$> compLoop y return $ Hoist.T $ f [x', y']+ compDomain factor (x :* y :* _) | Just Exp <- prj factor = do x' <- Hoist.lift <$> compLoop x@@ -136,24 +157,27 @@ | Just Not <- prj factor = do x' <- Hoist.lift <$> compLoop x return $ Hoist.F $ VHDL.not x'+ compDomain primary (x :* Nil) | Just (Qualified t) <- prj primary = do f <- compHType (undefined :: HExp (DenResult sig)) x' <- Hoist.lift <$> compLoop x return $ Hoist.P $ VHDL.qualified f x'+ | Just (Others) <- prj primary = do+ x' <- Hoist.lift <$> compLoop x+ return $ Hoist.P $ VHDL.aggregate $ VHDL.others x' | Just (Conversion f) <- prj primary = do- t <- compHType (undefined :: HExp (DenResult sig))+ tt <- compHType (undefined :: HExp (DenResult sig))+ tf <- compHTypeFun (f) x' <- Hoist.lift <$> compLoop x- return $ Hoist.P $ VHDL.cast t x'+ return $ Hoist.E $ VHDL.uCast x' tf tt compDomain primary args | Just (Name n) <- prj primary = return $ Hoist.P $ VHDL.name n- | Just (Literal i) <- prj primary = return $ Hoist.P $ VHDL.lit $ format i- | Just (Aggregate xs) <- prj primary =- let maps = fmap (Hoist.lift . VHDL.lit . format)- in return $ Hoist.P $ VHDL.aggregate $ maps xs+ | Just (Literal i) <- prj primary = return $ Hoist.P $ VHDL.literal $ VHDL.number $ printVal i+ | Just (Aggregate a) <- prj primary = return $ Hoist.P $ VHDL.aggregate a | Just (Function f _) <- prj primary = do as <- sequence $ listArgs compLoop args- return $ Hoist.P $ VHDL.function (VHDL.Ident f) (fmap Hoist.lift as)- | Just (Allocator) <- prj primary = undefined+ return $ Hoist.P $ VHDL.function (VHDL.simple f) (fmap Hoist.lift as)+ | Just (Allocator) <- prj primary = error "expression-backend: todo" --------------------------------------------------------------------------------
src/Language/Embedded/Hardware/Expression/Frontend.hs view
@@ -1,91 +1,187 @@+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+ module Language.Embedded.Hardware.Expression.Frontend where -import Language.Embedded.Hardware.Expression.Syntax+import qualified Language.VHDL as V -import Data.Bits (Bits)+import Language.Embedded.Hardware.Interface+import Language.Embedded.Hardware.Expression.Syntax hiding (Term, Factor, Primary)+import Language.Embedded.Hardware.Expression.Hoist+import Language.Embedded.Hardware.Expression.Represent+import Language.Embedded.Hardware.Expression.Represent.Bit+import qualified Language.Embedded.VHDL.Monad.Expression as V +import Data.Typeable (Typeable)+import qualified Data.Bits as B (Bits)+ import Prelude hiding (not, and, or, abs, rem, div, mod, exp) import qualified Prelude as P +import GHC.TypeLits+ ----------------------------------------------------------------------------------- *+-- * ... -------------------------------------------------------------------------------- --- | Lifts a typed value to an expression.-value :: HType a => a -> HExp a-value i = sugarT (Literal i)+type Hardware exp =+ ( Expr exp+ , Rel exp+ , Shift exp+ , Simple exp+ , Term exp+ , Factor exp+ , Primary exp) --- | Creates a variable from a string.-variable :: HType a => String -> HExp a-variable = sugarT . Name+-------------------------------------------------------------------------------- --- | Casts an expression using supplied conversion function.-cast :: (HType a, HType b) => (a -> b) -> HExp a -> HExp b-cast f = sugarT (Conversion f)+-- | Logical operators.+class Expr exp where+ true :: exp Bool+ false :: exp Bool+ and :: exp Bool -> exp Bool -> exp Bool+ or :: exp Bool -> exp Bool -> exp Bool+ xor :: exp Bool -> exp Bool -> exp Bool+ xnor :: exp Bool -> exp Bool -> exp Bool+ nand :: exp Bool -> exp Bool -> exp Bool+ nor :: exp Bool -> exp Bool -> exp Bool +instance Expr HExp where+ true = value True+ false = value False+ and = sugarT And+ or = sugarT Or+ xor = sugarT Xor+ xnor = sugarT Xnor+ nand = sugarT Nand+ nor = sugarT Nor+ -------------------------------------------------------------------------------- -true, false :: HExp Bool-true = value True-false = value False+-- | Relational operators.+class Rel exp where+ eq :: (HType a, Eq a) => exp a -> exp a -> exp Bool+ neq :: (HType a, Eq a) => exp a -> exp a -> exp Bool+ lt :: (HType a, Ord a) => exp a -> exp a -> exp Bool+ lte :: (HType a, Ord a) => exp a -> exp a -> exp Bool+ gt :: (HType a, Ord a) => exp a -> exp a -> exp Bool+ gte :: (HType a, Ord a) => exp a -> exp a -> exp Bool --- logical operators-and, or, xor, xnor, nand, nor :: HExp Bool -> HExp Bool -> HExp Bool-and = sugarT And-or = sugarT Or-xor = sugarT Xor-xnor = sugarT Xnor-nand = sugarT Nand-nor = sugarT Nor+instance Rel HExp where+ eq = sugarT Eq+ neq = sugarT Neq+ lt = sugarT Lt+ lte = sugarT Lte+ gt = sugarT Gt+ gte = sugarT Gte --- relational operators-eq, neq :: (HType a, Eq a) => HExp a -> HExp a -> HExp Bool-eq = sugarT Eq-neq = sugarT Neq+-------------------------------------------------------------------------------- -lt, lte, gt, gte :: (HType a, Ord a) => HExp a -> HExp a -> HExp Bool-lt = sugarT Lt-lte = sugarT Lte-gt = sugarT Gt-gte = sugarT Gte+-- | Shift operators.+class Shift exp where+ sll :: (HType a, B.Bits a) => exp a -> exp Integer -> exp a+ srl :: (HType a, B.Bits a) => exp a -> exp Integer -> exp a+ sla :: (HType a, B.Bits a) => exp a -> exp Integer -> exp a+ sra :: (HType a, B.Bits a) => exp a -> exp Integer -> exp a+ rol :: (HType a, B.Bits a) => exp a -> exp Integer -> exp a+ ror :: (HType a, B.Bits a) => exp a -> exp Integer -> exp a --- shift operators-sll, srl, sla, sra, rol, ror :: (HType a, Bits a, HType b, Integral b) => HExp a -> HExp b -> HExp a-sll = sugarT Sll-srl = sugarT Srl-sla = sugarT Sla-sra = sugarT Sra-rol = sugarT Rol-ror = sugarT Ror+instance Shift HExp where+ sll = sugarT Sll+ srl = sugarT Srl+ sla = sugarT Sla+ sra = sugarT Sra+ rol = sugarT Rol+ ror = sugarT Ror --- adding operators-add, sub :: (HType a, Num a) => HExp a -> HExp a -> HExp a-add = sugarT Add-sub = sugarT Sub+-------------------------------------------------------------------------------- -cat :: (HType a, Read a, Show a) => HExp a -> HExp a -> HExp a-cat = sugarT Cat+-- | Adding operators.+class Simple exp where+ neg :: (HType a, Num a) => exp a -> exp a+ add :: (HType a, Num a) => exp a -> exp a -> exp a+ sub :: (HType a, Num a) => exp a -> exp a -> exp a+ cat :: ( KnownNat n, KnownNat m, KnownNat (n + m), Typeable (n + m))+ => exp (Bits n) -> exp (Bits m) -> exp (Bits (n + m)) --- multiplying operators-mul :: (HType a, Num a) => HExp a -> HExp a -> HExp a-mul = sugarT Mul+instance Simple HExp where+ neg = sugarT Neg+ add = sugarT Add+ sub = sugarT Sub+ cat = sugarT Cat -div, mod, rem :: (HType a, Integral a) => HExp a -> HExp a -> HExp a-div = sugarT Div-mod = sugarT Mod-rem = sugarT Rem+-------------------------------------------------------------------------------- --- miscellaneous operators-exp :: (HType a, Num a, HType b, Integral b) => HExp a -> HExp b -> HExp a-exp = sugarT Exp+-- | Multiplying operators.+class Term exp where+ mul :: (HType a, Num a) => exp a -> exp a -> exp a+ div :: (HType a, Integral a) => exp a -> exp a -> exp a+ mod :: (HType a, Integral a) => exp a -> exp a -> exp a+ rem :: (HType a, Integral a) => exp a -> exp a -> exp a -abs :: (HType a, Num a) => HExp a -> HExp a-abs = sugarT Abs+instance Term HExp where+ mul = sugarT Mul+ div = sugarT Div+ mod = sugarT Mod+ rem = sugarT Rem -not :: HExp Bool -> HExp Bool-not = sugarT Not+-------------------------------------------------------------------------------- +-- | Miscellaneous operators.+class Factor exp where+ exp :: (HType a, Num a, HType b, Integral b) => exp a -> exp b -> exp a+ abs :: (HType a, Num a) => exp a -> exp a+ not :: exp Bool -> exp Bool++instance Factor HExp where+ exp = sugarT Exp+ abs = sugarT Abs+ not = sugarT Not+ --------------------------------------------------------------------------------++-- | Primary operations.+class Primary exp where+ value :: HType a => a -> exp a+ name :: HType a => String -> exp a+ cast :: (HType a, HType b) => (a -> b) -> exp a -> exp b+ +instance Primary HExp where+ value = sugarT . Literal+ name n = sugarT (Name (V.NSimple (V.Ident n)))+ cast f = sugarT (Conversion f)++-- | Creates a variable from a string.+var :: (Primary exp, HType a) => String -> exp a+var = name++-- | Converts an integral (signed/unsigned/integer) to an integer.+toInteger :: (Primary exp, HType a, Integral a) => exp a -> exp Integer+toInteger = cast (fromIntegral)++-- | Converts an integral to a signed value.+toSigned :: (Primary exp, HType a, HType b, Integral a, Num b) => exp a -> exp b+toSigned = cast (fromIntegral)++-- | Converts an integral to a unsigned value.+toUnsigned :: (Primary exp, HType a, HType b, Integral a, Num b) => exp a -> exp b+toUnsigned = cast (fromIntegral)++-- | Converts an integral to its bit representation.+toBits :: (Primary exp, HType a, HType (Bits b), Integral a, KnownNat b) => exp a -> exp (Bits b)+toBits = cast (bitFromInteger . fromIntegral)++--------------------------------------------------------------------------------++fromBits :: (Primary exp, HType (Bits a), HType b, Num b, KnownNat a) => exp (Bits a) -> exp b+fromBits = cast (fromIntegral . bitToInteger)++--------------------------------------------------------------------------------+-- I should probably not support most of these, as they can't implement the+-- interfaces fully. Would perhaps be better to implement my own versions+-- of the type classes. instance (HType a, Eq a) => Eq (HExp a) where
src/Language/Embedded/Hardware/Expression/Represent.hs view
@@ -1,161 +1,194 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+ module Language.Embedded.Hardware.Expression.Represent- ( Tagged (..)- , Rep (..)+ ( Rep(..)+ , Inhabited(..)+ , Sized(..)+ , HType(..)+ + , declareBoolean+ , declareNumeric+ , declareFloating+ + , module Data.Int+ , module Data.Word ) where -import Language.Embedded.VHDL (VHDL)-import Language.Embedded.VHDL.Monad (newLibrary, newImport)+import qualified Language.VHDL as V++import Language.VHDL (Expression)++import Language.Embedded.VHDL (VHDL)+import Language.Embedded.VHDL.Monad (newSym, newLibrary, newImport) import Language.Embedded.VHDL.Monad.Type+import qualified Language.Embedded.VHDL.Monad.Util as Util (printBits) +import Language.Embedded.Hardware.Expression.Hoist (lift)++import Data.Char (isDigit) import Data.Int import Data.Word--import Data.Char (intToDigit)-import Data.Bits (shiftR)-import Text.Printf (printf)-import Numeric (showIntAtBase)--import Data.ByteString (ByteString)-import qualified Data.ByteString as B+import Data.Typeable+import Text.Printf ----------------------------------------------------------------------------------- * Representable types (until I come up with a solution free of VHDL stuff).+-- * Representation of types. -------------------------------------------------------------------------------- --- | Tag a value with some (possibly) interesting information-newtype Tagged s b = Tag { unTag :: b }+-- | Collection of required classes for hardware expressions.+class (Typeable a, Rep a, Eq a) => HType a+instance (Typeable a, Rep a, Eq a) => HType a --- | A 'rep'resentable value.+--------------------------------------------------------------------------------+-- ** Representable types.++-- | 'Rep'resentable types. class Rep a where- width :: Tagged a Int- typed :: Tagged a Type- declare :: a -> VHDL ()- format :: a -> String--declareBoolean :: VHDL ()-declareBoolean =- do newLibrary "IEEE"- newImport "IEEE.std_logic_1164"--declareNumeric :: VHDL ()-declareNumeric =- do newLibrary "IEEE"- newImport "IEEE.std_logic_1164"- newImport "IEEE.numeric_std"--declareFloating :: VHDL ()-declareFloating =- do newLibrary "IEEE"- newImport "IEEE.float_pkg"------------------------------------------------------------------------------------- ** Boolean+ declare :: proxy a -> VHDL Type+ printVal :: a -> String+ printBits :: a -> String instance Rep Bool where- width = Tag 1- typed = Tag std_logic- declare _ = declareBoolean- format True = "1"- format False = "0"------------------------------------------------------------------------------------- ** Signed+ declare _ = declareBoolean >> return std_logic+ printVal True = "\'1\'"+ printVal False = "\'0\'"+ printBits = printVal instance Rep Int8 where- width = Tag 8- typed = Tag signed8- declare _ = declareNumeric- format = convert+ declare _ = declareNumeric >> return signed8+ printVal = show+ printBits = Util.printBits 8 instance Rep Int16 where- width = Tag 16- typed = Tag signed16- declare _ = declareNumeric- format = convert+ declare _ = declareNumeric >> return signed16+ printVal = show+ printBits = Util.printBits 16 instance Rep Int32 where- width = Tag 32- typed = Tag signed32- declare _ = declareNumeric- format = convert+ declare _ = declareNumeric >> return signed32+ printVal = show+ printBits = Util.printBits 32 instance Rep Int64 where- width = Tag 64- typed = Tag signed64- declare _ = declareNumeric- format = convert------------------------------------------------------------------------------------- ** Unsigned+ declare _ = declareNumeric >> return signed64+ printVal = show+ printBits = Util.printBits 64 instance Rep Word8 where- width = Tag 8- typed = Tag usigned8- declare _ = declareNumeric- format = convert+ declare _ = declareNumeric >> return usigned8+ printVal = show+ printBits = Util.printBits 8 instance Rep Word16 where- width = Tag 16- typed = Tag usigned16- declare _ = declareNumeric- format = convert+ declare _ = declareNumeric >> return usigned16+ printVal = show+ printBits = Util.printBits 16 instance Rep Word32 where- width = Tag 32- typed = Tag usigned32- declare _ = declareNumeric- format = convert+ declare _ = declareNumeric >> return usigned32+ printVal = show+ printBits = Util.printBits 32 instance Rep Word64 where- width = Tag 64- typed = Tag usigned64- declare _ = declareNumeric- format = convert+ declare _ = declareNumeric >> return usigned64+ printVal = show+ printBits = Util.printBits 64 ------------------------------------------------------------------------------------ ** Floating point.+instance Rep Int where+ declare _ = return (integer Nothing)+ printVal = show+ printBits = error "hardware-edsl.printBits: int." +instance Rep Integer where+ declare _ = return (integer Nothing)+ printVal = show+ printBits = error "hardware-edsl.printBits: integer."+ instance Rep Float where- width = Tag 32- typed = Tag float- declare _ = declareFloating- format = error "todo: format float."+ declare _ = declareFloating >> return float+ printVal = show+ printBits = error "hardware-edsl.printBits: float." instance Rep Double where- width = Tag 64- typed = Tag double- declare _ = declareFloating- format = error "todo: format double."+ declare _ = declareFloating >> return double+ printVal = show+ printBits = error "hardware-edsl.printBits: double." ------------------------------------------------------------------------------------ * Converting Integers to their Binrary representation+-- | Declare the necessary libraries to support boolean operations.+declareBoolean :: VHDL ()+declareBoolean =+ do newLibrary "IEEE"+ newImport "IEEE.std_logic_1164"++-- | Declare the necessary libraries to support numerical operations.+declareNumeric :: VHDL ()+declareNumeric =+ do newLibrary "IEEE"+ newImport "IEEE.std_logic_1164"+ newImport "IEEE.numeric_std"++-- | Declare the necessary libraries to support floating point operations.+declareFloating :: VHDL ()+declareFloating =+ do newLibrary "IEEE"+ newImport "IEEE.float_pkg"+ --------------------------------------------------------------------------------+-- ** Inhabited types. --- | Convert an Integral to its binary representation-convert :: Integral a => a -> String-convert = foldr1 (++) . fmap w2s . B.unpack . i2bs . toInteger+-- | Inhabited types, that is, types with a base element.+class Inhabited a+ where+ -- | Ground value.+ reset :: a --- | Go over an Integer and convert it into a bytestring containing its--- binary representation-i2bs :: Integer -> ByteString-i2bs x = B.reverse . B.unfoldr (fmap chunk) . Just $ sign x+instance Inhabited Bool where reset = False+instance Inhabited Int8 where reset = 0+instance Inhabited Int16 where reset = 0+instance Inhabited Int32 where reset = 0+instance Inhabited Int64 where reset = 0+instance Inhabited Word8 where reset = 0+instance Inhabited Word16 where reset = 0+instance Inhabited Word32 where reset = 0+instance Inhabited Word64 where reset = 0+instance Inhabited Int where reset = 0+instance Inhabited Integer where reset = 0+instance Inhabited Float where reset = 0+instance Inhabited Double where reset = 0++--------------------------------------------------------------------------------+-- ** Sized types.++-- | Types with a known size.+class Sized a where- sign :: (Num a, Ord a) => a -> a- sign | x < 0 = subtract 1 . negate- | otherwise = id+ -- | Bits required to represent values of type 'a'.+ bits :: proxy a -> Integer - chunk :: Integer -> (Word8, Maybe Integer)- chunk x = (b, i)- where- b = sign (fromInteger x)- i | x >= 128 = Just (x `shiftR` 8)- | otherwise = Nothing+instance Sized Bool where bits _ = 1+instance Sized Int8 where bits _ = 8+instance Sized Int16 where bits _ = 16+instance Sized Int32 where bits _ = 32+instance Sized Int64 where bits _ = 64+instance Sized Word8 where bits _ = 8+instance Sized Word16 where bits _ = 16+instance Sized Word32 where bits _ = 32+instance Sized Word64 where bits _ = 64 --- | Shows a word with zero padding------ I assum the negative numbers to already be padded with ones-w2s :: Word8 -> String-w2s w = printf "%08s" $ showIntAtBase 2 intToDigit w ""+--------------------------------------------------------------------------------+-- ** Hmm...++instance Num Bool where+ (+) = error "(+) not implemented for Bool"+ (-) = error "(-) not implemented for Bool"+ (*) = error "(*) not implemented for Bool"+ abs = id+ signum = id+ fromInteger 0 = False+ fromInteger 1 = True+ fromInteger _ = error "bool-num: >1" --------------------------------------------------------------------------------
+ src/Language/Embedded/Hardware/Expression/Represent/Bit.hs view
@@ -0,0 +1,338 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Language.Embedded.Hardware.Expression.Represent.Bit+ ( Bit+ , Bits+ , ni+ , bitFromInteger+ , bitToInteger+ , bitAdd+ , bitAdd'+ , bitSub+ , bitSub'+ , bitMul+ , bitMul'+ , bitQuotRem+ , bitNeg+ , bitReadsPrec+ , bitMinBound+ , bitMaxBound+ , bitSigNum+ , bitAnd+ , bitOr+ , bitXor+ , bitComplement+ , bitSplit+ , bitJoin+ , bitCoerce+ , bitShiftR+ , bitShiftL+ , bitTestBit+ , bitRotate+ , bitToList+ , bitShowBin+ , bitShowHex++ , UBits+ , forgetBits+ , recallBits+ )+ where++import Language.Embedded.Hardware.Expression.Represent++import Language.Embedded.VHDL (VHDL)+import Language.Embedded.VHDL.Monad (newSym, newLibrary, newImport)+import Language.Embedded.VHDL.Monad.Type++import Data.Ix+import Data.Typeable+import Data.Bits hiding (Bits)+import qualified Data.Bits as Bit (Bits)++import Control.Monad (guard)+import Control.DeepSeq (NFData(..))++import Data.Char (intToDigit)+import qualified Numeric as N++import GHC.TypeLits++--------------------------------------------------------------------------------+-- * ...+--------------------------------------------------------------------------------++--------------------------------------------------------------------------------+-- ** Single bit.++type Bit = Bool++--------------------------------------------------------------------------------+-- These aren't great to have..++instance Real Bool+ where+ toRational = error "toRational not implemented for bit."++instance Integral Bool+ where+ toInteger True = 1+ toInteger False = 0+ quotRem = error "quotRem not implemented for bit."++--------------------------------------------------------------------------------+-- ** Bit vectors of known lenght.++newtype Bits (n :: Nat) = B Integer++instance forall n. KnownNat n => Inhabited (Bits n)+ where+ reset = bitFromInteger 0++instance forall n. KnownNat n => Rep (Bits n)+ where+ declare = declareBits+ printVal = show . bitToInteger+ printBits b = '\"' : (tail $ bitShowBin b) ++ ['\"'] -- *** why tail?++instance forall n. KnownNat n => Sized (Bits n)+ where+ bits _ = ni (Proxy::Proxy n)++deriving instance Typeable (Bits n)++declareBits :: forall proxy n. KnownNat n => proxy (Bits n) -> VHDL Type+declareBits _ = declareBoolean >> return (std_logic_vector size)+ where size = fromInteger (ni (undefined :: Bits n))+ +--------------------------------------------------------------------------------+-- *** ...++ni :: KnownNat n => proxy n -> Integer+ni = fromIntegral . natVal++norm :: KnownNat n => Bits n -> Bits n+norm b@(B n) = B (n .&. ((1 `shiftL` fromInteger (ni b)) - 1))++bitFromInteger :: KnownNat n => Integer -> Bits n+bitFromInteger i = norm (B i)++bitToInteger :: Bits n -> Integer+bitToInteger (B i) = i++--------------------------------------------------------------------------------+-- *** ...++lift1 :: KnownNat n => (Integer -> Integer) -> Bits n -> Bits n+lift1 f (B i) = norm (B (f i))++lift2 :: KnownNat n => (Integer -> Integer -> Integer) -> Bits n -> Bits n -> Bits n+lift2 f (B i) (B j) = norm (B (f i j))++--------------------------------------------------------------------------------+-- *** ...++bitAdd :: KnownNat n => Bits n -> Bits n -> Bits n+bitAdd = lift2 (+)++bitSub :: KnownNat n => Bits n -> Bits n -> Bits n+bitSub = lift2 (-)++bitMul :: KnownNat n => Bits n -> Bits n -> Bits n+bitMul = lift2 (*)++bitAdd' :: Bits n -> Bits n -> Bits (n + 1)+bitAdd' (B i) (B j) = B (i + j)++bitSub' :: Bits n -> Bits n -> Bits (n + 1)+bitSub' (B i) (B j) = B (i - j)++bitMul' :: Bits n -> Bits n -> Bits (n + n)+bitMul' (B i) (B j) = B (i * j)++bitQuotRem :: Bits n -> Bits n -> (Bits n, Bits n)+bitQuotRem (B i) (B j) = let (a, b) = quotRem i j in (B a, B b)++bitNeg :: KnownNat n => Bits n -> Bits n+bitNeg = lift1 negate++bitMinBound :: Bits n+bitMinBound = B 0++bitMaxBound :: KnownNat n => Bits n+bitMaxBound = norm (B (-1))++bitSigNum :: Bits n -> Bits n+bitSigNum (B i) = B (signum i)++bitAnd :: Bits n -> Bits n -> Bits n+bitAnd (B i) (B j) = B (i .&. j)++bitOr :: Bits n -> Bits n -> Bits n+bitOr (B i) (B j) = B (i .|. j)++bitXor :: Bits n -> Bits n -> Bits n+bitXor (B i) (B j) = B (i .|. j)++bitComplement :: KnownNat n => Bits n -> Bits n+bitComplement = lift1 complement++bitSplit :: (KnownNat m, KnownNat n) => proxy m -> Bits (m + n) -> (Bits m, Bits n)+bitSplit m (B i) = (a, b)+ where a = B (i `shiftR` fromInteger (ni m))+ b = bitFromInteger i++bitJoin :: KnownNat n => Bits m -> Bits n -> Bits (m + n)+bitJoin (B i) b@(B j) = B (shiftL i (fromInteger (ni b)) .|. j)++bitCoerce :: forall n m. (KnownNat n, KnownNat m) => Bits n -> Maybe (Bits m)+bitCoerce b@(B i) = guard (ni b == ni d) >> return (B i)+ where d = undefined :: Bits m++bitShiftR :: Bits n -> Int -> Bits n+bitShiftR (B i) n = B (shiftR i n)++bitShiftL :: KnownNat n => Bits n -> Int -> Bits n+bitShiftL b n = lift1 (`shiftL` n) b++bitTestBit :: Bits n -> Int -> Bool+bitTestBit (B i) n = testBit i n++bitRotate :: KnownNat n => Bits n -> Int -> Bits n+bitRotate b@(B i) n+ | si < 2 = b+ | otherwise = bitOr (bitFromInteger (shiftL i n)) (bitFromInteger (shiftR i (si - n)))+ where n' = mod n si+ si = fromInteger (ni b)++bitToList :: KnownNat n => Bits n -> [Bool]+bitToList b = map (bitTestBit b) [start, start - 1 .. 0]+ where start = fromInteger (ni b)++bitReadsPrec :: KnownNat n => Int -> ReadS (Bits n)+bitReadsPrec p txt = [ (bitFromInteger b, cs) | (b, cs) <- readsPrec p txt ]++bitShowBin :: KnownNat n => Bits n -> String+bitShowBin = map sh . bitToList+ where sh x = if x then '1' else '0'++bitShowHex :: KnownNat n => Bits n -> String+bitShowHex b@(B i) = zeros (N.showHex i "")+ where zeros n = replicate (len - length n) '0' ++ n+ len = div (fromInteger (ni b) + 3) 4++--------------------------------------------------------------------------------++instance Show (Bits n) where+ showsPrec p (B x) = showsPrec p x++instance KnownNat n => Read (Bits n) where+ readsPrec = bitReadsPrec++instance Eq (Bits n) where+ B i == B j = i == j++instance NFData (Bits n) where+ rnf (B i) = seq i ()++instance Ord (Bits n) where+ compare (B i) (B j) = compare i j++instance KnownNat n => Bounded (Bits n) where+ minBound = bitMinBound+ maxBound = bitMaxBound++instance KnownNat n => Num (Bits n) where+ (+) = bitAdd+ (-) = bitSub+ (*) = bitMul+ negate = bitNeg+ abs = id+ signum = bitSigNum+ fromInteger = bitFromInteger++instance KnownNat n => Bit.Bits (Bits n) where+ isSigned _ = False+ bit = bitFromInteger . (2 ^)+ bitSize = fromInteger . ni+ bitSizeMaybe = Just . fromInteger . ni+ (.&.) = bitAnd+ (.|.) = bitOr+ xor = bitXor+ complement = bitComplement+ shiftR = bitShiftR+ shiftL = bitShiftL+ testBit = bitTestBit+ rotate = bitRotate+ popCount = length . filter id . bitToList++instance KnownNat n => Real (Bits n) where+ toRational (B i) = toRational i++instance KnownNat n => Enum (Bits n) where+ toEnum i = norm $ B $ toEnum i+ fromEnum (B i) = fromEnum i+ succ i = i + 1+ pred i = if i == minBound then maxBound else i - 1+ enumFrom i = enumFromTo i maxBound+ enumFromTo i j+ | i < j = enumFromThenTo i (succ i) j+ | i == j = [i]+ | otherwise = []++ enumFromThen x y = enumFromThenTo x y bound+ where+ bound | x <= y = maxBound+ | otherwise = minBound++ enumFromThenTo (B i) (B j) (B k) = map B (enumFromThenTo i j k)++instance KnownNat n => Integral (Bits n) where+ toInteger = bitToInteger+ quotRem = bitQuotRem++instance KnownNat n => Ix (Bits n) where+ range = undefined+ index = undefined+ inRange = undefined++--------------------------------------------------------------------------------+-- ** Bit vectors of unknown lenght.++newtype UBits = UB Integer+ deriving (Eq, Enum, Ord, Num, Real, Integral)++instance Rep UBits+ where+ declare = declareUBits+ printVal = show+ -- *** This is bad and produces a warning in vhdl as there's no guarantee+ -- that the lenght of the printed binary will be the expected one.+ -- Give UB an extra 'Maybe Integer' for storing the length whenever its+ -- available.+ printBits (UB i) = '\"' : (N.showIntAtBase 2 intToDigit i "") ++ ['\"']+ ++declareUBits :: proxy UBits -> VHDL Type+declareUBits _ = declareBoolean >> return std_logic++--------------------------------------------------------------------------------++forgetBits :: Bits n -> UBits+forgetBits b = UB (bitToInteger b)++recallBits :: KnownNat n => UBits -> Bits n+recallBits (UB i) = (B i)++--------------------------------------------------------------------------------++instance Show UBits where+ showsPrec p (UB x) = showsPrec p x++--------------------------------------------------------------------------------
src/Language/Embedded/Hardware/Expression/Syntax.hs view
@@ -1,40 +1,39 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE DataKinds #-} module Language.Embedded.Hardware.Expression.Syntax where import Language.Syntactic import Language.Syntactic.Functional (Denotation, Eval(..), EvalEnv) -import Language.Embedded.Hardware.Command+import qualified Language.VHDL as V (Name, Aggregate)++import Language.Embedded.Hardware.Command (CompArrayIx) import Language.Embedded.Hardware.Interface import Language.Embedded.Hardware.Expression.Represent+import Language.Embedded.Hardware.Expression.Represent.Bit -import Data.Bits (Bits) import Data.Typeable (Typeable)-import qualified Data.Bits as Bits+import qualified Data.Bits as B +import GHC.TypeLits hiding (Symbol)+ -------------------------------------------------------------------------------- -- * Syntax of hardware expressions. -------------------------------------------------------------------------------- --- | Collection of required classes for hardware expressions.-class (Typeable a, Rep a, Eq a) => HType a-instance (Typeable a, Rep a, Eq a) => HType a--type instance PredicateExp HExp = HType- -- | Domain of expressions. type Dom = Expression :+: Relational- :+: Shift- :+: Simple+ :+: ShiftExpression+ :+: SimpleExpression :+: Term :+: Factor :+: Primary@@ -64,7 +63,7 @@ type Internal (HExp a) = a desugar = unHExp- sugar = HExp+ sugar = HExp -------------------------------------------------------------------------------- -- ** Syntax.@@ -90,23 +89,24 @@ Gte :: (HType a, Ord a) => Relational (a :-> a :-> Full Bool) -- | Bit vector expressions.-data Shift sig+data ShiftExpression sig where- Sll :: (HType a, Bits a, HType b, Integral b) => Shift (a :-> b :-> Full a)- Srl :: (HType a, Bits a, HType b, Integral b) => Shift (a :-> b :-> Full a)- Sla :: (HType a, Bits a, HType b, Integral b) => Shift (a :-> b :-> Full a)- Sra :: (HType a, Bits a, HType b, Integral b) => Shift (a :-> b :-> Full a)- Rol :: (HType a, Bits a, HType b, Integral b) => Shift (a :-> b :-> Full a)- Ror :: (HType a, Bits a, HType b, Integral b) => Shift (a :-> b :-> Full a)+ Sll :: (HType a, B.Bits a) => ShiftExpression (a :-> Integer :-> Full a)+ Srl :: (HType a, B.Bits a) => ShiftExpression (a :-> Integer :-> Full a)+ Sla :: (HType a, B.Bits a) => ShiftExpression (a :-> Integer :-> Full a)+ Sra :: (HType a, B.Bits a) => ShiftExpression (a :-> Integer :-> Full a)+ Rol :: (HType a, B.Bits a) => ShiftExpression (a :-> Integer :-> Full a)+ Ror :: (HType a, B.Bits a) => ShiftExpression (a :-> Integer :-> Full a) -- | Numerical expressions.-data Simple sig+data SimpleExpression sig where- Neg :: (HType a, Num a) => Simple (a :-> Full a)- Pos :: (HType a, Num a) => Simple (a :-> Full a)- Add :: (HType a, Num a) => Simple (a :-> a :-> Full a)- Sub :: (HType a, Num a) => Simple (a :-> a :-> Full a)- Cat :: (HType a, Show a, Read a) => Simple (a :-> a :-> Full a)+ Neg :: (HType a, Num a) => SimpleExpression (a :-> Full a)+ Pos :: (HType a, Num a) => SimpleExpression (a :-> Full a)+ Add :: (HType a, Num a) => SimpleExpression (a :-> a :-> Full a)+ Sub :: (HType a, Num a) => SimpleExpression (a :-> a :-> Full a)+ Cat :: (KnownNat n, KnownNat m)+ => SimpleExpression (Bits n :-> Bits m :-> Full (Bits (n + m))) -- | Integral expressions. data Term sig@@ -126,14 +126,16 @@ -- | ... data Primary sig where- Name :: (HType a) => String -> Primary (Full a)- Literal :: (HType a) => a -> Primary (Full a)- Aggregate :: (HType a) => [a] -> Primary (Full [a])+ Name :: (HType a) => V.Name -> Primary (Full a)+ Literal :: (HType a) => a -> Primary (Full a)+ Aggregate :: (HType a) => V.Aggregate -> Primary (Full a) Function :: (Signature sig) => String -> Denotation sig -> Primary sig Qualified :: (HType a, HType b) => b -> Primary (a :-> Full a) Conversion :: (HType a, HType b) => (a -> b) -> Primary (a :-> Full b) Allocator :: (HType a) => Primary (Full a)-+ -- *** todo: expanded aggregate+ Others :: Primary (Bit :-> Full (Bits n))+ -------------------------------------------------------------------------------- -- ** Syntactic instances. @@ -221,10 +223,10 @@ instance EvalEnv Relational env -instance Equality Shift-instance StringTree Shift+instance Equality ShiftExpression+instance StringTree ShiftExpression -instance Symbol Shift+instance Symbol ShiftExpression where symSig Sll = signature symSig Srl = signature@@ -233,7 +235,7 @@ symSig Rol = signature symSig Ror = signature -instance Render Shift+instance Render ShiftExpression where renderSym Sll = "sll" renderSym Srl = "srl"@@ -242,27 +244,27 @@ renderSym Rol = "rol" renderSym Ror = "ror" -instance Eval Shift+instance Eval ShiftExpression where- evalSym Sll = \x i -> Bits.shiftL x (fromIntegral i)+ evalSym Sll = \x i -> B.shiftL x (fromIntegral i) evalSym Srl = \x i -> shiftLR x (fromIntegral i) where- shiftLR :: Bits a => a -> Int -> a- shiftLR x n = let y = Bits.shiftR x n in- case Bits.bitSizeMaybe x of- Just i -> foldr (flip Bits.clearBit) y [i - n `Prelude.mod` i .. i]+ shiftLR :: B.Bits a => a -> Int -> a+ shiftLR x n = let y = B.shiftR x n in+ case B.bitSizeMaybe x of+ Just i -> foldr (flip B.clearBit) y [i - n `Prelude.mod` i .. i] Nothing -> y- evalSym Sla = \x i -> Bits.shiftL x (fromIntegral i)- evalSym Sra = \x i -> Bits.shiftR x (fromIntegral i)- evalSym Rol = \x i -> Bits.rotateL x (fromIntegral i)- evalSym Ror = \x i -> Bits.rotateR x (fromIntegral i)+ evalSym Sla = \x i -> B.shiftL x (fromIntegral i)+ evalSym Sra = \x i -> B.shiftR x (fromIntegral i)+ evalSym Rol = \x i -> B.rotateL x (fromIntegral i)+ evalSym Ror = \x i -> B.rotateR x (fromIntegral i) -instance EvalEnv Shift env+instance EvalEnv ShiftExpression env -instance Equality Simple-instance StringTree Simple+instance Equality SimpleExpression+instance StringTree SimpleExpression -instance Symbol Simple+instance Symbol SimpleExpression where symSig Neg = signature symSig Pos = signature@@ -270,7 +272,7 @@ symSig Sub = signature symSig Cat = signature -instance Render Simple+instance Render SimpleExpression where renderSym Neg = "(-)" renderSym Pos = "id"@@ -278,15 +280,15 @@ renderSym Sub = "(-)" renderSym Cat = "(&)" -instance Eval Simple+instance Eval SimpleExpression where evalSym Neg = negate evalSym Pos = id evalSym Add = (+) evalSym Sub = (-)- evalSym Cat = \x y -> read (show x ++ show y)+ evalSym Cat = bitJoin -instance EvalEnv Simple env+instance EvalEnv SimpleExpression env instance Equality Term instance StringTree Term@@ -344,7 +346,8 @@ where symSig (Name _) = signature symSig (Literal _) = signature- symSig (Aggregate _) = undefined+ symSig (Aggregate _) = signature+ symSig (Others) = signature symSig (Function _ _) = signature symSig (Qualified _) = signature symSig (Conversion _) = signature@@ -355,6 +358,7 @@ renderSym (Name _) = "name" renderSym (Literal _) = "lit" renderSym (Aggregate _) = "agg"+ renderSym (Others) = "others" renderSym (Function _ _) = "fun" renderSym (Qualified _) = "qual" renderSym (Conversion _) = "conv"@@ -364,11 +368,12 @@ where evalSym (Name _) = error "cannot eval open names!" evalSym (Literal i) = i- evalSym (Aggregate xs) = xs+ evalSym (Aggregate _) = error "primary-todo: eval aggregate names."+ evalSym (Others) = error "primary-todo: eval others" evalSym (Function _ f) = f- evalSym (Qualified _) = error "todo: eval qualified names."+ evalSym (Qualified _) = error "primary-todo: eval qualified names." evalSym (Conversion f) = f- evalSym (Allocator) = undefined+ evalSym (Allocator) = error "primary-todo: eval allocator" instance EvalEnv Primary env
src/Language/Embedded/Hardware/Interface.hs view
@@ -1,38 +1,47 @@ {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeFamilies #-} -module Language.Embedded.Hardware.Interface where+module Language.Embedded.Hardware.Interface+ ( VHDL+ , module Language.Embedded.Hardware.Interface+ ) where import Language.VHDL (Expression) import Language.Embedded.VHDL (VHDL, Type) import Data.Constraint+import Data.String -------------------------------------------------------------------------------- -- * Interface for evaluation and compilation of pure expressions into VHDL. -------------------------------------------------------------------------------- --- | Constraint on the types of variables in a given expression language.-type family PredicateExp (exp :: * -> *) :: * -> Constraint+-- | Variable identifier.+type VarId = String --- | General interface for evaluating expressions.-class EvaluateExp exp+--------------------------------------------------------------------------------++-- | Expressions that support injection of values and named variables.+class FreeExp exp where+ -- | Constraint on the types of variables in a given expression language.+ type PredicateExp exp :: * -> Constraint+ -- | Literal expressions.- litE :: PredicateExp exp a => a -> exp a+ litE :: PredicateExp exp a => a -> exp a + -- | Variable expressions.+ varE :: PredicateExp exp a => VarId -> exp a++-- | General interface for evaluating expressions.+class FreeExp exp => EvaluateExp exp+ where -- | Evaluation of (closed) expressions.- evalE :: PredicateExp exp a => exp a -> a+ evalE :: exp a -> a -- | General interface for compiling expressions.-class CompileExp exp+class FreeExp exp => CompileExp exp where- -- | Variable expressions.- varE :: PredicateExp exp a => Integer -> exp a-- -- | Compilation of type kind.- compT :: PredicateExp exp a => exp a -> VHDL Type- -- | Compilation of expressions.- compE :: PredicateExp exp a => exp a -> VHDL Expression+ compE :: exp a -> VHDL Expression --------------------------------------------------------------------------------
src/Language/Embedded/VHDL.hs view
@@ -3,6 +3,7 @@ , module Language.Embedded.VHDL.Monad , module Language.Embedded.VHDL.Monad.Expression , module Language.Embedded.VHDL.Monad.Type+ , module Language.Embedded.VHDL.Monad.Util ) where import Language.VHDL as VHDL (Identifier(..), Mode(..), Direction(..)) @@ -10,3 +11,4 @@ import Language.Embedded.VHDL.Monad import Language.Embedded.VHDL.Monad.Expression import Language.Embedded.VHDL.Monad.Type+import Language.Embedded.VHDL.Monad.Util
src/Language/Embedded/VHDL/Monad.hs view
@@ -23,49 +23,61 @@ -- ^ imports , newLibrary, newImport - -- ^ declarations- , addPort, addGeneric- , addGlobal, addLocal+ -- ^ ...+--, addPort, addGeneric+ , addConstant, addSignal, addVariable , addConcurrent, addSequential , addType, addComponent + -- ^ ...+ , findType+ , inheritContext++ -- ^ declarations+ , declareComponent+ -- ^ statements , inProcess, inFor, inWhile, inConditional, inCase- , exit+ , exit, null -- ^ structures- , entity, architecture, package+ , entity, architecture, package, component -- ^ common things- , interfaceConstant, interfaceSignal, interfaceVariable- , declareConstant, declareSignal, declareVariable- , assignSignal, assignSignalS, assignVariable, assignArray-- , unconstrainedArray, constrainedArray+ , constant, signal, variable, array+ , assignSignal, assignVariable, assignArray+ , concurrentSignal, concurrentArray+ , portMap ) where import Language.VHDL +import Language.Embedded.VHDL.Monad.Util (maybePrimary)+ import Control.Applicative ((<$>)) import Control.Monad.Identity (Identity) import Control.Monad.State (StateT, MonadState, MonadIO) import qualified Control.Monad.Identity as CMI import qualified Control.Monad.State as CMS +import Data.Either (partitionEithers) import Data.Maybe (catMaybes) import Data.Foldable (toList) import Data.Functor (fmap)-import Data.List (groupBy)+import Data.List (groupBy, isPrefixOf, stripPrefix, find) import Data.Set (Set) import Data.Map (Map) import qualified Data.Set as Set import qualified Data.Map as Map import Text.PrettyPrint (Doc)+import qualified Text.PrettyPrint as Text import Prelude hiding (null, not, abs, exp, rem, mod, div, and, or) import qualified Prelude as P +import Debug.Trace+ -------------------------------------------------------------------------------- -- * VHDL monad and environment. --------------------------------------------------------------------------------@@ -73,14 +85,14 @@ -- | Code generation state data VHDLEnv = VHDLEnv { _unique :: !Integer- , _designs :: [DesignUnit]+ , _designs :: [DesignFile]+ , _units :: [DesignUnit] , _context :: Set ContextItem , _types :: Set TypeDeclaration- , _ports :: [InterfaceDeclaration]- , _generics :: [InterfaceDeclaration] , _components :: Set ComponentDeclaration- , _global :: [BlockDeclarativeItem]- , _local :: [BlockDeclarativeItem]+ , _constants :: [InterfaceDeclaration]+ , _signals :: [InterfaceDeclaration]+ , _variables :: [InterfaceDeclaration] , _concurrent :: [ConcurrentStatement] , _sequential :: [SequentialStatement] }@@ -89,13 +101,13 @@ emptyVHDLEnv = VHDLEnv { _unique = 0 , _designs = []+ , _units = [] , _context = Set.empty , _types = Set.empty , _components = Set.empty- , _ports = []- , _generics = []- , _global = []- , _local = []+ , _constants = []+ , _signals = []+ , _variables = [] , _concurrent = [] , _sequential = [] }@@ -145,8 +157,8 @@ return u -- | Generates a fresh and unique identifier.-newSym :: MonadV m => m Identifier-newSym = do i <- freshUnique; return (Ident $ 'v' : show i)+newSym :: MonadV m => String -> m String+newSym n = do i <- freshUnique; return (n ++ show i) -- | Generates a fresh and unique label. newLabel :: MonadV m => m Label@@ -169,14 +181,6 @@ item :: ContextItem item = ContextUse (UseClause [SelectedName (PName (NSimple (Ident i))) (SAll)]) --- | Adds a port declaration to the entity.-addPort :: MonadV m => InterfaceDeclaration -> m ()-addPort p = CMS.modify $ \s -> s { _ports = p : (_ports s) }---- | Adds a generic declaration to the entity.-addGeneric :: MonadV m => InterfaceDeclaration -> m ()-addGeneric g = CMS.modify $ \s -> s { _generics = g : (_generics s) }- -- | Adds a type declaration. addType :: MonadV m => TypeDeclaration -> m () addType t = CMS.modify $ \s -> s { _types = Set.insert t (_types s) }@@ -185,13 +189,18 @@ addComponent :: MonadV m => ComponentDeclaration -> m () addComponent c = CMS.modify $ \s -> s { _components = Set.insert c (_components s) } +-- | ...+addConstant :: MonadV m => InterfaceDeclaration -> m ()+addConstant c = CMS.modify $ \s -> s { _constants = c : (_constants s) }+ -- | Adds a global declaration.-addGlobal :: MonadV m => BlockDeclarativeItem -> m ()-addGlobal g = CMS.modify $ \s -> s { _global = g : (_global s) }+addSignal :: MonadV m => InterfaceDeclaration -> m ()+addSignal v = CMS.modify $ \s -> s { _signals = v : (_signals s) } -- | Adds a local declaration.-addLocal :: MonadV m => BlockDeclarativeItem -> m ()-addLocal l = CMS.modify $ \s -> s { _local = l : (_local s) }+--addVariable :: MonadV m => BlockDeclarativeItem -> m ()+addVariable :: MonadV m => InterfaceDeclaration -> m ()+addVariable v = CMS.modify $ \s -> s { _variables = v : (_variables s) } -- | Adds a concurrent statement. addConcurrent :: MonadV m => ConcurrentStatement -> m ()@@ -202,31 +211,164 @@ addSequential seq = CMS.modify $ \s -> s { _sequential = seq : (_sequential s) } --------------------------------------------------------------------------------+-- ** ...+--+-- having units be indexed by their names would help.++inheritContext :: MonadV m => Identifier -> m ()+inheritContext e =+ do u <- findEntity e+ case u of+ Nothing -> return ()+ Just entity -> inherit $ getContext entity+ where+ inherit :: MonadV m => ContextClause -> m ()+ inherit (ContextClause cs) = go cs+ where+ go :: MonadV m => [ContextItem] -> m ()+ go [] = return ()+ go (l@(ContextLibrary _):cs) = go cs+ go (c@(ContextUse _) :cs) = add c >> go cs++ add :: MonadV m => ContextItem -> m ()+ add c = CMS.modify $ \s -> s { _context = Set.insert c (_context s) }++extendContext :: MonadV m => Identifier -> m ()+extendContext e =+ do u <- findEntity e+ case u of+ Nothing -> return ()+ Just entity ->+ do n <- extendUnit entity+ updateUnit n+ where+ updateUnit :: MonadV m => DesignUnit -> m ()+ updateUnit u =+ do units <- CMS.gets _units+ let new = update u units+ CMS.modify $ \s -> s { _units = new }++ update :: DesignUnit -> [DesignUnit] -> [DesignUnit]+ update u [] = []+ update u (x:xs)+ | Just a <- name u+ , Just b <- name x+ , a == b = u : xs+ | otherwise = x : update u xs+ where+ name :: DesignUnit -> Maybe Identifier+ name (DesignUnit _ (LibraryPrimary (PrimaryEntity (EntityDeclaration i _ _ _)))) = Just i+ name _ = Nothing+ + extendUnit :: MonadV m => DesignUnit -> m (DesignUnit)+ extendUnit (DesignUnit (ContextClause cs) lib) =+ do ctxt <- CMS.gets _context+ let new = foldr extend cs ctxt+ return (DesignUnit (ContextClause new) lib)++ extend :: ContextItem -> [ContextItem] -> [ContextItem]+ extend c cs = if (elem c cs) then (cs) else (cs ++ [c])++--------------------------------------------------------------------------------+-- ** ...++findType :: MonadV m => TypeDeclaration -> m (Maybe Identifier)+findType t =+ do set <- CMS.gets $ \s -> Set.filter (\t' -> compare t t' == EQ) (_types s)+ return $ case Set.null set of+ False -> Just $ typeName $ Set.findMin set+ True -> Nothing++findEntity :: MonadV m => Identifier -> m (Maybe DesignUnit)+findEntity e =+ do curr <- CMS.gets _units+ prev <- CMS.gets _designs+ return $ safeHead $ filter select $ curr ++ concatMap getUnits prev+ where+ select :: DesignUnit -> Bool+ select (DesignUnit _ (LibraryPrimary (PrimaryEntity (EntityDeclaration i _ _ _)))) | e == i = True+ select _ = False++ safeHead :: [a] -> Maybe a+ safeHead [] = Nothing+ safeHead (x:_) = Just x+ +--------------------------------------------------------------------------------++getUnits :: DesignFile -> [DesignUnit]+getUnits (DesignFile units) = units++getContext :: DesignUnit -> ContextClause+getContext (DesignUnit ctxt _) = ctxt++typeName :: TypeDeclaration -> Identifier+typeName (TDFull (FullTypeDeclaration i _)) = i+typeName (TDPartial (IncompleteTypeDeclaration i)) = i++packageName :: DesignUnit -> Maybe Identifier+packageName (DesignUnit _ (LibraryPrimary (PrimaryPackage (PackageDeclaration i _)))) = Just i+packageName _ = Nothing++-------------------------------------------------------------------------------- -- * Concurrent and sequential statements -------------------------------------------------------------------------------- +-- | Extract block declaration from interface declaration.+translateInterface :: InterfaceDeclaration -> BlockDeclarativeItem+translateInterface (InterfaceConstantDeclaration is t e) =+ BDIConstant (ConstantDeclaration is t e)+translateInterface (InterfaceSignalDeclaration is m t b e) =+ BDISignal (SignalDeclaration is t (Just (if b then Bus else Register)) e)+translateInterface (InterfaceVariableDeclaration is m t e) =+ BDIShared (VariableDeclaration False is t e)+translateInterface (InterfaceFileDeclaration is t) =+ BDIFile (FileDeclaration is t Nothing)++-- | ...+translateSequential :: SequentialStatement -> ConcurrentStatement+translateSequential (SSignalAss (SignalAssignmentStatement _ name _ e)) =+ ConSignalAss (CSASCond Nothing False (ConditionalSignalAssignment name (Options False Nothing) (ConditionalWaveforms [] (e, Nothing))))++-- | ...+translateConcurrent :: ConcurrentStatement -> SequentialStatement+translateConcurrent (ConSignalAss (CSASCond _ _ (ConditionalSignalAssignment name _ (ConditionalWaveforms _ (e, _))))) =+ SSignalAss (SignalAssignmentStatement Nothing name Nothing e)++-- | Run monadic actions in a contained environment.+contain :: MonadV m => m () -> m [SequentialStatement]+contain m =+ do m -- do+ new <- reverse <$> CMS.gets _sequential -- get+ CMS.modify $ \e -> e { _sequential = [] } -- reset+ return new -- return++-- | Exit loop.+exit :: MonadV m => Label -> Expression -> m ()+exit label e = addSequential $ SExit $ ExitStatement (Nothing) (Just label) (Just e)++--------------------------------------------------------------------------------+ -- | Runs the given action inside a process. inProcess :: MonadV m => Label -> [Identifier] -> m a -> m (a, ProcessStatement) inProcess l is m =- do oldLocals <- CMS.gets _local+ do oldLocals <- CMS.gets _variables oldSequential <- CMS.gets _sequential- CMS.modify $ \e -> e { _local = []+ CMS.modify $ \e -> e { _variables = [] , _sequential = [] } result <- m- newLocals <- reverse <$> CMS.gets _local+ newLocals <- reverse <$> CMS.gets _variables newSequential <- reverse <$> CMS.gets _sequential- CMS.modify $ \e -> e { _local = oldLocals+ CMS.modify $ \e -> e { _variables = oldLocals , _sequential = oldSequential } return ( result- , ProcessStatement- (Just l) -- label- (False) -- postponed- (sensitivity) -- sensitivitylist- (translate $ merge $ newLocals) -- declarativepart- (newSequential)) -- statementpart+ , ProcessStatement (Just l) (False)+ (sensitivity is)+ (fmap (translate . translateInterface) $ merge $ newLocals)+ (newSequential)) where- sensitivity | P.null is = Nothing- | otherwise = Just $ SensitivityList $ fmap NSimple is+ sensitivity :: [Identifier] -> Maybe SensitivityList+ sensitivity [] = Nothing+ sensitivity xs = Just $ SensitivityList $ fmap NSimple xs -- | Run program in for loop. inFor :: MonadV m => Identifier -> Range -> m () -> m (LoopStatement)@@ -261,10 +403,6 @@ iter :: Maybe Expression -> Maybe IterationScheme iter = maybe (Nothing) (Just . IterWhile) --- | Exit loop.-exit :: MonadV m => Label -> Expression -> m ()-exit label e = addSequential $ SExit $ ExitStatement (Nothing) (Just label) (Just e)- -- | Conditional statements. inConditional :: MonadV m => (Condition, m ()) -> [(Condition, m ())] -> m () -> m (IfStatement) inConditional (c, m) os e =@@ -276,55 +414,55 @@ e' <- contain e CMS.modify $ \e -> e { _sequential = oldSequential } return $- IfStatement- (Nothing)+ IfStatement Nothing (c, m') (zip cs ns') (maybeList e') where maybeList :: [SequentialStatement] -> Maybe [SequentialStatement]- maybeList xs- | P.null xs = Nothing- | otherwise = Just xs+ maybeList [] = Nothing+ maybeList xs = Just xs -- | Case statements.-inCase :: MonadV m => Expression -> [(Choices, m ())] -> m (CaseStatement)-inCase e choices =+inCase :: MonadV m => Expression -> [(Choices, m ())] -> m () -> m (CaseStatement)+inCase e choices d = do let (cs, ns) = unzip choices oldSequential <- CMS.gets _sequential CMS.modify $ \e -> e { _sequential = [] } ns' <- mapM contain ns- CMS.modify $ \e -> e { _sequential = oldSequential } + d' <- contain d+ CMS.modify $ \e -> e { _sequential = oldSequential }+ let xs = zipWith CaseStatementAlternative cs ns' return $- CaseStatement- (Nothing)- (e)- (zipWith CaseStatementAlternative cs ns')--contain :: MonadV m => m () -> m [SequentialStatement]-contain m = do- m -- do- new <- reverse <$> CMS.gets _sequential -- get- CMS.modify $ \e -> e { _sequential = [] } -- reset- return new -- return+ CaseStatement Nothing e+ (xs ++ maybeList d')+ where+ maybeList :: [SequentialStatement] -> [CaseStatementAlternative]+ maybeList [] = []+ maybeList xs = [CaseStatementAlternative (Choices [ChoiceOthers]) xs]+ -------------------------------------------------------------------------------- -- * Design units -------------------------------------------------------------------------------- --- ... design unit with context-addDesign :: MonadV m => LibraryUnit -> m ()-addDesign lib =+-- | Design file.+addDesign :: MonadV m => DesignFile -> m ()+addDesign d = CMS.modify $ \s -> s { _designs = d : (_designs s) }++-- | Design unit with context.+addUnit :: MonadV m => LibraryUnit -> m ()+addUnit lib = do ctxt <- CMS.gets _context- dsig <- CMS.gets _designs+ dsig <- CMS.gets _units let item = DesignUnit (ContextClause (Set.toList ctxt)) lib- CMS.modify $ \s -> s { _designs = item : dsig+ CMS.modify $ \s -> s { _units = item : dsig , _context = Set.empty } --- .. design unit ignoring context-addDesign_ :: MonadV m => LibraryUnit -> m ()-addDesign_ lib = CMS.modify $ \s -> s { _designs = (DesignUnit (ContextClause []) lib) : (_designs s)}+-- | Design unit ignoring context.+addUnit_ :: MonadV m => LibraryUnit -> m ()+addUnit_ lib = CMS.modify $ \s -> s { _units = (DesignUnit (ContextClause []) lib) : (_units s)} -------------------------------------------------------------------------------- -- ** Architectures@@ -333,23 +471,47 @@ -- identifiers and concurrent statements it produces. Strings are its entity -- and architecture names, respectively. architecture :: MonadV m => Identifier -> Identifier -> m a -> m a-architecture entity name m =- do oldGlobal <- CMS.gets _global+architecture entity@(Ident n) name@(Ident e) m =+ do oldConstants <- CMS.gets _constants+ oldGlobal <- CMS.gets _signals oldConcurrent <- CMS.gets _concurrent- CMS.modify $ \e -> e { _global = []- , _concurrent = [] }+ oldSequential <- CMS.gets _sequential+ oldTypes <- CMS.gets _types+ oldComponents <- CMS.gets _components+ CMS.modify $ \e -> e { _constants = []+ , _signals = []+ , _concurrent = []+ , _sequential = []+ , _types = Set.empty+ , _components = Set.empty } result <- m- newGlobal <- reverse <$> CMS.gets _global+ newConstants <- reverse <$> CMS.gets _constants+ newGlobal <- reverse <$> CMS.gets _signals newConcurrent <- reverse <$> CMS.gets _concurrent- addDesign_ $ LibrarySecondary $ SecondaryArchitecture $- ArchitectureBody- (name)+ newSequential <- reverse . filter isSignal <$> CMS.gets _sequential+ newTypes <- fmap BDIType . Set.toList <$> CMS.gets _types+ newComponents <- fmap BDIComp . Set.toList <$> CMS.gets _components+ let signals = fmap translateSequential newSequential+ addUnit_ $ LibrarySecondary $ SecondaryArchitecture $+ ArchitectureBody (name) (NSimple entity)- (merge newGlobal)- (newConcurrent)- CMS.modify $ \e -> e { _global = oldGlobal- , _concurrent = oldConcurrent }+ (newTypes -- merge+ ++ newComponents+ ++ fmap translateInterface newGlobal+ ++ fmap translateInterface newConstants)+ (signals ++ newConcurrent)+ CMS.modify $ \e -> e { _constants = oldConstants+ , _signals = oldGlobal+ , _concurrent = oldConcurrent+ , _sequential = oldSequential+ , _types = oldTypes+ , _components = oldComponents }+ extendContext entity return result+ where+ isSignal :: SequentialStatement -> Bool+ isSignal (SSignalAss _) = True+ isSignal _ = False -------------------------------------------------------------------------------- -- ** Entities@@ -357,30 +519,43 @@ -- | Declares an entity with the given name by consuming all port-level -- declaraions and context items produced by running the monadic action. entity :: MonadV m => Identifier -> m a -> m a-entity name m =- do oldPorts <- CMS.gets _ports- oldGenerics <- CMS.gets _generics- CMS.modify $ \e -> e { _ports = []- , _generics = [] }+entity name@(Ident n) m =+ do oldTypes <- CMS.gets _types+ oldPorts <- CMS.gets _signals+ oldGenerics <- CMS.gets _variables+ CMS.modify $ \e -> e { _types = Set.empty+ , _signals = []+ , _variables = [] } result <- m- newPorts <- reverse <$> CMS.gets _ports- newGenerics <- reverse <$> CMS.gets _generics- addDesign $ LibraryPrimary $ PrimaryEntity $- EntityDeclaration- (name)+ types <- CMS.gets _types+ newPorts <- reverse <$> CMS.gets _signals+ newGenerics <- reverse <$> CMS.gets _variables+ CMS.when (P.not $ Set.null types) $+ do let packageName = n ++ "_types"+ ctxt <- CMS.gets _context+ addUnit $ packageTypes packageName types+ CMS.modify $ \s -> s { _context = ctxt }+ newImport $ "WORK." ++ packageName+ addUnit $ LibraryPrimary $ PrimaryEntity $+ EntityDeclaration name (EntityHeader (GenericClause <$> maybeNull newGenerics) (PortClause <$> maybeNull newPorts)) ([]) (Nothing)- CMS.modify $ \e -> e { _ports = oldPorts- , _generics = oldGenerics }+ CMS.modify $ \e -> e { _types = oldTypes+ , _signals = oldPorts+ , _variables = oldGenerics } return result- where- maybeNull :: [InterfaceDeclaration] -> Maybe InterfaceList- maybeNull [] = Nothing- maybeNull xs = Just $ InterfaceList $ merge xs +maybeNull :: [InterfaceDeclaration] -> Maybe InterfaceList+maybeNull [] = Nothing+maybeNull xs = Just $ InterfaceList $ xs --merge ...++packageTypes :: String -> Set TypeDeclaration -> LibraryUnit+packageTypes name types = LibraryPrimary $ PrimaryPackage $ PackageDeclaration+ (Ident name) (fmap PHDIType (reverse $ Set.toList types))+ -------------------------------------------------------------------------------- -- ** Packages @@ -392,14 +567,26 @@ CMS.modify $ \e -> e { _types = Set.empty } result <- m newTypes <- CMS.gets _types- addDesign $ LibraryPrimary $ PrimaryPackage $- PackageDeclaration- (Ident name)- (fmap PHDIType $ Set.toList newTypes)+ addUnit $ packageTypes name newTypes CMS.modify $ \e -> e { _types = oldTypes } return result --------------------------------------------------------------------------------+-- ** Component.++-- | Declares an entire component, with entity declaration and a body.+component :: MonadV m => m () -> m ()+component m =+ do oldEnv <- CMS.get+ oldFiles <- CMS.gets _designs+ CMS.put (emptyVHDLEnv { _designs = oldFiles })+ m+ newUnits <- CMS.gets _units+ newFiles <- CMS.gets _designs+ CMS.put (oldEnv { _designs = newFiles })+ addDesign $ DesignFile newUnits++-------------------------------------------------------------------------------- -- * Pretty printing VHDL programs -------------------------------------------------------------------------------- @@ -414,30 +601,36 @@ -------------------------------------------------------------------------------- -- | Pretty print a VHDL environment.------ *** Shouldn't use revers to fix ordering issues! Pair architectures/bodies--- with their respective entities. prettyVEnv :: VHDLEnv -> Doc-prettyVEnv env = pp (DesignFile $ types ++ archi)+prettyVEnv env = Text.vcat (pp main : fmap pp files) where- archi = reverse $ _designs env- types = reverse $ designTypes (_types env)+ main = DesignFile units+ units = reverse $ _units env+ files = reverse $ map reorderDesign $ _designs env --- *** Scan type declarations for necessary imports instead.--- *** Types are added in an ugly manner.-designTypes :: Set TypeDeclaration -> [DesignUnit]-designTypes set- | Set.null set = []- | otherwise = _designs . snd $ runVHDL pack emptyVHDLEnv+--------------------------------------------------------------------------------++reorderDesign :: DesignFile -> DesignFile+reorderDesign (DesignFile units) = DesignFile (reverse units)++reorderUnit :: DesignUnit -> DesignUnit+reorderUnit (DesignUnit ctxt lib) = DesignUnit+ (reorderContext ctxt)+ (reorderLibrary lib)++-- todo : reverse at the level of design file instead.+reorderLibrary :: LibraryUnit -> LibraryUnit+reorderLibrary (LibraryPrimary prim) = LibraryPrimary prim+reorderLibrary (LibrarySecondary second) = LibrarySecondary second++-- todo : reverse instead?+reorderContext :: ContextClause -> ContextClause+reorderContext (ContextClause items) = ContextClause (reorder items []) where- pack :: MonadV m => m ()- pack = package "types" $ do- -- *** Instead of importing every library possible the correct ones- -- should be declared when adding a type through 'addType'.- newLibrary "IEEE"- newImport "IEEE.STD_LOGIC_1164"- newImport "IEEE.NUMERIC_STD"- CMS.modify $ \e -> e { _types = set }+ reorder :: [ContextItem] -> [ContextItem] -> [ContextItem]+ reorder [] rs = rs+ reorder (lib@(ContextLibrary _) : cs) rs = lib : (rs ++ cs)+ reorder (use@(ContextUse _) : cs) rs = reorder (use : rs) cs -------------------------------------------------------------------------------- -- * Common things@@ -446,77 +639,70 @@ -------------------------------------------------------------------------------- -- ** Ports/Generic declarations -interfaceConstant :: Identifier -> SubtypeIndication -> Maybe Expression -> InterfaceDeclaration-interfaceConstant i t e = InterfaceConstantDeclaration [i] t e+constant :: MonadV m => Identifier -> SubtypeIndication -> Expression -> m ()+constant i t e = addConstant $ InterfaceConstantDeclaration [i] t (Just e) -interfaceSignal :: Identifier -> Mode -> SubtypeIndication -> Maybe Expression -> InterfaceDeclaration-interfaceSignal i m t e = InterfaceSignalDeclaration [i] (Just m) t False e+signal :: MonadV m => Identifier -> Mode -> SubtypeIndication -> Maybe Expression -> m ()+signal i m t e = addSignal $ InterfaceSignalDeclaration [i] (Just m) t False e -interfaceVariable :: Identifier -> Mode -> SubtypeIndication -> Maybe Expression -> InterfaceDeclaration-interfaceVariable i m t e = InterfaceVariableDeclaration [i] (Just m) t e+variable :: MonadV m => Identifier -> SubtypeIndication -> Maybe Expression -> m ()+variable i t e = addVariable $ InterfaceVariableDeclaration [i] Nothing t e +array :: MonadV m => Identifier -> Mode -> SubtypeIndication -> Maybe Expression -> m ()+array = signal+ ----------------------------------------------------------------------------------- ** Array Declarations.+-- ** Assign Signal/Variable. -compositeTypeDeclaration :: Identifier -> CompositeTypeDefinition -> TypeDeclaration-compositeTypeDeclaration name t = TDFull (FullTypeDeclaration name (TDComposite t))+assignSignal :: MonadV m => Name -> Expression -> m ()+assignSignal n e = addSequential $ SSignalAss $ + SignalAssignmentStatement+ (Nothing)+ (TargetName n)+ (Nothing)+ (WaveElem [WaveEExp e Nothing]) -unconstrainedArray :: Identifier -> SubtypeIndication -> TypeDeclaration-unconstrainedArray name typ = compositeTypeDeclaration name $- CTDArray (ArrU (UnconstrainedArrayDefinition [] typ))+assignVariable :: MonadV m => Name -> Expression -> m ()+assignVariable n e = addSequential $ SVarAss $+ VariableAssignmentStatement+ (Nothing)+ (TargetName n)+ (e) -constrainedArray :: Identifier -> SubtypeIndication -> Range -> TypeDeclaration-constrainedArray name typ range = compositeTypeDeclaration name $- CTDArray (ArrC (ConstrainedArrayDefinition- (IndexConstraint [DRRange range]) typ))+assignArray :: MonadV m => Name -> Expression -> m ()+assignArray = assignSignal ----------------------------------------------------------------------------------- ** Global/Local Declarations. -declareConstant :: Identifier -> SubtypeIndication -> Maybe Expression -> BlockDeclarativeItem-declareConstant i t e = BDIConstant $ ConstantDeclaration [i] t e--declareSignal :: Identifier -> SubtypeIndication -> Maybe Expression -> BlockDeclarativeItem-declareSignal i t e = BDISignal $ SignalDeclaration [i] t Nothing e+concurrentSignal :: MonadV m => Name -> Expression -> m ()+concurrentSignal n e = addConcurrent $ ConSignalAss $+ CSASCond Nothing False $+ ConditionalSignalAssignment (TargetName n) (Options False Nothing) $+ ConditionalWaveforms [] (WaveElem [WaveEExp e Nothing], Nothing) -declareVariable :: Identifier -> SubtypeIndication -> Maybe Expression -> BlockDeclarativeItem-declareVariable i t e = BDIShared $ VariableDeclaration False [i] t e+concurrentArray :: MonadV m => Name -> Expression -> m ()+concurrentArray = concurrentSignal ----------------------------------------------------------------------------------- ** Assign Signal/Variable.+-- Portmap. -assignSignal :: Identifier -> Expression -> ConcurrentStatement-assignSignal i e = ConSignalAss $ CSASCond Nothing False $ - ConditionalSignalAssignment- (TargetName (NSimple i))- (Options False Nothing)- (ConditionalWaveforms- ([])- ( WaveElem [WaveEExp e Nothing]- , Nothing))+portMap :: MonadV m => Label -> Identifier -> [(Identifier, Identifier)] -> m ()+portMap l c is = addConcurrent $ ConComponent $ ComponentInstantiationStatement l+ (IUComponent $ NSimple c)+ (Nothing)+ (Just $ PortMapAspect $ AssociationList $ flip fmap is $ \(i, j) ->+ AssociationElement (Just $ FPDesignator $ FDPort $ NSimple i) $ APDesignator $ ADSignal $ NSimple j) -assignSignalS :: Identifier -> Expression -> SequentialStatement-assignSignalS i e = SSignalAss $- SignalAssignmentStatement- (Nothing)- (TargetName (NSimple i))- (Nothing)- (WaveElem [WaveEExp e Nothing])+declareComponent :: MonadV m => Identifier -> [InterfaceDeclaration] -> m ()+declareComponent name is = addComponent $ ComponentDeclaration name Nothing+ (Just (PortClause (InterfaceList is)))+ (Nothing) -assignVariable :: Identifier -> Expression -> SequentialStatement-assignVariable i e = SVarAss $- VariableAssignmentStatement- (Nothing)- (TargetName (NSimple i))- (e)+--------------------------------------------------------------------------------+-- .... -assignArray :: Name -> Expression -> SequentialStatement-assignArray i e = SSignalAss $- SignalAssignmentStatement- (Nothing)- (TargetName i)- (Nothing)- (WaveElem [WaveEExp e Nothing])+null :: MonadV m => m ()+null = addSequential $ SNull $ NullStatement Nothing -------------------------------------------------------------------------------- -- Some helper classes and their instances@@ -549,6 +735,23 @@ -------------------------------------------------------------------------------- +class Declarative a+ where+ translate :: BlockDeclarativeItem -> a++instance Declarative ProcessDeclarativeItem+ where+ translate = processBlock++-- | Try to transform the declarative item into a process item+processBlock :: BlockDeclarativeItem -> ProcessDeclarativeItem+processBlock (BDIConstant c) = PDIConstant c+processBlock (BDIShared v) = PDIVariable v+processBlock (BDIFile f) = PDIFile f+processBlock b = error $ "Unknown block item: " ++ show b++--------------------------------------------------------------------------------+ setBlockIds :: BlockDeclarativeItem -> [Identifier] -> BlockDeclarativeItem setBlockIds (BDIConstant c) is = BDIConstant $ c { const_identifier_list = is } setBlockIds (BDISignal s) is = BDISignal $ s { signal_identifier_list = is }@@ -562,27 +765,11 @@ getBlockIds (BDIShared v) = var_identifier_list v getBlockIds (BDIFile f) = fd_identifier_list f -class Declarative a- where- -- lists are used so we can fail without having to throw errors- translate :: [BlockDeclarativeItem] -> [a]--instance Declarative ProcessDeclarativeItem- where- translate = catMaybes . fmap tryProcess---- | Try to transform the declarative item into a process item-tryProcess :: BlockDeclarativeItem -> Maybe (ProcessDeclarativeItem)-tryProcess (BDIConstant c) = Just $ PDIConstant c-tryProcess (BDIShared v) = Just $ PDIVariable v-tryProcess (BDIFile f) = Just $ PDIFile f-tryProcess _ = Nothing- -------------------------------------------------------------------------------- -- Ord instance for use in sets -------------------------------------------------------------------------------- ----- *** These break the Ord rules but seems to be needed for Set.+-- todo: don't rely on these too much. deriving instance Ord ContextItem deriving instance Ord LibraryClause@@ -591,24 +778,48 @@ instance Ord TypeDeclaration where- compare (TDFull l) (TDFull r) = compare (ftd_identifier l) (ftd_identifier r)- compare (TDPartial l) (TDPartial r) = compare l r- compare (TDFull l) _ = GT- compare (TDPartial l) _ = LT+ compare (TDFull (FullTypeDeclaration a (TDComposite b)))+ (TDFull (FullTypeDeclaration x (TDComposite y)))+ = compare b y+ compare _ _ = error "Ord not supported for incomplete type declarations." +instance Ord CompositeTypeDefinition+ where+ compare (CTDArray a) (CTDArray x) = compare a x+ compare _ _ = error "Ord not supported for record type definitions."++instance Ord ArrayTypeDefinition+ where+ compare (ArrU (UnconstrainedArrayDefinition a b))+ (ArrU (UnconstrainedArrayDefinition x y)) =+ case compare b y of+ GT -> GT+ LT -> LT+ EQ -> compare a x+ compare (ArrC (ConstrainedArrayDefinition a b))+ (ArrC (ConstrainedArrayDefinition x y)) =+ case compare b y of+ GT -> GT+ LT -> LT+ EQ -> compare a x++deriving instance Ord IndexSubtypeDefinition++deriving instance Ord IndexConstraint+ deriving instance Ord IncompleteTypeDeclaration instance Ord ComponentDeclaration where- compare l r = compare (comp_identifier l) (comp_identifier r)+ compare a x = compare (comp_identifier a) (comp_identifier x) deriving instance Ord SubtypeIndication deriving instance Ord TypeMark instance Ord Constraint where- compare (CRange a) (CRange b) = compare a b- compare _ _ = error "Ord not supported for index constraints"+ compare (CRange a) (CRange x) = compare a x+ compare _ _ = error "Ord not supported for index constraints." deriving instance Ord RangeConstraint @@ -637,8 +848,39 @@ instance Ord Primary where- compare (PrimName a) (PrimName x) = compare a x+ compare (PrimName a) (PrimName x) = compare a x+ compare (PrimLit a) (PrimLit x) = compare a x+ compare (PrimAgg a) (PrimAgg x) = compare a x+ compare (PrimFun a) (PrimFun x) = compare a x+ compare (PrimQual a) (PrimQual x) = compare a x+ compare (PrimTCon a) (PrimTCon x) = compare a x+ compare (PrimAlloc a) (PrimAlloc x) = compare a x+ compare (PrimExp a) (PrimExp x) = compare a x + compare (PrimExp a) x | Just p <- maybePrimary a = compare p x+ compare a (PrimExp x) | Just p <- maybePrimary x = compare a p+ + compare a x = error ("\na: " ++ show a ++ "\nx: " ++ show x)++deriving instance Ord Aggregate+deriving instance Ord ElementAssociation+deriving instance Ord Choices+deriving instance Ord Choice++deriving instance Ord FunctionCall+deriving instance Ord AssociationList+deriving instance Ord AssociationElement+deriving instance Ord FormalPart+deriving instance Ord FormalDesignator+deriving instance Ord ActualPart+deriving instance Ord ActualDesignator++deriving instance Ord QualifiedExpression++deriving instance Ord TypeConversion++deriving instance Ord Allocator+ deriving instance Ord LogicalOperator deriving instance Ord RelationalOperator deriving instance Ord ShiftOperator@@ -678,5 +920,16 @@ deriving instance Ord AttributeName deriving instance Ord Signature++deriving instance Ord Literal+deriving instance Ord NumericLiteral+deriving instance Ord AbstractLiteral+deriving instance Ord PhysicalLiteral+deriving instance Ord DecimalLiteral+deriving instance Ord EnumerationLiteral+deriving instance Ord BitStringLiteral++deriving instance Ord Exponent+deriving instance Ord BasedLiteral --------------------------------------------------------------------------------
src/Language/Embedded/VHDL/Monad/Expression.hs view
@@ -5,19 +5,22 @@ , add, sub, cat, neg , mul, div, mod, rem , exp, abs, not- , name, string, indexed, selected, slice- , lit, null- , aggregate, associate+ , name, simple, indexed, selected, slice, attribute+ , literal, number, string+ , aggregate, aggregated, associated, others , function , qualified , cast- , resize+ -- utility.+ , resize, asBits, asSigned, asUnsigned, toSigned, toUnsigned, toInteger , range, downto, to+ , point, upper, lower, zero+ , choices, is, between ) where import Language.VHDL -import Prelude hiding (and, or, div, mod, rem, exp, abs, not, null)+import Prelude hiding (and, or, div, mod, rem, exp, abs, not, null, toInteger) -------------------------------------------------------------------------------- -- * Expressions and their sub-layers.@@ -101,67 +104,139 @@ not = FacNot ----------------------------------------------------------------------------------- ** Primaries+-- ** Primaries. --- names-name :: String -> Primary-name = PrimName . NSimple . Ident+--------------------------------------------------------------------------------+-- *** Names. -string :: String -> Primary-string = PrimLit . LitString . SLit+name :: Name -> Primary+name = PrimName -indexed :: Identifier -> Expression -> Name-indexed i l = NIndex $ IndexedName (PName $ NSimple i) [l]+simple :: String -> Name+simple = NSimple . Ident -selected :: Identifier -> Identifier -> Primary-selected p s = PrimName $ NSelect $ SelectedName (PName $ NSimple p) (SSimple s)+selected :: Name -> Identifier -> Name+selected i s = NSelect $ SelectedName (PName i) (SSimple s) -slice :: Identifier -> (SimpleExpression, SimpleExpression) -> Primary-slice i (f, t) = PrimName $ NSlice $ SliceName (PName $ NSimple i) (DRRange $ RSimple f DownTo t)+indexed :: Name -> Expression -> Name+indexed i l = NIndex $ IndexedName (PName i) [l] --- literals-lit :: Show i => i -> Primary-lit = PrimLit . LitNum . NLitPhysical . PhysicalLiteral Nothing . NSimple . Ident . show+slice :: Name -> Range -> Name+slice i r = NSlice $ SliceName (PName i) (DRRange r) -null :: Primary-null = PrimLit LitNull+attribute :: String -> Name -> Primary+attribute s n = PrimName $ NAttr $ AttributeName (PName n) Nothing (Ident s) Nothing --- aggregates-aggregate :: [Expression] -> Primary-aggregate = PrimAgg . Aggregate . fmap (ElementAssociation Nothing)+--------------------------------------------------------------------------------+-- *** Literals. -associate :: [(Maybe Choices, Expression)] -> Primary-associate es = PrimAgg $ Aggregate $ map (uncurry ElementAssociation) es+literal :: Literal -> Primary+literal = PrimLit --- function calls-function :: Identifier -> [Expression] -> Primary-function i [] = PrimFun $ FunctionCall (NSimple i) Nothing+number :: String -> Literal+number = LitNum . NLitPhysical . PhysicalLiteral Nothing . NSimple . Ident++string :: String -> Literal+string = LitString . SLit++--------------------------------------------------------------------------------+-- *** Aggregates.++aggregate :: Aggregate -> Primary+aggregate = PrimAgg++aggregated :: [Expression] -> Aggregate+aggregated = Aggregate . fmap (ElementAssociation Nothing)++associated :: [(Maybe Choices, Expression)] -> Aggregate+associated es = Aggregate $ map (uncurry ElementAssociation) es++others :: Expression -> Aggregate+others = Aggregate . (:[]) . ElementAssociation (Just (Choices [ChoiceOthers]))++--------------------------------------------------------------------------------+-- *** Functions.++function :: Name -> [Expression] -> Primary+function i [] = PrimFun $ FunctionCall i Nothing function i xs = PrimFun- . FunctionCall (NSimple i) . Just . AssociationList+ . FunctionCall i . Just . AssociationList $ fmap (AssociationElement Nothing . APDesignator . ADExpression) xs --- qualified expressions+--------------------------------------------------------------------------------+-- *** Qualified.+ qualified :: SubtypeIndication -> Expression -> Primary qualified (SubtypeIndication _ t _) = PrimQual . QualExp t --- type conversions+--------------------------------------------------------------------------------+-- *** Type conversion.+ cast :: SubtypeIndication -> Expression -> Primary-cast (SubtypeIndication _ t _) = PrimTCon . TypeConversion t+cast (SubtypeIndication _ t _) = PrimTCon . TypeConversion (unrange t)+ where+ unrange :: TypeMark -> TypeMark+ unrange (TMType (NSlice (SliceName (PName (NSimple (Ident typ))) _))) = TMType (NSimple (Ident typ))+ unrange (TMType (NSimple (Ident typ))) = TMType (NSimple (Ident typ)) ----------------------------------------------------------------------------------- ** Utility+-- ... resize :: Expression -> Expression -> Primary-resize size exp = PrimFun $ FunctionCall name $ Just $ AssociationList [assoc size, assoc exp]- where- name = NSimple $ Ident "resize"- assoc = AssociationElement Nothing . APDesignator . ADExpression+resize exp size = function (simple "resize") [exp, size] +asBits :: Expression -> Primary+asBits exp = function (simple "std_logic_vector") [exp]++asSigned :: Expression -> Primary+asSigned exp = function (simple "signed") [exp]++asUnsigned :: Expression -> Primary+asUnsigned exp = function (simple "unsigned") [exp]++toSigned :: Expression -> Expression -> Primary+toSigned exp size = function (simple "to_signed") [exp, size]++toUnsigned :: Expression -> Expression -> Primary+toUnsigned exp size = function (simple "to_unsigned") [exp, size]++toInteger :: Expression -> Primary+toInteger exp = function (simple "to_integer") [exp]++--------------------------------------------------------------------------------+-- ...+ range :: SimpleExpression -> Direction -> SimpleExpression -> Range-range = RSimple+range = RSimple downto, to :: Direction downto = DownTo to = To++--------------------------------------------------------------------------------+-- ...++point :: Show i => i -> SimpleExpression+point i = SimpleExpression Nothing (Term (FacPrim (literal (number (show i))) (Nothing)) []) []++upper, lower :: Integer -> SimpleExpression+upper 0 = point 0+upper n = point (n-1)+lower n = point n++zero :: SimpleExpression+zero = point 0++--------------------------------------------------------------------------------+-- ...++choices :: [Choice] -> Choices+choices = Choices++is :: SimpleExpression -> Choice+is = ChoiceSimple++between :: Range -> Choice+between = ChoiceRange . DRRange --------------------------------------------------------------------------------
src/Language/Embedded/VHDL/Monad/Type.hs view
@@ -1,16 +1,26 @@ module Language.Embedded.VHDL.Monad.Type ( Type , Kind(..)-- , std_logic- , signed8, signed16, signed32, signed64- , usigned8, usigned16, usigned32, usigned64+ , std_logic, std_logic_vector+ , signed2, signed4, signed8, signed16, signed32, signed64+ , usigned2, usigned4, usigned8, usigned16, usigned32, usigned64+ , integer , float, double+ , unconstrainedArray, constrainedArray+ -- utility.+ , typeName, typeRange, typeWidth+ , isBit, isBits, isSigned, isUnsigned, isInteger ) where import Language.VHDL -import Language.Embedded.VHDL.Monad.Expression (lit)+import Language.Embedded.VHDL.Monad.Expression+ ( literal+ , number+ , range+ , point+ , upper+ , zero ) -------------------------------------------------------------------------------- -- * VHDL Types.@@ -26,32 +36,42 @@ -- ** Standard logic types. std_logic :: Type-std_logic = SubtypeIndication Nothing (TMType (NSimple (Ident "std_logic"))) Nothing+std_logic = SubtypeIndication Nothing+ (TMType (NSimple (Ident "std_logic")))+ (Nothing) +std_logic_vector :: Integer -> Type+std_logic_vector range = SubtypeIndication Nothing+ (TMType (NSlice (SliceName+ (PName (NSimple (Ident "std_logic_vector")))+ (DRRange (RSimple (upper range) DownTo zero)))))+ (Nothing)+ -------------------------------------------------------------------------------- -- ** Signed & unsigned numbers. -arith :: String -> Int -> Type+arith :: String -> Integer -> Type arith typ range = SubtypeIndication Nothing- (TMType (NSlice (SliceName- (PName (NSimple (Ident typ)))- (DRRange (RSimple (point (range - 1)) DownTo (point 0))))))- (Nothing)- where- point :: Int -> SimpleExpression- point i = SimpleExpression Nothing (Term (FacPrim (lit i) (Nothing)) []) []+ (TMType (NSlice (SliceName+ (PName (NSimple (Ident typ)))+ (DRRange (RSimple (upper range) DownTo zero)))))+ (Nothing) -signed, usigned :: Int -> Type+signed, usigned :: Integer -> Type signed = arith "signed" usigned = arith "unsigned" -signed8, signed16, signed32, signed64 :: Type+signed2, signed4, signed8, signed16, signed32, signed64 :: Type+signed2 = signed 2+signed4 = signed 4 signed8 = signed 8 signed16 = signed 16 signed32 = signed 32 signed64 = signed 64 -usigned8, usigned16, usigned32, usigned64 :: Type+usigned2, usigned4, usigned8, usigned16, usigned32, usigned64 :: Type+usigned2 = usigned 2+usigned4 = usigned 4 usigned8 = usigned 8 usigned16 = usigned 16 usigned32 = usigned 32@@ -69,5 +89,75 @@ float = floating 32 double = floating 64 --- .. add more ..+--------------------------------------------------------------------------------+-- ** Integers.++integer :: Maybe Range -> Type+integer r = SubtypeIndication Nothing+ (TMType (NSimple (Ident "integer")))+ (fmap (CRange . RangeConstraint) r)++--------------------------------------------------------------------------------+-- ** Array Declarations.++compositeTypeDeclaration :: Identifier -> CompositeTypeDefinition -> TypeDeclaration+compositeTypeDeclaration name t = TDFull (FullTypeDeclaration name (TDComposite t))++unconstrainedArray :: Identifier -> SubtypeIndication -> TypeDeclaration+unconstrainedArray name typ = compositeTypeDeclaration name $+ CTDArray (ArrU (UnconstrainedArrayDefinition [] typ))++constrainedArray :: Identifier -> SubtypeIndication -> Range -> TypeDeclaration+constrainedArray name typ range = compositeTypeDeclaration name $+ CTDArray (ArrC (ConstrainedArrayDefinition+ (IndexConstraint [DRRange range]) typ))++--------------------------------------------------------------------------------+-- Utility.++typeName :: Type -> String+typeName (SubtypeIndication _ (TMType (NSimple (Ident n))) _) = n+typeName (SubtypeIndication _ (TMType (NSlice (SliceName (PName (NSimple (Ident n))) _))) _) = n++typeRange :: Type -> Maybe Range+typeRange (SubtypeIndication _ (TMType (NSlice (SliceName _ (DRRange r)))) _) = Just r+typeRange _ = Nothing++-- todo: this assumes we only use numbers when specifying ranges and constraints.+typeWidth :: Type -> Integer+typeWidth (SubtypeIndication _ t c) = (unrange t) * (maybe 1 unconstraint c)+ where+ unliteral :: SimpleExpression -> Integer+ unliteral (SimpleExpression _ (Term (FacPrim (PrimLit (LitNum (NLitPhysical (PhysicalLiteral _ (NSimple (Ident i)))))) _) _) _) =+ read i++ unrange :: TypeMark -> Integer+ unrange (TMType (NSlice (SliceName _ (DRRange (RSimple u DownTo l))))) =+ unliteral u - unliteral l + 1+ unrange (TMType (NSlice (SliceName _ (DRRange (RSimple l To u))))) =+ unliteral u - unliteral l + 1++ unconstraint :: Constraint -> Integer+ unconstraint (CRange (RangeConstraint (RSimple u DownTo l))) =+ unliteral u - unliteral l + 1+ unconstraint (CRange (RangeConstraint (RSimple l To u))) =+ unliteral u - unliteral l + 1++--------------------------------------------------------------------------------++isBit :: Type -> Bool+isBit t = "std_logic" == typeName t++isBits :: Type -> Bool+isBits t = "std_logic_vector" == typeName t++isSigned :: Type -> Bool+isSigned t = "signed" == typeName t++isUnsigned :: Type -> Bool+isUnsigned t = "unsigned" == typeName t++isInteger :: Type -> Bool+isInteger t = "integer" == typeName t+ --------------------------------------------------------------------------------
+ src/Language/Embedded/VHDL/Monad/Util.hs view
@@ -0,0 +1,191 @@+module Language.Embedded.VHDL.Monad.Util+ ( uType, uCast, uResize, uResizeBits+ -- utility.+ , maybePrimary, maybeLit, maybeVar, maybeFun, maybeExp+ , printPrimary+ , printBits+ ) where++import Language.VHDL+import Language.Embedded.VHDL.Monad.Expression+import Language.Embedded.VHDL.Monad.Type++import Text.Printf++import Prelude hiding (toInteger)++--------------------------------------------------------------------------------+-- * Temp (still working on these).+--------------------------------------------------------------------------------++uType :: Expression -> SubtypeIndication -> Expression+uType exp to = uCast exp to to++-- todo: handle bit case better.+-- todo: add naturals for unsigned integers.+uCast :: Expression -> SubtypeIndication -> SubtypeIndication -> Expression+uCast exp from to | isInteger from = go+ where+ -- Integer -> X+ go | isInteger to = exp+ | isUnsigned to = expr $ toUnsigned exp $ expr $ width to+ | isSigned to = expr $ toSigned exp $ expr $ width to+ | isBits to = expr $ asBits+ $ expr $ toSigned exp+ $ expr $ width to+ | otherwise = exp+uCast exp from to | isUnsigned from = go+ where+ -- Unsigned -> X+ go | isInteger to, Just lit <- maybeLit exp = exp+ | isInteger to = expr $ toInteger exp+ | isUnsigned to = uResize exp from to+ | isSigned to = expr $ asSigned $ uResize exp from to+ | isBits to = expr $ asBits $ uResize exp from to+ | otherwise = exp+uCast exp from to | isSigned from = go+ where+ -- Signed -> X+ go | isInteger to , Just lit <- maybeLit exp = exp+ | isInteger to = expr $ toInteger exp+ | isUnsigned to = expr $ asUnsigned $ uResize exp from to+ | isSigned to = uResize exp from to+ | isBits to = expr $ asBits $ uResize exp from to+ | otherwise = exp+uCast exp from to | isBits from = go+ where+ -- Bits n -> X+ go | isInteger to, Just lit <- maybeLit exp = exp+ | isInteger to = expr $ toInteger $ expr $ asSigned exp+ | isUnsigned to = uResize (expr $ asUnsigned exp) from to+ | isSigned to = uResize (expr $ asSigned exp) from to+ | isBits to = uResizeBits exp from to+ | otherwise = exp+uCast exp from to | isBit from, isBit to = exp+uCast exp from to =+ error $ "hardware-edsl.todo: missing type cast from ("+ ++ show (typeName from) ++ ") to ("+ ++ show (typeName to) ++ ")."++uResize :: Expression -> SubtypeIndication -> SubtypeIndication -> Expression+uResize exp from to+ -- if literal, simply resize it.+ | Just p <- maybeLit exp = expr $ literal $ number $ printPrimary p to+ -- if variable, and types are equal, disregard resize.+ | Just v <- maybeVar exp, typeWidth from == typeWidth to = exp+ -- if already resized, disregard new resize.+ | Just w <- castWidth exp, w == typeWidth to = exp+ -- otherwise, resize.+ | otherwise = expr $ resize exp $ expr $ width to+ where+ ++uResizeBits :: Expression -> SubtypeIndication -> SubtypeIndication -> Expression+uResizeBits exp from to+ -- if literal, simply resize it.+ | Just p <- maybeLit exp = expr $ literal $ number $ printPrimary p to+ -- if variable, and same size, disregard resize.+ | typeWidth from == typeWidth to = exp+ -- if target is smaller, slice source.+ | typeWidth from > typeWidth to+ , Just r <- typeRange to = expr $ name $ slice prefix r+ -- if target is larger, append zeroes.+ | typeWidth from < typeWidth to =+ let zeroes = name $ simple $ printBits (typeWidth to - typeWidth from) (0 :: Int)+ bits = name $ prefix+ wrap s = ENand (Relation (ShiftExpression s Nothing) Nothing) Nothing+ in wrap (cat [term zeroes, term bits])+ | otherwise = error $ show exp+ where+ prefix :: Name+ prefix | Just (PrimName n) <- maybeVar exp = n+ | Just (PrimFun f) <- maybeFun exp = fc_function_name f+ | otherwise = error "hardware-edsl.slice: prefix of slice not var/fun."++--------------------------------------------------------------------------------++expr :: Primary -> Expression+expr (PrimExp e) = e+expr (primary) = ENand (Relation (ShiftExpression (SimpleExpression Nothing (Term (FacPrim primary Nothing) []) []) Nothing) Nothing) Nothing++term :: Primary -> Term+term primary = Term (FacPrim primary Nothing) []++width :: SubtypeIndication -> Primary+width = literal . number . show . typeWidth++--------------------------------------------------------------------------------++maybePrimary :: Expression -> Maybe Primary+maybePrimary (ENand (Relation (ShiftExpression (SimpleExpression Nothing (Term (FacPrim p Nothing) []) []) Nothing) Nothing) Nothing) = Just p+maybePrimary _ = Nothing++maybeLit :: Expression -> Maybe Primary+maybeLit e | Just p@(PrimLit _) <- maybePrimary e = Just p+ | otherwise = Nothing++maybeVar :: Expression -> Maybe Primary+maybeVar e | Just p@(PrimName _) <- maybePrimary e = Just p+ | otherwise = Nothing++maybeFun :: Expression -> Maybe Primary+maybeFun e | Just p@(PrimFun _) <- maybePrimary e = Just p+ | otherwise = Nothing++maybeCast :: Expression -> Maybe Primary+maybeCast e | Just p@(PrimTCon _) <- maybePrimary e = Just p+ | otherwise = Nothing++maybeExp :: Expression -> Maybe Expression+maybeExp e | Just (PrimExp p) <- maybePrimary e = Just p+ | otherwise = Nothing++--------------------------------------------------------------------------------++castWidth :: Expression -> Maybe Integer+castWidth e+ | Just f <- maybeFun e+ , Just (n, as) <- stripFun f = widthOf n as+ where+ widthOf :: String -> [Expression] -> Maybe Integer+ widthOf "resize" [e, size] = stripNum =<< maybeLit size+ widthOf "to_signed" [e, size] = stripNum =<< maybeLit size+ widthOf "to_unsigned" [e, size] = stripNum =<< maybeLit size+ widthOf "to_integer" [e] = Nothing -- todo: hmm?+ widthOf "signed" [e] = castWidth e+ widthOf "unsigned" [e] = castWidth e+ widthOf "std_logic_vector" [e] = castWidth e+ widthOf _ _ = Nothing+castWidth _ = Nothing++--------------------------------------------------------------------------------++stripNum :: Primary -> Maybe Integer+stripNum (PrimLit (LitNum (NLitPhysical (PhysicalLiteral Nothing (NSimple (Ident i)))))) = Just (read i)+stripNum _ = Nothing++stripFun :: Primary -> Maybe (String, [Expression])+stripFun (PrimFun (FunctionCall (NSimple (Ident i)) Nothing)) = Just (i, [])+stripFun (PrimFun (FunctionCall (NSimple (Ident i)) (Just (AssociationList as)))) = Just (i, stripArgs as)+ where+ stripArgs :: [AssociationElement] -> [Expression]+ stripArgs [] = []+ stripArgs ((AssociationElement Nothing (APDesignator (ADExpression a))):as) = a : stripArgs as+stripFun _ = Nothing++stripPrimary :: Primary -> Maybe Expression+stripPrimary (PrimExp e) = Just e+stripPrimary _ = Nothing++--------------------------------------------------------------------------------++-- todo: this assumes i>0? and i<2^(width t)?+printPrimary :: Primary -> SubtypeIndication -> String+printPrimary p t = case (stripNum p) of+ Just i -> printBits (typeWidth t) i+ Nothing -> error "hardware-edsl.printPrimary: not a literal."++printBits :: (PrintfArg a, PrintfType b) => Integer -> a -> b+printBits zeroes = printf ("\"%0" ++ show zeroes ++ "b\"")++--------------------------------------------------------------------------------