{-# LANGUAGE GADTs #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} module Language.Embedded.Hardware.Expression.Backend.VHDL where import Language.Syntactic import Language.Syntactic.Functional (Denotation, evalSym) import Language.Embedded.Hardware.Expression.Syntax 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 import qualified Language.Embedded.Hardware.Expression.Hoist as Hoist import Language.Embedded.VHDL (VHDL) 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 = PrimType litE = value varE = var -------------------------------------------------------------------------------- instance EvaluateExp HExp where evalE = evalHExp evalHExp :: HExp a -> a evalHExp = go . unHExp where go :: AST T sig -> Denotation sig go (Sym (T s)) = evalSym s go (f :$ a) = go f $ go a -------------------------------------------------------------------------------- instance CompileExp HExp where compE = compHExp compHType :: forall a . PrimType a => HExp a -> VHDL VHDL.Type compHType _ = declareType (Proxy :: Proxy a) compHTypeFun :: forall a b . (PrimType a, PrimType b) => (a -> b) -> VHDL VHDL.Type compHTypeFun _ = declareType (Proxy :: 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 compDomain :: forall sig . PrimType (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] | Just Xor <- prj expr = go $ \a b -> VHDL.xor [a, b] | Just Xnor <- prj expr = go $ \a b -> VHDL.xnor [a, b] | Just Nand <- prj expr = go VHDL.nand | Just Nor <- prj expr = go VHDL.nor where go :: (VHDL.Relation -> VHDL.Relation -> VHDL.Expression) -> VHDL Kind go f = do 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 | Just Lt <- prj relate = go VHDL.lt | Just Lte <- prj relate = go VHDL.lte | Just Gt <- prj relate = go VHDL.gt | Just Gte <- prj relate = go VHDL.gte where go :: (VHDL.ShiftExpression -> VHDL.ShiftExpression -> VHDL.Relation) -> VHDL Kind go f = do 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 | Just Sla <- prj shift = go $ VHDL.sla | Just Sra <- prj shift = go $ VHDL.sra | Just Rol <- prj shift = go $ VHDL.rol | Just Ror <- prj shift = go $ VHDL.ror where go :: (VHDL.SimpleExpression -> VHDL.SimpleExpression -> VHDL.ShiftExpression) -> VHDL Kind go f = do 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 | Just Cat <- prj simple = go VHDL.cat where go :: ([VHDL.Term] -> VHDL.SimpleExpression) -> VHDL Kind go f = do x' <- Hoist.lift <$> compLoop x y' <- Hoist.lift <$> compLoop y return $ Hoist.Si $ f [x', y'] compDomain simple (x :* _) | Just Neg <- prj simple = do x' <- Hoist.lift <$> compLoop x return $ Hoist.Si $ VHDL.neg x' | 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 | Just Mod <- prj term = go VHDL.mod | Just Rem <- prj term = go VHDL.rem where go :: ([VHDL.Factor] -> VHDL.Term) -> VHDL Kind go f = do 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 y' <- Hoist.lift <$> compLoop y return $ Hoist.F $ VHDL.exp x' y' compDomain factor (x :* _) | Just Abs <- prj factor = do x' <- Hoist.lift <$> compLoop x return $ Hoist.F $ VHDL.abs x' | 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 tt <- compHType (undefined :: HExp (DenResult sig)) tf <- compHTypeFun (f) x' <- Hoist.lift <$> compLoop 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.literal $ VHDL.number $ primTypeVal 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.simple f) (fmap Hoist.lift as) | Just (Allocator) <- prj primary = error "expression-backend-todo: allocators." --------------------------------------------------------------------------------