packages feed

hardware-edsl-0.1.2: src/Language/Embedded/Hardware/Expression/Syntax.hs

{-# 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 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.Typeable (Typeable)
import qualified Data.Bits as B

import GHC.TypeLits hiding (Symbol)

--------------------------------------------------------------------------------
-- * Syntax of hardware expressions.
--------------------------------------------------------------------------------

-- | Domain of expressions.
type Dom =
      Expression
  :+: Relational
  :+: ShiftExpression
  :+: SimpleExpression
  :+: Term
  :+: Factor
  :+: Primary

-- | Typed expressions.
data T sig
  where
    T :: HType (DenResult sig) => { unT :: Dom sig } -> T sig

-- | Specialized sugarSym for T.
sugarT
  :: ( Signature (SmartSig fi), sub :<: Dom
     , T :<: SmartSym fi
     , SyntacticN f fi
     , SmartFun (SmartSym fi) (SmartSig fi) ~ fi
     , HType (DenResult (SmartSig fi)))
  => sub (SmartSig fi)
  -> f
sugarT sym = sugarSym (T $ inj sym)

-- | Hardware expressions.
newtype HExp a = HExp { unHExp :: ASTF T a }

instance Syntactic (HExp a)
  where
    type Domain   (HExp a) = T
    type Internal (HExp a) = a

    desugar = unHExp
    sugar   = HExp 

--------------------------------------------------------------------------------
-- ** Syntax.

-- | Logical expressions.
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)

-- | Relational expressions.
data Relational sig
  where
    Eq   :: (HType a)        => Relational (a :-> a :-> Full Bool)
    Neq  :: (HType a)        => Relational (a :-> a :-> Full Bool)
    Lt   :: (HType a, Ord a) => Relational (a :-> a :-> Full Bool)
    Lte  :: (HType a, Ord a) => Relational (a :-> a :-> Full Bool)
    Gt   :: (HType a, Ord a) => Relational (a :-> a :-> Full Bool)
    Gte  :: (HType a, Ord a) => Relational (a :-> a :-> Full Bool)

-- | Bit vector expressions.
data ShiftExpression sig
  where
    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 SimpleExpression sig
  where
    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
  where
    Mul :: (HType a, Num a)      => Term (a :-> a :-> Full a)
    Div :: (HType a, Integral a) => Term (a :-> a :-> Full a)
    Mod :: (HType a, Integral a) => Term (a :-> a :-> Full a)
    Rem :: (HType a, Integral a) => Term (a :-> a :-> Full a)

-- | ...
data Factor sig
  where
    Exp :: (HType a, Num a, HType b, Integral b) => Factor (a :-> b :-> Full a)
    Abs :: (HType a, Num a) => Factor (a :-> Full a)
    Not :: Factor (Bool :-> Full Bool)

-- | ...
data Primary sig
  where
    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.

instance CompArrayIx HExp

instance Equality T
  where
    equal (T s) (T t) = equal s t
    hash  (T s)       = hash s

instance StringTree T
  where
    stringTreeSym as (T s) = stringTreeSym as (T s)

instance Symbol T
  where
    symSig (T s) = symSig s

instance Render T
  where
    renderSym     (T s) = renderSym s
    renderArgs as (T s) = renderArgs as s

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

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

instance Equality   ShiftExpression
instance StringTree ShiftExpression

instance Symbol ShiftExpression
  where
    symSig Sll = signature
    symSig Srl = signature
    symSig Sla = signature
    symSig Sra = signature
    symSig Rol = signature
    symSig Ror = signature

instance Render ShiftExpression
  where
    renderSym Sll = "sll"
    renderSym Srl = "srl"
    renderSym Sla = "sla"
    renderSym Sra = "sra"
    renderSym Rol = "rol"
    renderSym Ror = "ror"

instance Eval ShiftExpression
  where
    evalSym Sll = \x i -> B.shiftL x (fromIntegral i)
    evalSym Srl = \x i -> shiftLR     x (fromIntegral i)
      where
        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 -> 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 ShiftExpression env

instance Equality   SimpleExpression
instance StringTree SimpleExpression

instance Symbol SimpleExpression
  where
    symSig Neg = signature
    symSig Pos = signature
    symSig Add = signature
    symSig Sub = signature
    symSig Cat = signature

instance Render SimpleExpression
  where
    renderSym Neg = "(-)"
    renderSym Pos = "id"
    renderSym Add = "(+)"
    renderSym Sub = "(-)"
    renderSym Cat = "(&)"

instance Eval SimpleExpression
  where
    evalSym Neg = negate
    evalSym Pos = id
    evalSym Add = (+)
    evalSym Sub = (-)
    evalSym Cat = bitJoin

instance EvalEnv SimpleExpression env

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

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

instance Equality   Primary
instance StringTree Primary

instance Symbol Primary
  where
    symSig (Name _)       = signature
    symSig (Literal _)    = signature
    symSig (Aggregate _)  = signature
    symSig (Others)       = signature
    symSig (Function _ _) = signature
    symSig (Qualified _)  = signature
    symSig (Conversion _) = signature
    symSig (Allocator)    = signature

instance Render Primary
  where
    renderSym (Name _)       = "name"
    renderSym (Literal _)    = "lit"
    renderSym (Aggregate _)  = "agg"
    renderSym (Others)       = "others"
    renderSym (Function _ _) = "fun"
    renderSym (Qualified _)  = "qual"
    renderSym (Conversion _) = "conv"
    renderSym (Allocator)    = "alloc"

instance Eval Primary
  where
    evalSym (Name _)       = error "cannot eval open names!"
    evalSym (Literal i)    = i
    evalSym (Aggregate _)  = error "primary-todo: eval aggregate names."
    evalSym (Others)       = error "primary-todo: eval others"
    evalSym (Function _ f) = f
    evalSym (Qualified _)  = error "primary-todo: eval qualified names."
    evalSym (Conversion f) = f
    evalSym (Allocator)    = error "primary-todo: eval allocator"

instance EvalEnv Primary env

--------------------------------------------------------------------------------