imperative-edsl-vhdl-0.3.2: src/Language/Embedded/VHDL/Expression.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Language.Embedded.VHDL.Expression
( VHDLDomain
, Data
, Type
-- expressions
, not, and, or, xor, xnor, nand, nor
, eq, neq
, lt, lte, gt, gte
, sll, srl, sla, sra, rol, ror
, add, sub, cat
, mul
, div, mod, rem
, exp, abs
, value, force, share
-- types
, std_logic
, signed, usigned
, signed8, signed16, signed32, signed64
, usigned8, usigned16, usigned32, usigned64
) where
import Language.VHDL (Identifier(..))
import qualified Language.VHDL as V
import Language.Embedded.VHDL.Interface
import Language.Embedded.VHDL.Monad (VHDL)
import Language.Embedded.VHDL.Expression.Hoist
import Language.Embedded.VHDL.Expression.Represent
import qualified Language.Embedded.VHDL.Monad as M
import qualified Language.Embedded.VHDL.Expression.Hoist as Hoist
import Language.Embedded.VHDL.Monad.Type (
std_logic
, signed, usigned
, signed8, signed16, signed32, signed64
, usigned8, usigned16, usigned32, usigned64
)
import qualified Language.Embedded.VHDL.Monad.Type as T
import Language.Syntactic hiding (fold, printExpr, showAST, drawAST, writeHtmlAST)
import Language.Syntactic.Functional
import Language.Syntactic.Functional.Sharing
import Language.Syntactic.Functional.Tuple
import Language.Syntactic.Sugar.BindingTyped ()
import Language.Syntactic.Sugar.TupleTyped ()
import qualified Language.Syntactic as Syntactic
import Control.Arrow
import Control.Applicative (liftA)
import Data.Bits (Bits)
import Data.Maybe (fromJust)
import Data.Typeable (Typeable)
import Data.Word (Word8)
import qualified Data.Bits as Bits
import Prelude hiding (not, and, or, abs, rem, div, mod, exp)
import qualified Prelude
--------------------------------------------------------------------------------
-- * ...
--------------------------------------------------------------------------------
class (Typeable a, Rep a, Eq a) => Type a
instance (Typeable a, Rep a, Eq a) => Type a
--------------------------------------------------------------------------------
-- ** ...
data Expression sig
where
And :: Expression (Bool :-> Bool :-> Full Bool)
Or :: Expression (Bool :-> Bool :-> Full Bool)
Xor :: Expression (Bool :-> Bool :-> Full Bool)
Xnor :: Expression (Bool :-> Bool :-> Full Bool)
Nand :: Expression (Bool :-> Bool :-> Full Bool)
Nor :: Expression (Bool :-> Bool :-> Full Bool)
instance Equality Expression
instance StringTree Expression
instance Symbol Expression
where
symSig And = signature
symSig Or = signature
symSig Xor = signature
symSig Xnor = signature
symSig Nand = signature
symSig Nor = signature
instance Render Expression
where
renderSym And = "and"
renderSym Or = "or"
renderSym Xor = "xor"
renderSym Xnor = "xnor"
renderSym Nand = "nand"
renderSym Nor = "nor"
instance Eval Expression
where
evalSym And = (&&)
evalSym Or = (||)
evalSym Xor = \x y -> (x && Prelude.not y) || (Prelude.not x && y)
evalSym Xnor = \x y -> (Prelude.not x && Prelude.not y) || (x && y)
evalSym Nand = \x y -> Prelude.not (x && y)
evalSym Nor = \x y -> Prelude.not (x || y)
instance EvalEnv Expression env
--------------------------------------------------------------------------------
-- ** ...
data Relational sig
where
Eq :: Type a => Relational (a :-> a :-> Full Bool)
Neq :: Type a => Relational (a :-> a :-> Full Bool)
Lt :: (Type a, Ord a) => Relational (a :-> a :-> Full Bool)
Lte :: (Type a, Ord a) => Relational (a :-> a :-> Full Bool)
Gt :: (Type a, Ord a) => Relational (a :-> a :-> Full Bool)
Gte :: (Type a, Ord a) => Relational (a :-> a :-> Full Bool)
instance Equality Relational
instance StringTree Relational
instance Symbol Relational
where
symSig Eq = signature
symSig Neq = signature
symSig Lt = signature
symSig Lte = signature
symSig Gt = signature
symSig Gte = signature
instance Render Relational
where
renderSym Eq = "(==)"
renderSym Neq = "(/=)"
renderSym Lt = "(<)"
renderSym Lte = "(<=)"
renderSym Gt = "(>)"
renderSym Gte = "(>=)"
instance Eval Relational
where
evalSym Eq = (==)
evalSym Neq = (/=)
evalSym Lt = (<)
evalSym Lte = (<=)
evalSym Gt = (>)
evalSym Gte = (>=)
instance EvalEnv Relational env
--------------------------------------------------------------------------------
-- ** ...
data Shift sig
where
Sll :: (Type a, Bits a, Type b, Integral b) => Shift (a :-> b :-> Full a)
Srl :: (Type a, Bits a, Type b, Integral b) => Shift (a :-> b :-> Full a)
Sla :: (Type a, Bits a, Type b, Integral b) => Shift (a :-> b :-> Full a)
Sra :: (Type a, Bits a, Type b, Integral b) => Shift (a :-> b :-> Full a)
Rol :: (Type a, Bits a, Type b, Integral b) => Shift (a :-> b :-> Full a)
Ror :: (Type a, Bits a, Type b, Integral b) => Shift (a :-> b :-> Full a)
instance Equality Shift
instance StringTree Shift
instance Symbol Shift
where
symSig Sll = signature
symSig Srl = signature
symSig Sla = signature
symSig Sra = signature
symSig Rol = signature
symSig Ror = signature
instance Render Shift
where
renderSym Sll = "sll"
renderSym Srl = "srl"
renderSym Sla = "sla"
renderSym Sra = "sra"
renderSym Rol = "rol"
renderSym Ror = "ror"
instance Eval Shift
where
evalSym Sll = \x i -> Bits.shiftL x (fromIntegral i)
evalSym Srl = \x i -> shiftLR x (fromIntegral i)
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)
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]
Nothing -> y
instance EvalEnv Shift env
--------------------------------------------------------------------------------
-- ** ...
data Simple sig
where
Neg :: (Type a, Num a) => Simple (a :-> Full a)
Pos :: (Type a, Num a) => Simple (a :-> Full a)
Add :: (Type a, Num a) => Simple (a :-> a :-> Full a)
Sub :: (Type a, Num a) => Simple (a :-> a :-> Full a)
Cat :: (Type a, Show a, Read a) => Simple (a :-> a :-> Full a)
instance Equality Simple
instance StringTree Simple
instance Symbol Simple
where
symSig Neg = signature
symSig Pos = signature
symSig Add = signature
symSig Sub = signature
symSig Cat = signature
instance Render Simple
where
renderSym Neg = "(-)"
renderSym Pos = "id"
renderSym Add = "(+)"
renderSym Sub = "(-)"
renderSym Cat = "(&)"
instance Eval Simple
where
evalSym Neg = negate
evalSym Pos = id
evalSym Add = (+)
evalSym Sub = (-)
evalSym Cat = \x y -> read (show x ++ show y)
instance EvalEnv Simple env
--------------------------------------------------------------------------------
-- ** ...
data Term sig
where
Mul :: (Type a, Num a) => Term (a :-> a :-> Full a)
Div :: (Type a, Integral a) => Term (a :-> a :-> Full a)
Mod :: (Type a, Integral a) => Term (a :-> a :-> Full a)
Rem :: (Type a, Integral a) => Term (a :-> a :-> Full a)
instance Equality Term
instance StringTree Term
instance Symbol Term
where
symSig Mul = signature
symSig Div = signature
symSig Mod = signature
symSig Rem = signature
instance Render Term
where
renderSym Mul = "(*)"
renderSym Div = "(/)"
renderSym Mod = "(%)"
renderSym Rem = "rem"
instance Eval Term
where
evalSym Mul = (*)
evalSym Div = Prelude.div
evalSym Mod = Prelude.mod
evalSym Rem = Prelude.rem
instance EvalEnv Term env
--------------------------------------------------------------------------------
-- ** ...
data Factor sig
where
Exp :: (Type a, Num a, Type b, Integral b) => Factor (a :-> b :-> Full a)
Abs :: (Type a, Num a) => Factor (a :-> Full a)
Not :: Factor (Bool :-> Full Bool)
instance Equality Factor
instance StringTree Factor
instance Symbol Factor
where
symSig Exp = signature
symSig Abs = signature
symSig Not = signature
instance Render Factor
where
renderSym Exp = "(**)"
renderSym Abs = "abs"
renderSym Not = "not"
instance Eval Factor
where
evalSym Exp = (^)
evalSym Abs = Prelude.abs
evalSym Not = Prelude.not
instance EvalEnv Factor env
--------------------------------------------------------------------------------
-- ** ...
data Primary sig
where
Lit :: Type a => a -> Primary (Full a)
instance Equality Primary
instance StringTree Primary
instance Symbol Primary
where
symSig (Lit _) = signature
instance Render Primary
where
renderSym (Lit _) = "lit"
instance Eval Primary
where
evalSym (Lit i) = i
instance EvalEnv Primary env
--------------------------------------------------------------------------------
type VHDLDomain = Typed Dom
type Dom =
-- Syntactic
BindingT
:+: Let
:+: Tuple
:+: Construct
-- VHDL constructs
:+: Expression
:+: Relational
:+: Shift
:+: Simple
:+: Term
:+: Factor
:+: Primary
newtype Data a = Data { unData :: ASTF VHDLDomain a }
instance Type a => Syntactic (Data a)
where
type Domain (Data a) = VHDLDomain
type Internal (Data a) = a
desugar = unData
sugar = Data
class (Syntactic a, Domain a ~ VHDLDomain, Type (Internal a)) => Syntax a
instance (Syntactic a, Domain a ~ VHDLDomain, Type (Internal a)) => Syntax a
type instance PredicateExp Data = Type
--------------------------------------------------------------------------------
-- * Backend
--------------------------------------------------------------------------------
codeMotionInterface :: CodeMotionInterface VHDLDomain
codeMotionInterface = defaultInterface VarT LamT sharable (const True)
where
sharable :: ASTF VHDLDomain a -> ASTF VHDLDomain b -> Bool
sharable (Sym _) _ = False
sharable (lam :$ _) _
| Just _ <- prLam lam = False
sharable _ (lam :$ _)
| Just _ <- prLam lam = False
sharable (sel :$ _) _
| Just Sel1 <- prj sel = False
| Just Sel2 <- prj sel = False
| Just Sel3 <- prj sel = False
| Just Sel4 <- prj sel = False
sharable _ _ = True
showExpr :: (Syntactic a, Domain a ~ VHDLDomain) => a -> String
showExpr = render . codeMotion codeMotionInterface . desugar
showAST :: (Syntactic a, Domain a ~ VHDLDomain) => a -> String
showAST = Syntactic.showAST . codeMotion codeMotionInterface . desugar
eval :: (Syntactic a, Domain a ~ VHDLDomain) => a -> Internal a
eval = evalClosed . desugar
--------------------------------------------------------------------------------
-- * Frontend
--------------------------------------------------------------------------------
value :: Syntax a => Internal a -> a
value = sugar . injT . Lit
force :: Syntax a => a -> a
force = resugar
share :: (Syntax a, Syntax b) => a -> (a -> b) -> b
share = sugarSymTyped Let
--------------------------------------------------------------------------------
-- ** ...
-- logical operators
and, or, xor, xnor, nand, nor :: Data Bool -> Data Bool -> Data Bool
and = sugarSymTyped And
or = sugarSymTyped Or
xor = sugarSymTyped Xor
xnor = sugarSymTyped Xnor
nand = sugarSymTyped Nand
nor = sugarSymTyped Nor
-- relational operators
eq, neq :: (Type a, Eq a) => Data a -> Data a -> Data Bool
eq = sugarSymTyped Eq
neq = sugarSymTyped Neq
lt, lte, gt, gte :: (Type a, Ord a) => Data a -> Data a -> Data Bool
lt = sugarSymTyped Lt
lte = sugarSymTyped Lte
gt = sugarSymTyped Gt
gte = sugarSymTyped Gte
-- shift operators
sll, srl, sla, sra, rol, ror :: (Type a, Bits a, Type b, Integral b) => Data a -> Data b -> Data a
sll = sugarSymTyped Sll
srl = sugarSymTyped Srl
sla = sugarSymTyped Sla
sra = sugarSymTyped Sra
rol = sugarSymTyped Rol
ror = sugarSymTyped Ror
-- adding operators
add, sub :: (Type a, Num a) => Data a -> Data a -> Data a
add = sugarSymTyped Add
sub = sugarSymTyped Sub
cat :: (Type a, Read a, Show a) => Data a -> Data a -> Data a
cat = sugarSymTyped Cat
-- multiplying operators
mul :: (Type a, Num a) => Data a -> Data a -> Data a
mul = sugarSymTyped Mul
div, mod, rem :: (Type a, Integral a) => Data a -> Data a -> Data a
div = sugarSymTyped Div
mod = sugarSymTyped Mod
rem = sugarSymTyped Rem
-- miscellaneous operators
exp :: (Type a, Num a, Type b, Integral b) => Data a -> Data b -> Data a
exp = sugarSymTyped Exp
abs :: (Type a, Num a) => Data a -> Data a
abs = sugarSymTyped Abs
not :: Data Bool -> Data Bool
not = sugarSymTyped Not
--------------------------------------------------------------------------------
-- ** ...
instance (Type a, Eq a) => Eq (Data a)
where
(==) = error "VHDL: equality checking is not supported"
instance (Type a, Ord a) => Ord (Data a)
where
compare = error "VHDL: compare is not supported"
max = error "VHDL: max is not supported"
min = error "VHDL: min is not supported"
instance (Type a, Bounded a) => Bounded (Data a)
where
minBound = value minBound
maxBound = value maxBound
instance (Type a, Enum a) => Enum (Data a)
where
toEnum = error "VHDL: toEnum is not supported"
fromEnum = error "VHDL: fromEnum is not supported"
instance (Type a, Real a) => Real (Data a)
where
toRational = error "VHDL: toRational is not supported"
instance (Type a, Num a) => Num (Data a)
where
fromInteger = value . fromInteger
(+) = add
(-) = sub
(*) = mul
abs = abs
signum = error "VHDL: signum is not supported"
instance (Type a, Integral a) => Integral (Data a)
where
quot = error "VHDL: quotient is not supported"
rem = rem
div = div
mod = mod
quotRem a b = (quot a b, rem a b)
divMod a b = (div a b, mod a b)
toInteger = error "VHDL: toInteger is not supported"
instance (Type a, Fractional a) => Fractional (Data a)
where
(/) = error "VHDL: floating point division is not _yet_ supported"
recip = (/) (value 1)
fromRational = error "VHDL: fromRational is not supported"
--------------------------------------------------------------------------------
-- * Evaluation of Expressions
--------------------------------------------------------------------------------
instance EvaluateExp Data
where
litE = value
evalE = eval
--------------------------------------------------------------------------------
-- * Compilation of expressions
--------------------------------------------------------------------------------
instance CompileExp Data
where
varE i = sugarSymTyped ((VarT (Name i)))
compT = compileT
compE = liftA lift
. compileE
. mapAST (\(Typed s) -> s)
. codeMotion codeMotionInterface
. desugar
--------------------------------------------------------------------------------
-- ** ...
compileT :: forall a. Rep a => Data a -> VHDL T.Type
compileT _ =
do let t = unTag (typed :: Tagged a T.Type)
declare (undefined :: a)
return t
compileE :: ASTF Dom a -> VHDL Kind
compileE var
| Just (Var v) <- prj var = return $ P $ M.name $ vars v
| Just (VarT v) <- prj var = return $ P $ M.name $ vars v
compileE val
| Just (Lit v) <- prj val = return $ P $ M.string $ format v
compileE (lets :$ a :$ (lam :$ body))
| Just (Let) <- prj lets
, Just (LamT v) <- prj lam
= do let v' = Ident $ vars v
a' <- lift <$> compileE a
M.addSequential $ M.assignVariable v' a'
compileE body
-- that we pick variable assignment might be a problem
compileE (expr :$ x :$ y)
| Just And <- prj expr = go $ \a b -> M.and [a, b]
| Just Or <- prj expr = go $ \a b -> M.or [a, b]
| Just Xor <- prj expr = go $ \a b -> M.xor [a, b]
| Just Xnor <- prj expr = go $ \a b -> M.xnor [a, b]
| Just Nand <- prj expr = go $ M.nand
| Just Nor <- prj expr = go $ M.nor
where
go :: (V.Relation -> V.Relation -> V.Expression) -> VHDL Kind
go f = bin (\a b -> Hoist.E $ f (lift a) (lift b)) x y
compileE (relate :$ x :$ y)
| Just Eq <- prj relate = go $ M.eq
| Just Neq <- prj relate = go $ M.neq
| Just Lt <- prj relate = go $ M.lt
| Just Lte <- prj relate = go $ M.lte
| Just Gt <- prj relate = go $ M.gt
| Just Gte <- prj relate = go $ M.gte
where
go :: (V.ShiftExpression -> V.ShiftExpression -> V.Relation) -> VHDL Kind
go f = bin (\a b -> Hoist.R $ f (lift a) (lift b)) x y
compileE (shift :$ x :$ y)
| Just Sll <- prj shift = go $ M.sll
| Just Srl <- prj shift = go $ M.srl
| Just Sla <- prj shift = go $ M.sla
| Just Sra <- prj shift = go $ M.sra
| Just Rol <- prj shift = go $ M.rol
| Just Ror <- prj shift = go $ M.ror
where
go :: (V.SimpleExpression -> V.SimpleExpression -> V.ShiftExpression) -> VHDL Kind
go f = bin (\a b -> Hoist.Sh $ f (lift a) (lift b)) x y
compileE (simple :$ x)
| Just Neg <- prj simple = go $ M.neg
| Just Pos <- prj simple = go $ lift
where
go :: (V.Term -> V.SimpleExpression) -> VHDL Kind
go f = un (\a -> Hoist.Si $ f (lift a)) x
compileE (simple :$ x :$ y)
| Just Add <- prj simple = go $ \a b -> M.add [a, b]
| Just Sub <- prj simple = go $ \a b -> M.sub [a, b]
| Just Cat <- prj simple = go $ \a b -> M.cat [a, b]
where
go :: (V.Term -> V.Term -> V.SimpleExpression) -> VHDL Kind
go f = bin (\a b -> Hoist.Si $ f (lift a) (lift b)) x y
compileE (term :$ x :$ y)
| Just Mul <- prj term = go $ \a b -> M.mul [a, b]
| Just Div <- prj term = go $ \a b -> M.div [a, b]
| Just Mod <- prj term = go $ \a b -> M.mod [a, b]
| Just Rem <- prj term = go $ \a b -> M.rem [a, b]
where
go :: (V.Factor -> V.Factor -> V.Term) -> VHDL Kind
go f = bin (\a b -> Hoist.T $ f (lift a) (lift b)) x y
compileE (factor :$ x :$ y)
| Just Exp <- prj factor = go $ M.exp
where
go :: (V.Primary -> V.Primary -> V.Factor) -> VHDL Kind
go f = bin (\a b -> Hoist.F $ f (lift a) (lift b)) x y
compileE (factor :$ x)
| Just Abs <- prj factor = go $ M.abs
| Just Not <- prj factor = go $ M.not
where
go :: (V.Primary -> V.Factor) -> VHDL Kind
go f = un (\a -> Hoist.F $ f (lift a)) x
compileE (primary)
| Just (Lit i) <- prj primary = return $ Hoist.P $ M.lit $ format i
compileE x = error $ "imperative-edsl: missing compiler case for " ++ (Syntactic.showAST x)
--------------------------------------------------------------------------------
-- | ...
vars :: Name -> String
vars v = 'v' : show v
-- | ...
un :: (Kind -> Kind) -> ASTF Dom a -> VHDL Kind
un f x = compileE x >>= return . f
-- | ...
bin :: (Kind -> Kind -> Kind) -> ASTF Dom a -> ASTF Dom b -> VHDL Kind
bin f x y = do
x' <- compileE x
y' <- compileE y
return $ f x' y'
--------------------------------------------------------------------------------