HHDL-0.1.0.0: src/Hardware/HHDL/HHDL.hs
{-# 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])