{-# LANGUAGE RankNTypes, GADTs, TypeFamilies, TypeOperators, TemplateHaskell #-} {-# LANGUAGE FlexibleInstances, FlexibleContexts, UndecidableInstances #-} {-# LANGUAGE MultiParamTypeClasses, OverlappingInstances, NoImplicitPrelude #-} {-# LANGUAGE DoRec #-} -- {-# LANGUAGE NoMonomorphismRestriction #-} module Hardware.HHDL.HHDL( -- convenience exports. module Data.Typeable , module Hardware.HHDL.HDLPrelude , module Prelude , module Control.Monad.Fix , module Hardware.HHDL.BitRepr , module Hardware.HHDL.TyLeA , module Hardware.HHDL.TH -- This module exports. , (:.)(..), Nil(Nil) -- our own HList. , Wire -- abstract type. , HDL(..) -- what kind of HDL you want to generate. , WireOp(..) -- the means to extend operations. , toBits -- a method to get bit vector from a type. , WList , WiresList -- a class that defines list of wires. , NLM , Clock(..), ClockAllowed , Clocked -- the type constructor of clocked circuits. , mkClockedNamed -- for top-level exported entities. , mkClocked , Comb -- the type constrictor of combinational (stateless) circuits. , mkComb , Mealy -- simple MEaly state machine. , mkMealyNamed -- for top-level exported entities. , mkMealy , assignWire -- w <- assignWire (expression) , assignFlattened , register -- latched <- register defaultValue wireToLatch , instantiate -- instantiate entity, literally. outputs <- instantiate entity inputs , constant -- convert Haskell value (BitRepr one) into wire. , writeHDLText -- write HDL text of an entity. , match -- match expression against list of patterns. , (-->) -- combine pattern and netlists. , pvar, pcst, pwild -- variable match, constant match, wildcard match. , pJust, mkJust, pNothing, mkNothing -- generated for Maybe. , pLeft, mkLeft, pRight, mkRight -- generated for Maybe. ) where -- what we need from Prelude: import Prelude ( putStrLn, ($), (.), IO, (++), String, repeat, zipWith, head , fst, snd, length, map, Show(..), reverse, Int, Integer, flip, filter , unwords, unlines, replicate, const, undefined, error, Ordering(..) , concat, concatMap, take, tail, iterate, Bool(..), Monad(..) , writeFile, otherwise, asTypeOf , foldr, foldl, foldl1, zipWith3, zip, init, Maybe(..), Either(..)) import qualified Prelude import Control.Monad.State import Control.Monad import Control.Monad.Fix import qualified Data.Bits as B import qualified Data.Bits import Data.IORef import Data.List (nub, intersperse) import Data.Maybe import qualified Data.Map as Map import qualified Data.Set as Set import Data.Typeable import Data.Word import qualified Language.Haskell.TH as TH import System.IO.Unsafe import qualified Text.Printf import Hardware.HHDL.BitRepr import Hardware.HHDL.HDLPrelude import Hardware.HHDL.TH import Hardware.HHDL.TyLeA ------------------------------------------------------------------------------- -- Our own HList. infixr 5 :. data a :. as = a :. as deriving Show data Nil = Nil ------------------------------------------------------------------------------- -- Unique index generation. {-# NOINLINE uniqueCounterRef #-} uniqueCounterRef :: IORef Int uniqueCounterRef = unsafePerformIO (newIORef 0) createUniqueIndex :: (String -> Int -> a) -> String -> a createUniqueIndex mk n = unsafePerformIO $ do atomicModifyIORef uniqueCounterRef (\x -> (x+1,())) i <- readIORef uniqueCounterRef return $ mk n i ------------------------------------------------------------------------------- -- What is wire. data Wire clk ty where Wire :: Maybe String -> Int -> Wire clk ty Expr :: WireOp (op c ty) => op c ty -> Wire c ty instance Show (Wire c ty) where show w = error "No show for wires right now!" data HDL = VHDL | Verilog deriving (Prelude.Eq, Prelude.Ord, Show) class BitRepr (WireOpType op) => WireOp op where type WireOpType op -- |Transformation to HDL. opToHDL :: BitRepr (WireOpType op) => HDL -> op -> String -- |Flattening transformation. opFlatten :: op -> NLM clocks op opType :: op -> WireOpType op opType op = undefined opTypeSize :: op -> Int opTypeSize op = bitVectorSize (opType op) data SimpleOps c ty where OpConst :: (BitRepr ty, Show ty) => ty -> SimpleOps c ty OpSimpleBin :: (BitRepr res, BitRepr arg) => Wire c arg -> [(HDL,String)] -> Wire c arg -> SimpleOps c res OpSimpleUn :: (BitRepr res, BitRepr arg) => [(HDL,String)] -> Wire c arg -> SimpleOps c res instance BitRepr ty => WireOp (Wire c ty) where type WireOpType (Wire c ty) = ty opToHDL hdl wire = case wire of Wire _ _ -> signalName wire Expr e -> opToHDL hdl e opFlatten w@(Wire _ _) = return w opFlatten (Expr e) = liftM Expr $ opFlatten e toBits :: BitRepr ty => ty -> String toBits x | n > 1 = show bits | otherwise = show $ head bits where i = toBitVector x n = bitVectorSize x bits = reverse $ concatMap show $ take n $ map snd $ tail $ iterate ((`Prelude.divMod` 2) . fst) (i,0) instance BitRepr ty => WireOp (SimpleOps c ty) where type WireOpType (SimpleOps c ty) = ty opToHDL hdl (OpConst x) = toBits x opToHDL hdl (OpSimpleBin l ops r) = opToHDL hdl l++hdlOp++opToHDL hdl r where hdlOp = (" "++) $ (++" ") $ maybe (error $ "No op for hdl "++show hdl) Prelude.id $ Prelude.lookup hdl ops opFlatten o@(OpConst x) = return o opFlatten (OpSimpleBin l ops r) = do l <- assignFlattened l r <- assignFlattened r return $ OpSimpleBin l ops r instance (Show ty, BitRepr ty, IntegerConstant ty) => IntegerConstant (Wire c ty) where fromInteger i = Expr (OpConst (fromInteger i)) simpleBinAnyHDL a op b = OpSimpleBin a (Prelude.zip [VHDL, Verilog] (repeat op)) b instance (BitRepr ty, Arith ty, BitRepr (ArithResult ty)) => Arith (Wire c ty) where type ArithResult (Wire c ty) = Wire c (ArithResult ty) a + b = Expr $ simpleBinAnyHDL a "+" b a - b = Expr $ simpleBinAnyHDL a "-" b a * b = Expr $ simpleBinAnyHDL a "*" b instance Boolean (Wire c Bool) where not x = Expr $ OpSimpleUn [(VHDL, "not"), (Verilog, "!")] x a && b = Expr $ OpSimpleBin a [(VHDL, "and"),(Verilog, "&&")] b a || b = Expr $ OpSimpleBin a [(VHDL, "or"),(Verilog, "||")] b type family WList c ts type instance WList c Nil = Nil type instance WList c (t :. ts) = Wire c t :. WList c ts class WiresList a where type WireNamesList a mkWireList :: Maybe (WireNamesList a) -> NLM clocks a copyWireList :: Maybe (WireNamesList a) -> a -> NLM clocks a instance WiresList Nil where type WireNamesList Nil = Nil mkWireList _ = return Nil copyWireList _ _ = return Nil instance (BitRepr a, WiresList as) => WiresList (Wire c a :. as) where type WireNamesList (Wire c a :. as) = String :. WireNamesList as mkWireList names = do let (n,ns) = case names of Just (n :. ns) -> (Just n, Just ns) Nothing -> (Nothing, Nothing) a <- mkWire n as <- mkWireList ns return (a :. as) copyWireList names ~(w :. ws) = do let (n,ns) = case names of Just (n :. ns) -> (Just n, Just ns) Nothing -> (Nothing, Nothing) w <- assignWithForcedCopy n w ws <- copyWireList ns ws return (w :. ws) class RegisterWiresList a clocks where type RegisterDefault a registerWiresList :: RegisterDefault a -> a -> NLM clocks a instance RegisterWiresList Nil clocks where type RegisterDefault Nil = Nil registerWiresList _ _ = return Nil instance (Show a, BitRepr a, ClockAllowed c clocks, RegisterWiresList as clocks) => RegisterWiresList (Wire c a :. as) clocks where type RegisterDefault (Wire c a :. as) = a :. RegisterDefault as registerWiresList ~(a :. as) ~(w :. ws) = do w' <- register a w ws' <- registerWiresList as ws return $ w' :. ws' data SignalKind = BitSignal | BusSignal Int deriving Show class HDLSignal a where signalNameKind :: a -> (String, SignalKind) signalName :: HDLSignal a => a -> String signalName = fst . signalNameKind signalKind :: HDLSignal a => a -> SignalKind signalKind = snd . signalNameKind wireBusSize :: BitRepr a => Wire c a -> Int wireBusSize wire = bitVectorSize (wireType wire) where wireType :: BitRepr a => Wire c a -> a wireType _ = undefined wireOpBusSize :: (BitRepr (WireOpType op), WireOp op) => op -> Int wireOpBusSize op = bitVectorSize (projectType op) where projectType :: WireOp op => op -> WireOpType op projectType = undefined instance BitRepr a => HDLSignal (Wire c a) where signalNameKind wire = (name,kind) where kind = if width == 1 then BitSignal else BusSignal width width = wireBusSize wire name = case wire of Wire Nothing i -> "generated_temporary_name_"++show i Wire (Just n) i -> concat [n,"_",show i] class HDLSignals a where signalsWires :: a -> [(String,SignalKind)] instance HDLSignals Nil where signalsWires Nil = [] instance (HDLSignal a, HDLSignals as) => HDLSignals (a :. as) where signalsWires (w :. ws) = signalNameKind w : signalsWires ws class HDLOp op where opArgs :: WiresList as => op clk ty -> as opSize :: BitRepr ty => op clk ty -> Int class (Typeable c, Typeable (ClkReset c)) => Clock c where type ClkReset c -- |Provide construction of clock value to carry around. clockValue :: c -- |Reset sensitivity. clockResetPositive :: c -> Bool -- |Front sensitivity. clockFrontEdge :: c -> Bool changeDotsToUnderscores :: Typeable t => t -> String changeDotsToUnderscores = map (\c -> if c == '.' then '_' else c) . show . typeOf clockName :: Clock c => c -> String clockName c = changeDotsToUnderscores c clockResetName :: Clock c => c -> String clockResetName c = changeDotsToUnderscores $ clockReset c where clockReset :: Clock c => c -> ClkReset c clockReset _ = undefined class ClockList l where clockListValue :: l clockListClocks :: l -> [String] clockListResets :: l -> [String] instance ClockList Nil where clockListValue = Nil clockListClocks = const [] clockListResets = const [] instance (ClockList t, Clock h) => ClockList (h :. t) where clockListValue = clockValue :. clockListValue clockListClocks (c :. cs) = nub $ clockName c : clockListClocks cs clockListResets (c :. cs) = nub $ clockResetName c : clockListResets cs class (Clock c, ClockList cs) => ClockAllowed c cs instance (Clock c, Clock c1, ClockAllowed c cs) => ClockAllowed c (c1 :. cs) instance (Clock c, ClockList (c :. cs)) => ClockAllowed c (c :. cs) class (ClockList clockSubset, ClockList clockSet) => ClockSubset clockSubset clockSet instance ClockList clockSet => ClockSubset Nil clockSet instance (Clock c, ClockAllowed c clockSet, ClockSubset css clockSet, ClockList clockSet) => ClockSubset (c :. css) clockSet wireClock :: Clock c => Wire c a -> c wireClock w = clockValue -- |Basic netlist operations. data NetlistOp domain where -- Latching wires. First comes default Register :: (ClockAllowed c clocks, BitRepr a, Show a) => a -> Wire c a -> Wire c a -> NetlistOp clocks -- Assign dest what -- dest <= what; Assign :: BitRepr ty => Wire c ty -> Wire c ty -> NetlistOp clocks -- Instance ent -- entity ent port map (...); Instance :: (Instantiable entity, HDLSignals ins, HDLSignals outs , EntityIns entity ~ ins, EntityOuts entity ~ outs) => entity -> ins -> outs -> NetlistOp clocks -- |Netlist type. data Netlist clocks = Netlist { netlistOperations :: [NetlistOp clocks] } -- |State of netlist construction monad. data NLMS domain = NLMS { nlmsNetlist :: Netlist domain , nlmsCounter :: Int } emptyNLMS :: NLMS clocked emptyNLMS = NLMS (Netlist []) 0 type NLM clocked a = State (NLMS clocked) a mkWire :: BitRepr a => Maybe String -> NLM clocked (Wire c a) mkWire name = do n <- liftM nlmsCounter get modify $ \nlms -> nlms { nlmsCounter = n+1 } return $ Wire name n tempWire :: BitRepr a => NLM clocked (Wire c a) tempWire = mkWire Nothing constant :: (BitRepr a, Show a) => a -> Wire c a constant c = Expr $ OpConst c class (ClockList (EntityClocks entity) , HDLSignals (EntityIns entity) , HDLSignals (EntityOuts entity) , GenHDL entity) => Instantiable entity where type EntityClocks entity type EntityIns entity type EntityOuts entity getInputsOuputsClocks :: entity -> (EntityIns entity, EntityOuts entity, EntityClocks entity) data Comb ins outs where Comb :: (HDLSignals ins, HDLSignals outs) => String -> Int -> ins -> outs -> Netlist Nil -> Comb ins outs instance (HDLSignals ins , HDLSignals outs , GenHDL (Comb ins outs)) => Instantiable (Comb ins outs) where type EntityClocks (Comb ins outs) = Nil type EntityIns (Comb ins outs) = ins type EntityOuts (Comb ins outs) = outs getInputsOuputsClocks (Comb _ _ ins outs _) = (ins, outs, Nil) runNetlistCreation :: (WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs) => Maybe (WireNamesList ins, WireNamesList outs) -> (ins -> outs -> Netlist domain -> a) -> (ins -> NLM domain outs) -> a runNetlistCreation names q f = mk $ do ins <- mkWireList (fmap fst names) outs <- f ins outs <- copyWireList (fmap snd names) outs return (ins,outs) where mk act = (\((ins,outs),nlms) -> q ins outs (nlmsNetlist nlms)) $ runState act emptyNLMS -- |Create a combinational circut with named inputs and outputs from netlist description. mkCombNamed :: (HDLSignals ins, HDLSignals outs, WiresList ins, WiresList outs) => Maybe (WireNamesList ins, WireNamesList outs) -> String -> (ins -> NLM Nil outs) -> Comb ins outs mkCombNamed names n f = runNetlistCreation names (createUniqueIndex Comb n) f -- |Create a combinational circut anonymous inputs and outputs from netlist description. mkComb :: (HDLSignals ins, HDLSignals outs, WiresList ins, WiresList outs) => String -> (ins -> NLM Nil outs) -> Comb ins outs mkComb n f = mkCombNamed Nothing n f -- |Create a combinational circuit from pure function. -- You can easily shoot your foot here by creating cyclic expressions like -- 'f a = y where { x = a+y; y = x-a}. -- Use with care. mkCombPure :: (HDLSignals ins, HDLSignals outs, WiresList ins, WiresList outs) => String -> (ins -> outs) -> Comb ins outs mkCombPure n f = mkComb n (\ins -> return (f ins)) data Clocked clks ins outs where Clocked :: (HDLSignals ins, HDLSignals outs, ClockList clks) => clks -> String -> Int -> ins -> outs -> Netlist clks -> Clocked clks ins outs instance (ClockList clks , HDLSignals ins , HDLSignals outs , GenHDL (Clocked clks ins outs)) => Instantiable (Clocked clks ins outs) where type EntityClocks (Clocked clks ins outs) = clks type EntityIns (Clocked clks ins outs) = ins type EntityOuts (Clocked clks ins outs) = outs getInputsOuputsClocks (Clocked clks _ _ ins outs _) = (ins, outs, clks) mkClockedNamed :: (ClockList clks, WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs) => Maybe (WireNamesList ins, WireNamesList outs) -> String -> (ins -> NLM clks outs) -> Clocked clks ins outs mkClockedNamed names n f = runNetlistCreation names (createUniqueIndex (Clocked clockListValue) n) f mkClocked :: (ClockList clks, WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs) => String -> (ins -> NLM clks outs) -> Clocked clks ins outs mkClocked n f = mkClockedNamed Nothing n f data Mealy clk ins outs where Mealy :: (HDLSignals ins, HDLSignals outs, Clock clk) => clk -> String -> Int -> ins -> outs -> Netlist (clk :. Nil) -> Mealy clk ins outs instance (Clock clk , HDLSignals ins , HDLSignals outs , GenHDL (Mealy clk ins outs)) => Instantiable (Mealy clk ins outs) where type EntityClocks (Mealy clk ins outs) = clk :. Nil type EntityIns (Mealy clk ins outs) = ins type EntityOuts (Mealy clk ins outs) = outs getInputsOuputsClocks (Mealy clk _ _ ins outs _) = (ins, outs, clk :. Nil) mkMealyNamed :: (Clock clk, WiresList state, HDLSignals state, WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs, RegisterWiresList state (clk :. Nil)) => Maybe (WireNamesList ins, WireNamesList outs) -> RegisterDefault state -> String -> (state -> ins -> NLM (clk :. Nil) (state, outs)) -> Mealy clk ins outs mkMealyNamed names defs n f = runNetlistCreation names (createUniqueIndex (Mealy clockValue) n) action where action ins = do rec state <- registerWiresList defs nextState ~(nextState, outs) <- f state ins return outs mkMealy:: (Clock clk, WiresList state, HDLSignals state, WiresList ins, WiresList outs, HDLSignals ins, HDLSignals outs, RegisterWiresList state (clk :. Nil)) => RegisterDefault state -> String -> (state -> ins -> NLM (clk :. Nil) (state, outs)) -> Mealy clk ins outs mkMealy defs n f = mkMealyNamed Nothing defs n f ------------------------------------------------------------------------------- -- BitRepr instances. instance BitRepr Int where type BitVectorSize Int = $(tySize 32) toBitVector x = convertThroughInteger x fromBitVector x = convertThroughInteger x bitVectorSize x = 32 instance BitRepr Word8 where type BitVectorSize Word8 = $(tySize 8) toBitVector x = convertThroughInteger x fromBitVector x = convertThroughInteger x bitVectorSize x = 8 instance BitRepr Nil where type BitVectorSize Nil = $(tySize 0) toBitVector x = 0 fromBitVector x = Nil bitVectorSize x = 0 instance (BitRepr a, BitRepr as , Nat (Plus (BitVectorSize a) (BitVectorSize as))) => BitRepr (a :. as) where type BitVectorSize (a :. as) = Plus (BitVectorSize a) (BitVectorSize as) toBitVector (a :. as) = B.shiftL (toBitVector a) (bitVectorSize as) B..|. toBitVector as fromBitVector x = a :. as where mask :: BitRepr a => a -> Integer mask x = B.shiftL (1 :: Integer) (bitVectorSize x) - 1 ys = x B..&. mask as y = B.shiftR x (bitVectorSize as) B..&. mask a a = fromBitVector y as = fromBitVector ys bitVectorSize (a :. as) = bitVectorSize a + bitVectorSize as instance BitRepr () where type BitVectorSize () = $(tySize 0) toBitVector = const 0 fromBitVector = const () ------------------------------------------------------------------------------- -- Dumping HDL. data HDLGenState = HDLGenState { -- errors, if we encounter any. hdlgErrors :: [String] -- Mapping from entities to their "real" names. , hdlgGeneratedEntities :: Map.Map (String, Int) String -- how deep we recurred? , hdlgRecursionLevel :: Int -- lines of generated text. In reverse order. , hdlgTextLines :: [String] -- nesting level. , hdlgNestLevel :: Int -- what kind of language we generate. , hdlgLanguage :: HDL -- set of defined names. , hdlgDefinedNames :: Set.Set String } deriving (Prelude.Eq, Prelude.Ord, Show) type HDLGen a = State HDLGenState a emptyHDLGenState hdl = HDLGenState { hdlgErrors = [] , hdlgGeneratedEntities = Map.empty , hdlgRecursionLevel = 0 , hdlgTextLines = [] , hdlgNestLevel = 0 , hdlgLanguage = hdl , hdlgDefinedNames = Set.empty } runHDLGeneration :: GenHDL a => HDL -> a -> (String, [String]) runHDLGeneration hdl entity = (text, errors) where errors = hdlgErrors state text = unlines $ reverse $ hdlgTextLines state (_,state) = runState (generateHDL entity) (emptyHDLGenState hdl) generateLine :: String -> HDLGen () generateLine s = modify $ \hdlg -> hdlg { hdlgTextLines = (replicate (hdlgNestLevel hdlg) ' '++s) : hdlgTextLines hdlg } generateEmptyLines :: Int -> HDLGen () generateEmptyLines n = modify $ \hdlg -> hdlg { hdlgTextLines = (replicate n "") ++ hdlgTextLines hdlg } generateNest :: HDLGen a -> HDLGen a generateNest act = do nest <- liftM hdlgNestLevel get modify $ \hdlg -> hdlg { hdlgNestLevel = nest + 4 } x <- act modify $ \hdlg -> hdlg { hdlgNestLevel = nest } return x generateDashes :: HDLGen () generateDashes = modify $ \hdlg -> hdlg { hdlgTextLines = dashesLine (hdlgLanguage hdlg) (hdlgNestLevel hdlg) : hdlgTextLines hdlg } where dashesLine hdl n = concat [replicate n ' ',prefix hdl, replicate (79-n-2) '-'] prefix hdl = case hdl of VHDL -> "--" Verilog -> "//" generateError :: String -> HDLGen () generateError err = modify $ \hdlg -> hdlg { hdlgErrors = err : hdlgErrors hdlg} generateComment :: String -> HDLGen () generateComment c = do hdl <- liftM hdlgLanguage get let commentPrefix = case hdl of VHDL -> "--" Verilog -> "//" generateLine $ unwords [commentPrefix,c] generateDashesComment :: String -> HDLGen () generateDashesComment c = do generateDashes generateComment c generateDefineName :: String -> HDLGen () generateDefineName name = modify $ \hdlg -> hdlg { hdlgDefinedNames = Set.insert name $ hdlgDefinedNames hdlg } generateFilterDefined :: [a] -> (a -> String) -> HDLGen [a] generateFilterDefined things nameProjection = do defined <- liftM hdlgDefinedNames get let things' = filter (not . flip Set.member defined . nameProjection) things mapM (generateDefineName . nameProjection) things' return things' class GenHDL a where generateHDL :: a -> HDLGen () names :: HDLSignals s => s -> [String] names s = map fst $ signalsWires s entityPortsList dir signals = ( map fst wiresKinds ,map (\(name,kind) -> (name,unwords [name,":",dir,vhdlType kind])) wiresKinds) where wiresKinds = signalsWires signals vhdlType BitSignal = "bit" vhdlType (BusSignal width) = "unsigned ("++show (width-1)++" downto 0)" generateHDLForEntity :: (HDLSignals ins, HDLSignals outs, ClockList clocks) => String -> Int -> ins -> outs -> clocks -> Netlist domain -> HDLGen () generateHDLForEntity name index ins outs clocks netlist = do hdl <- liftM hdlgLanguage get n <- liftM (Map.lookup key . hdlgGeneratedEntities) get case n of Nothing -> do ourName <- registerOurEntity mapM_ subEntity $ netlistOperations netlist case hdl of VHDL -> vhdlText ourName Verilog -> verilogText ourName Just _ -> return () where key = (name, index) registerOurEntity = do names <- liftM (Set.fromList . Map.elems . hdlgGeneratedEntities) get let newNames = map (name++) $ map ('_':) $ map show [(1::Int)..] let ourName = head $ filter (not . (`Set.member` names)) newNames modify $ \hdlgs -> hdlgs { hdlgGeneratedEntities = Map.insert key ourName $ hdlgGeneratedEntities hdlgs } return ourName subEntity :: NetlistOp domain -> HDLGen () subEntity (Instance entity ins outs) = do generateHDL entity subEntity _ = return () generateEntityClocksResets clks = map addTypeDir $ clocks ++ resets where addTypeDir name = name ++ ": in std_logic" clocks = clockListClocks clks resets = clockListResets clks generateVHDLDeclarations ops' = do ops <- generateFilterDefined ops' fst forM ops $ \(name, kind) -> do let ty = case kind of BitSignal -> "bit" BusSignal n -> "unsigned ("++show (n-1)++" downto 0)" generateLine $ concat ["signal ", name, " : ", ty,";"] return () declareOperationSignals :: NetlistOp domain -> HDLGen () declareOperationSignals op = generateVHDLDeclarations $ case op of Register _ wa wb -> signalsWires $ wa :. Nil Assign wa op -> signalsWires $ wa :. Nil Instance entity ins outs -> signalsWires outs vhdlOperation :: NetlistOp domain -> HDLGen () vhdlOperation op = case op of Register def wa wb -> do let c = wireClock wa let cn = clockName c let edge = (if clockFrontEdge c then "rising_edge" else "falling_edge") ++"("++cn++")" let rn = clockResetName c let resetFunc = rn ++ " = " ++ (if clockResetPositive c then "'1'" else "'0'") generateLine $ "process ("++cn++", "++rn++") is" generateLine $ "begin" generateNest $ do generateLine $ unwords ["if",resetFunc, "then"] generateNest $ vhdlOperation (Assign wa (constant def)) generateLine $ unwords ["elsif",edge, "then"] generateNest $ vhdlOperation (Assign wa wb) generateLine "end if;" generateLine $ "end process;" Assign wa op -> do generateLine $ concat [signalName wa, " <= " ,opToHDL VHDL op, ";"] Instance entity ins outs -> do let (eins, eouts, eclks) = getInputsOuputsClocks entity let insNames = names ins let outsNames = names outs let einsNames = names eins let eoutsNames = names eouts let clocks = nub $ clockListClocks eclks let resets = nub $ clockListResets eclks let connect a b = a ++" => " ++ b let allNames = zipWith connect insNames einsNames ++ zipWith connect outsNames eoutsNames ++ map (\c -> connect c c) clocks ++ map (\c -> connect c c) resets let withCommas = zipWith (++) (" ":repeat ", ") allNames generateLine "entity (" generateNest $ mapM generateLine withCommas generateLine ");" vhdlText name = do generateEmptyLines 2 generateDashesComment $ "Entity declaration and architecture for "++name++"." generateEmptyLines 1 generateLine "library ieee;" generateLine "use ieee.std_logic_1164.all;" generateLine "use ieee.numeric_bit.all;" generateEmptyLines 1 generateLine $ "entity "++name++" is" generateNest $ do generateLine "port (" let (inputsNames,inputs) = entityPortsList "in" ins let (outputsNames, outputs) = entityPortsList "out" outs let clockResets = generateEntityClocksResets clocks let inouts = inputs ++ outputs let allSignals = (map snd inouts) ++ clockResets let signals = reverse $ zipWith (++) (reverse allSignals) ("" : repeat ";") mapM generateDefineName $ map fst inouts generateNest $ do mapM generateLine signals generateLine ");" return $ inputsNames ++ outputsNames generateLine $ "end entity "++name++";" generateEmptyLines 2 generateLine $ "architecture hhdl_generated of "++name++" is" generateNest $ do addSupportFunctions mapM declareOperationSignals $ netlistOperations netlist generateLine $ "begin" generateNest $ do mapM vhdlOperation $ netlistOperations netlist generateLine $ "end architecture hhdl_generated;" return () verilogText name = do generateLine $ "Verilog text for entity "++name addSupportFunctions = mapM generateLine [ replicate 60 '-' , "-- Supporting functions." , "" , "pure function select_func(s : in bit; t, f : in bit) return bit is" , "begin" , " if s = '1' then" , " return t;" , " else" , " return f;" , " end if;" , "end function select_func;" , "" , "pure function select_func(s : in bit; t, f : in unsigned) return unsigned is" , "begin" , " if s = '1' then" , " return t;" , " else" , " return f;" , " end if;" , "end function select_func;" , "" , "pure function bit_equality(a, b : in bit) return bit is" , "begin" , " if a = b then" , " return '1';" , " else" , " return '0';" , " end if;" , "end function bit_equality;" , "" , "pure function bit_equality(a, b : in unsigned) return bit is" , "begin" , " if a = b then" , " return '1';" , " else" , " return '0';" , " end if;" , "end function bit_equality;" , "" ] instance GenHDL (Comb ins outs) where generateHDL (Comb name index ins outs netlist) = do generateHDLForEntity name index ins outs Nil netlist instance GenHDL (Clocked cs ins outs) where generateHDL (Clocked clocks name index ins outs netlist) = do generateHDLForEntity name index ins outs clocks netlist instance GenHDL (Mealy c ins outs) where generateHDL (Mealy c name index ins outs netlist) = do generateHDLForEntity name index ins outs (c :. Nil) netlist writeHDLText :: GenHDL a => HDL -> a -> (String -> IO ()) -> IO () writeHDLText hdl entity write = do let (text, errors) = runHDLGeneration hdl entity write text case errors of [] -> return () errs -> do putStrLn $ "\n\n\nErrors:" mapM putStrLn errs putStrLn "------------------" putStrLn $ "Total " ++ show (length errs) ++ " errors in HDL generation." ------------------------------------------------------------------------------- -- Bit vectors. data BV size = BV Integer instance Nat size => BitRepr (BV size) where type BitVectorSize (BV size) = size toBitVector (BV i) = i fromBitVector i = r where r = BV (i B..&. bitMask r) instance Nat size => IntegerConstant (BV size) where fromInteger i = fromBitVector i instance Show (BV size) where showsPrec n (BV i) = (concat [o,Text.Printf.printf "BV 0x%x" i,c]++) where (o,c) | n > 10 = ("(",")") | otherwise = ("","") instance Nat size => Eq (BV size) where type EqResult (BV size) = Bool a == b = toBitVector a == toBitVector b a /= b = toBitVector a /= toBitVector b _toSelBusSizeBitVector :: AlgTypeBitEnc a => a -> BV (SelectorBusSize a) _toSelBusSizeBitVector = undefined _toSelBusSizeBitVectorWireExpr :: AlgTypeBitEnc a => Wire c a -> BV (SelectorBusSize a) _toSelBusSizeBitVectorWireExpr = undefined _toArgsBusSizeBitVector :: AlgTypeBitEnc a => Wire c a -> Wire c (BV (ArgsBusSize a)) _toArgsBusSizeBitVector = undefined ------------------------------------------------------------------------------- -- Netlist operations. addNetlistOperation op = modify $ \nlms -> nlms { nlmsNetlist = Netlist $ op : netlistOperations (nlmsNetlist nlms) } register :: (ClockAllowed c clocks, BitRepr a, Show a) => a -> Wire c a -> NLM clocks (Wire c a) register resetValue computedValue = do w <- tempWire modify $ \nlms -> nlms { nlmsNetlist = Netlist (Register resetValue w computedValue : netlistOperations (nlmsNetlist nlms)) } return w instantiate :: (Instantiable entity, ClockSubset (EntityClocks entity) clocks , WiresList (EntityIns entity), WiresList (EntityOuts entity)) => entity -> EntityIns entity -> NLM clocks (EntityOuts entity) instantiate entity ins = do outs <- mkWireList Nothing addNetlistOperation $ Instance entity ins outs return outs assignWire :: (BitRepr ty) => Wire c ty -> NLM registers (Wire c ty) assignWire what = do assignFlattened what assignWithForcedCopy n wire = do t <- mkWire n addNetlistOperation $ Assign t wire return t assignFlattened :: (BitRepr ty) => Wire c ty -> NLM registers (Wire c ty) assignFlattened w@(Wire _ _) = return w assignFlattened (Expr op) = do op <- opFlatten op assignWithForcedCopy Nothing $ Expr op extendZero :: (Nat src, Nat dest) => Wire c (BV src) -> Wire c (BV dest) extendZero what = Expr $ Extend False what extendSign :: (Nat src, Nat dest) => Wire c (BV src) -> Wire c (BV dest) extendSign what = Expr $ Extend True what castWires :: (BitRepr src, BitRepr res, BitVectorSize src ~ BitVectorSize res) => Wire c src -> Wire c res castWires what = Expr $ CastWires what _runPureNetlist :: NLM Nil a -> NLM clocks a _runPureNetlist action = do s <- get let (a,s') = runState action (copyNLMS s) put (copyNLMSBack s' s) return a where copyNLMS (NLMS (Netlist netlist) cntr) = NLMS (Netlist []) cntr copyNLMSBack :: NLMS Nil -> NLMS clocks -> NLMS clocks copyNLMSBack (NLMS (Netlist ops1) cntr) (NLMS (Netlist ops2) _) = NLMS (Netlist $ copyOps ops1 ops2) cntr copyOps :: [NetlistOp Nil] -> [NetlistOp clocks] -> [NetlistOp clocks] copyOps [] ops2 = ops2 copyOps (Assign to what : ops1) ops2 = copyOps ops1 (ops2++[Assign to what]) copyOps (Instance ent ins outs : ops1) ops2 = copyOps ops1 (ops2++[Instance ent ins outs]) ------------------------------------------------------------------------------- -- Operations for expressions. data Extend c dest where -- bool flag is whether we're using sign (we are when True). Extend :: (Nat src, Nat res) => Bool -> Wire c (BV src) -> Extend c (BV res) instance BitRepr res => WireOp (Extend c res) where type WireOpType (Extend c res) = res opToHDL hdl op@(Extend signExtendFlag arg) | widen = widenExpr | narrow = narrowExpr | otherwise = subExpr where destSize = wireOpBusSize op srcSize = wireOpBusSize arg widen = destSize > srcSize narrow = destSize > srcSize delta = destSize - srcSize sign = case hdl of VHDL -> subExpr ++"("++show (srcSize-1)++")" Verilog -> subExpr ++"["++show (srcSize-1)++"]" extension = case hdl of VHDL -> if signExtendFlag then concat $ intersperse " & " (replicate delta sign) else show (replicate delta '0') Verilog -> if signExtendFlag then concat $ intersperse ", " (replicate delta sign) else show (replicate delta '0') subExpr = opToHDL hdl arg widenExpr = case hdl of VHDL -> unwords [extension, subExpr] Verilog -> "{"++concat [extension, ", ", subExpr]++"}" narrowExpr = case hdl of VHDL -> subExpr ++"("++show (destSize-1)++" downto 0)" opFlatten (Extend se a) = liftM (Extend se) $ assignFlattened a data CastWires c res where -- bool flag is whether we're using sign (we are when True). CastWires :: (BitRepr src, BitRepr res, BitVectorSize src ~ BitVectorSize res) => Wire c src -> CastWires c res instance BitRepr res => WireOp (CastWires c res) where type WireOpType (CastWires c res) = res opToHDL hdl (CastWires op) = opToHDL hdl op opFlatten (CastWires op) = do op <- assignFlattened op return $ CastWires op class BitRepr (WireOpListTypes a) => WireOpList a where type WireOpListTypes a -- type WireOpListClock a opsToHDL :: HDL -> a -> [String] instance WireOpList Nil where type WireOpListTypes Nil = Nil opsToHDL hdl = const [] instance (WireOp x, WireOpList xs , Nat (Plus (BitVectorSize (WireOpType x)) (BitVectorSize (WireOpListTypes xs)))) => WireOpList (x :. xs) where type WireOpListTypes (x :. xs) = WireOpType x :. WireOpListTypes xs opsToHDL hdl (a :. as) = opToHDL hdl a : opsToHDL hdl as data SplitWiresOp c r where SplitWiresOp :: BitRepr s => Wire c s -> Int -> SplitWiresOp c r instance BitRepr r => WireOp (SplitWiresOp c r) where type WireOpType (SplitWiresOp c r) = r opToHDL hdl x@(SplitWiresOp wire ofs) = case hdl of VHDL | rSize > 1 -> unwords [subExpr, "(", show (rSize+ofs-1), "downto", show ofs, ")"] | otherwise -> unwords [subExpr, "(", show ofs,")"] Verilog -> error "Verilog SplitWiresOp!!!" where rSize = opTypeSize x subExpr = opToHDL hdl wire opFlatten (SplitWiresOp wire ofs) = liftM (\w -> SplitWiresOp w ofs) $ assignFlattened wire type family SplitProjection c w class BitRepr w => SplitWires w where splitWires :: Wire c w -> SplitProjection c w instance (BitRepr a, BitRepr b, Nat (Plus (BitVectorSize a) (BitVectorSize b)), Nat (BitVectorSize(a,b))) => BitRepr (a,b) where type BitVectorSize (a,b) = Plus (BitVectorSize a) (BitVectorSize b) toBitVector (x0,x1) = B.shiftL (toBitVector x0) (bitVectorSize x1) B..|. toBitVector x1 fromBitVector v = (x0,x1) where x1 = fromBitVector v x0 = fromBitVector (B.shiftR v (bitVectorSize x1)) type instance SplitProjection c (a,b) = (Wire c a, Wire c b) instance (BitRepr a, BitRepr b, BitRepr (a,b)) => SplitWires (a,b) where splitWires wab = (wa, wb) where wa = Expr $ SplitWiresOp wab (wireBusSize wb) wb = Expr $ SplitWiresOp wab 0 splitWires2 :: (BitRepr a, BitRepr b, BitRepr (a,b)) => Wire clk (a,b) -> (Wire clk a, Wire clk b) splitWires2 = splitWires $(liftM concat $ forM [3..8] $ \n -> let typeNames' = map (\i -> TH.mkName ("t_"++show i)) [1..n] typeNames = map TH.VarT typeNames' ty = foldl TH.AppT (TH.TupleT n) typeNames clkN = TH.mkName "clk" clk = TH.VarT clkN wireTy ty = TH.ConT (TH.mkName "Wire") `TH.AppT` clk `TH.AppT` ty wiresTy = foldl TH.AppT (TH.TupleT n) $ map wireTy typeNames bitReprP ty = TH.ClassP (TH.mkName "BitRepr") [ty] bitVectorSizeT ty = TH.ConT (TH.mkName "BitVectorSize") `TH.AppT` ty commonCxt = map bitReprP typeNames brCxt = TH.ClassP (TH.mkName "Nat") [bitVectorSizeT ty] : commonCxt swCxt = bitReprP ty : commonCxt argNames = map (\i -> TH.mkName ("x"++show i)) [1..n] shiftNames = map (\i -> TH.mkName ("s"++show i)) [1..n] argVars = map TH.VarE argNames prevArgs = Prelude.scanr (:) [] argVars sumWidths ws = foldr (\a b -> TH.InfixE (Just a) (TH.VarE $ TH.mkName "+") (Just b)) (TH.LitE $ TH.IntegerL 0) $ map (TH.AppE (TH.VarE (TH.mkName "wireBusSize"))) ws def v widths = flip (TH.ValD (TH.VarP v)) [] $ TH.NormalB $ TH.ConE (TH.mkName "Expr") `TH.AppE` (TH.ConE (TH.mkName "SplitWiresOp") `TH.AppE` vV `TH.AppE` sumWidths widths) defs = zipWith def argNames (tail prevArgs) vN = TH.mkName "v" vV = TH.VarE vN bitVecSizeTy = TH.TySynInstD (TH.mkName "BitVectorSize") [ty] $ foldl1 (\a b -> TH.ConT (TH.mkName "Plus") `TH.AppT` a `TH.AppT` b) $ map bitVectorSizeT typeNames defShift Nothing def arg = TH.ValD (TH.VarP def) (TH.NormalB $ TH.LitE $ TH.IntegerL 0) [] defShift (Just prev) def arg = TH.ValD (TH.VarP def) (TH.NormalB $ TH.InfixE (Just (TH.VarE prev)) (TH.VarE $ TH.mkName "+") (Just sz)) [] where sz = TH.VarE (TH.mkName "bitVectorSize") `TH.AppE` TH.VarE arg shiftDefs = Prelude.zipWith3 defShift (map Just (Prelude.init shiftNames) ++ [Nothing]) shiftNames argNames toBVE = Prelude.foldr1 (\x y -> TH.InfixE (Just x) (TH.VarE $ TH.mkName "Data.Bits..|.") (Just y)) $ zipWith (\x s -> TH.VarE (TH.mkName "Data.Bits.shiftL") `TH.AppE` (TH.VarE (TH.mkName "toBitVector") `TH.AppE` TH.VarE x) `TH.AppE` TH.VarE s) argNames shiftNames toBV = TH.FunD (TH.mkName "toBitVector") [TH.Clause [TH.TupP $ map TH.VarP argNames] (TH.NormalB toBVE) shiftDefs] fromBVEShiftDef x s pxs = [ TH.ValD (TH.VarP x) (TH.NormalB convertedX) [] , TH.ValD (TH.VarP s) (TH.NormalB shiftE) [] ] where vx = TH.VarE x convertedX = TH.VarE (TH.mkName "fromBitVector") `TH.AppE` shiftedV shiftedV = TH.VarE (TH.mkName "Data.Bits.shiftR") `TH.AppE` vV `TH.AppE` TH.VarE s shiftE = case pxs of Nothing -> TH.LitE $ TH.IntegerL 0 Just (x,s) -> TH.InfixE (Just $ TH.VarE (TH.mkName "bitVectorSize") `TH.AppE` TH.VarE x) (TH.VarE $ TH.mkName "+") (Just $ TH.VarE s) shiftArgs as = map Just (tail as) ++ [Nothing] fromBVEShiftDefs = concat $ zipWith3 fromBVEShiftDef argNames shiftNames (shiftArgs $ zip argNames shiftNames) fromBVE = TH.TupE $ map TH.VarE argNames fromBV = TH.FunD (TH.mkName "fromBitVector") [TH.Clause [TH.VarP vN] (TH.NormalB fromBVE) fromBVEShiftDefs] split = TH.FunD (TH.mkName "splitWires") [TH.Clause [TH.VarP vN] (TH.NormalB $ TH.TupE argVars) defs] specializedSplitN = TH.mkName $ "splitWires"++show n decls = [ TH.InstanceD swCxt (TH.ConT (TH.mkName "SplitWires") `TH.AppT` ty) [split] , TH.TySynInstD (TH.mkName "SplitProjection") [clk,ty] wiresTy , TH.InstanceD brCxt (TH.ConT (TH.mkName "BitRepr") `TH.AppT` ty) [bitVecSizeTy, toBV, fromBV] , TH.SigD specializedSplitN $ TH.ForallT (map TH.PlainTV $ clkN : typeNames') brCxt $ (TH.AppT (TH.AppT TH.ArrowT $ wireTy ty) wiresTy) , TH.FunD specializedSplitN [TH.Clause [] (TH.NormalB $ TH.VarE (TH.mkName "splitWires")) []] ] in do -- runIO $ mapM (putStrLn . show . ppr) decls return decls ) _castAlgTypeToPair :: (Nat (Plus (SelectorBusSize a) (ArgsBusSize a)), BitRepr a , Plus (SelectorBusSize a) (ArgsBusSize a) ~ BitVectorSize a, AlgTypeBitEnc a) => Wire c a -> Wire c (BV (SelectorBusSize a), BV (ArgsBusSize a)) _castAlgTypeToPair w = castWires w _splitAlgType :: (Plus (SelectorBusSize a) (ArgsBusSize a) ~ BitVectorSize a, Nat (Plus (SelectorBusSize a) (ArgsBusSize a)), AlgTypeBitEnc a, BitRepr a) => Wire c a -> (Wire c (BV (SelectorBusSize a)), Wire c (BV (ArgsBusSize a))) _splitAlgType w = splitWires $ _castAlgTypeToPair w _castArgsWires :: (Nat (ArgsBusSize a), AlgTypeBitEnc a, BitRepr a, BitRepr b) => Wire c a -> Wire c (BV (ArgsBusSize a)) -> Wire c b _castArgsWires a w = r where r = castWires (extendZero w) data Join c w where Join :: (BitRepr a, BitRepr b) => Wire c a -> Wire c b -> Join c (a :. b) instance BitRepr w => WireOp (Join c w) where type WireOpType (Join c w) = w opToHDL hdl (Join l r) = case hdl of VHDL -> unwords ["(",opToHDL hdl l,"&",opToHDL hdl r,")"] Verilog -> concat ["{",opToHDL hdl l,",",opToHDL hdl r,"}"] opFlatten (Join l r) = liftM2 Join (assignFlattened l) (assignFlattened r) infixr 5 & (&) :: (BitRepr a, BitRepr b, Nat (Plus (BitVectorSize a) (BitVectorSize b))) => Wire c a -> Wire c b -> Wire c (a :. b) a & b = Expr $ Join a b data Equality c w where -- first is the flag for equality testing, if true. Equality :: BitRepr w => Bool -> Wire c w -> Wire c w -> Equality c Bool instance BitRepr w => WireOp (Equality c w) where type WireOpType (Equality c w) = w opToHDL hdl (Equality eq l r) = case hdl of VHDL -> concat ["bit_equality( ", opToHDL hdl l,", ", opToHDL hdl r,")"] Verilog -> error "Equality Verilog!!!" where op = case hdl of VHDL -> if eq then "=" else "/=" Verilog -> if eq then "==" else "!=" opFlatten (Equality eq l r) = liftM2 (Equality eq) (assignFlattened l) (assignFlattened r) instance (Eq w, EqResult w ~ Bool, BitRepr w) => Eq (Wire c w) where type EqResult (Wire c w) = Wire c Bool a == b = Expr $ Equality True a b a /= b = Expr $ Equality False a b data Select c w where Select :: Wire c Bool -> Wire c a -> Wire c a -> Select c a instance BitRepr a => WireOp (Select c a) where type WireOpType (Select c a) = a opToHDL hdl (Select c l r) = case hdl of VHDL -> concat["select_func(",cv, ", ", lv,", ",rv,")"] Verilog -> error "Verilog Select!!!" where cv = opToHDL hdl c lv = opToHDL hdl l rv = opToHDL hdl r opFlatten (Select c l r) = do c <- assignFlattened c l <- assignFlattened l r <- assignFlattened r return $ Select c l r selectWires :: BitRepr a => Wire c Bool -> Wire c a -> Wire c a -> Wire c a selectWires sel true false = Expr $ Select sel true false ------------------------------------------------------------------------------- -- Pattern matching. -- We hardwire (pun intended) Wire(s) into Patterns because we can match -- only on bit vectors. And those bit vectors get transferred by Wire(s). type family ConcatPatList a b type instance ConcatPatList a b = ConcatWiresList (a :. b) --type instance ConcatPatList (x :. xs) ys = x :. (ConcatPatList xs ys) class (WiresList (ConcatWiresList a)) => WiresListConcat a where type ConcatWiresList a concatWiresList :: a -> ConcatWiresList a instance WiresListConcat Nil where type ConcatWiresList Nil = Nil concatWiresList Nil = Nil instance WiresList as => WiresListConcat (Nil :. as) where type ConcatWiresList (Nil :. as) = as concatWiresList (Nil :. as) = as instance (WiresListConcat (as :. bs), WiresList (a :. ConcatWiresList (as :. bs))) => WiresListConcat ((a :. as) :. bs) where type ConcatWiresList ((a :. as) :. bs) = a :. ConcatWiresList (as :. bs) concatWiresList ((a :. as) :. bs) = a :. concatWiresList (as :. bs) data PatMatch v r where PatMatch :: (Wire c v -> NLM Nil (Wire c Bool, Wire c result)) -> PatMatch (Wire c v) (Wire c result) data Pattern w o where Pattern :: {unPattern :: WiresList o => (Wire c w -> NLM Nil (o, Wire c Bool))} -> Pattern (Wire c w) o match :: (ClockAllowed c registers, BitRepr v, BitRepr r) => Wire c v -> [PatMatch (Wire c v) (Wire c r)] -> NLM registers (Wire c r) match v ms = do w <- assignWire v _runPureNetlist $ reduceMatches w ms where reduceMatches :: BitRepr r => Wire c v -> [PatMatch (Wire c v) (Wire c r)] -> NLM Nil (Wire c r) reduceMatches w [] = error "Empty list of pattern matches!" reduceMatches w [PatMatch pm] = do (_,r) <- pm w return r reduceMatches w pms = do pms' <- reduceMatchesByTwo pms reduceMatches w pms' reduceMatchesByTwo :: BitRepr r => [PatMatch (Wire c v) (Wire c r)] -> NLM Nil [PatMatch (Wire c v) (Wire c r)] reduceMatchesByTwo [] = return [] reduceMatchesByTwo [pm] = return [pm] reduceMatchesByTwo (PatMatch pm1:PatMatch pm2:pms) = do let pm = PatMatch $ \v -> do (f1,r1) <- pm1 v (f2,r2) <- pm2 v fw <- assignWire $ f1 || f2 sw <- assignWire $ selectWires f1 r1 r2 return (fw, sw) pms' <- reduceMatchesByTwo pms return $ pm : pms' infixl 8 --> (-->) :: WiresList wires => Pattern (Wire c t) wires -> (wires -> NLM Nil (Wire c result)) -> PatMatch (Wire c t) (Wire c result) (Pattern p) --> f = PatMatch $ \w -> do (ws,flag) <- p w r <- f ws return (flag, r) -- |Constant match. pcst :: (Eq a, EqResult a ~ Bool, Eq (Wire c a), Show a, BitRepr a) => a -> Pattern (Wire c a) Nil pcst c = Pattern $ \w -> return (Nil, w == constant c) pvar :: BitRepr a => Pattern (Wire c a) (Wire c a :. Nil) pvar = Pattern $ \w -> return (w :. Nil, constant True) pwild :: BitRepr a => Pattern (Wire c a) Nil pwild = Pattern $ \w -> return (Nil, constant True) -- Pattern matching for some Prelude types. $(reifyGenerateMakeMatch [''Maybe, ''Either, ''Bool])