{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
module Clash.Netlist.Util where
import Control.Error (hush)
import Control.Exception (throw)
import Control.Lens ((.=),(%=))
import qualified Control.Lens as Lens
import Control.Monad (zipWithM)
import Control.Monad.Trans.Except (runExcept)
import Data.Either (partitionEithers)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.List (intersperse, unzip4)
import Data.Maybe (catMaybes,fromMaybe)
import Data.Text.Lazy (append,pack,unpack)
import qualified Data.Text.Lazy as Text
import Unbound.Generics.LocallyNameless
(Embed, Fresh, embed, unbind, unembed, unrec)
import qualified Unbound.Generics.LocallyNameless as Unbound
import Clash.Annotations.TopEntity (PortName (..), TopEntity (..))
import Clash.Driver.Types
(ClashException (..), Manifest (..), SrcSpan)
import Clash.Core.DataCon (DataCon (..))
import Clash.Core.FreeVars (termFreeIds, typeFreeVars)
import Clash.Core.Name (Name (..), appendToName, name2String)
import Clash.Core.Pretty (showDoc)
import Clash.Core.Subst (substTms, substTys)
import Clash.Core.Term (LetBinding, Term (..), TmName, TmOccName)
import Clash.Core.TyCon
(TyCon (..), TyConName, TyConOccName, tyConDataCons)
import Clash.Core.Type (Type (..), TypeView (..), LitTy (..),
coreView, splitTyConAppM, tyView)
import Clash.Core.Util (collectBndrs, termType, tyNatSize)
import Clash.Core.Var (Id, Var (..), modifyVarName)
import Clash.Netlist.Id (IdType (..), stripDollarPrefixes)
import Clash.Netlist.Types as HW
import Clash.Signal.Internal (ClockKind (..))
import Clash.Util
isVoid :: HWType -> Bool
isVoid (Void {}) = True
isVoid _ = False
mkIdentifier :: IdType -> Identifier -> NetlistMonad Identifier
mkIdentifier typ nm = Lens.use mkIdentifierFn <*> pure typ <*> pure nm
extendIdentifier
:: IdType
-> Identifier
-> Identifier
-> NetlistMonad Identifier
extendIdentifier typ nm ext =
Lens.use extendIdentifierFn <*> pure typ <*> pure nm <*> pure ext
splitNormalized :: Fresh m
=> HashMap TyConOccName TyCon
-> Term
-> m (Either String ([Id],[LetBinding],Id))
splitNormalized tcm expr = do
(args,letExpr) <- fmap (first partitionEithers) $ collectBndrs expr
case letExpr of
Letrec b
| (tmArgs,[]) <- args -> do
(xes,e) <- unbind b
case e of
Var t v -> return $! Right (tmArgs,unrec xes,Id v (embed t))
_ -> return $! Left ($(curLoc) ++ "Not in normal form: res not simple var")
| otherwise -> return $! Left ($(curLoc) ++ "Not in normal form: tyArgs")
_ -> do
ty <- termType tcm expr
return $! Left ($(curLoc) ++ "Not in normal form: no Letrec:\n\n" ++ showDoc expr ++ "\n\nWhich has type:\n\n" ++ showDoc ty)
unsafeCoreTypeToHWType
:: SrcSpan
-> String
-> (HashMap TyConOccName TyCon -> Bool -> Type -> Maybe (Either String HWType))
-> HashMap TyConOccName TyCon
-> Bool
-> Type
-> HWType
unsafeCoreTypeToHWType sp loc builtInTranslation m keepVoid =
either (\msg -> throw (ClashException sp (loc ++ msg) Nothing)) id .
coreTypeToHWType builtInTranslation m keepVoid
unsafeCoreTypeToHWTypeM
:: String
-> Type
-> NetlistMonad HWType
unsafeCoreTypeToHWTypeM loc ty =
unsafeCoreTypeToHWType
<$> (snd <$> Lens.use curCompNm)
<*> pure loc
<*> Lens.use typeTranslator
<*> Lens.use tcCache
<*> pure False
<*> pure ty
coreTypeToHWTypeM
:: Type
-> NetlistMonad (Maybe HWType)
coreTypeToHWTypeM ty = hush <$> (coreTypeToHWType <$> Lens.use typeTranslator <*> Lens.use tcCache <*> pure False <*> pure ty)
synchronizedClk :: HashMap TyConOccName TyCon
-> Type
-> Maybe (Identifier,Integer)
synchronizedClk tcm ty
| not . null . Lens.toListOf typeFreeVars $ ty = Nothing
| Just (tyCon,args) <- splitTyConAppM ty
= case name2String tyCon of
"Clash.Sized.Vector.Vec" -> synchronizedClk tcm (args!!1)
"Clash.Signal.Internal.SClock" -> case splitTyConAppM (head args) of
Just (_,[LitTy (SymTy s),litTy])
| Right i <- runExcept (tyNatSize tcm litTy) -> Just (pack s,i)
_ -> error $ $(curLoc) ++ "Clock period not a simple literal: " ++ showDoc ty
"Clash.Signal.Internal.Signal" -> case splitTyConAppM (head args) of
Just (_,[LitTy (SymTy s),litTy])
| Right i <- runExcept (tyNatSize tcm litTy) -> Just (pack s,i)
_ -> error $ $(curLoc) ++ "Clock period not a simple literal: " ++ showDoc ty
_ -> case tyConDataCons (tcm HashMap.! nameOcc tyCon) of
[dc] -> let argTys = dcArgTys dc
argTVs = map nameOcc (dcUnivTyVars dc)
argSubts = zip argTVs args
args' = map (substTys argSubts) argTys
in case args' of
(arg:_) -> synchronizedClk tcm arg
_ -> Nothing
_ -> Nothing
| otherwise
= Nothing
coreTypeToHWType
:: (HashMap TyConOccName TyCon -> Bool -> Type -> Maybe (Either String HWType))
-> HashMap TyConOccName TyCon
-> Bool
-> Type
-> Either String HWType
coreTypeToHWType builtInTranslation m keepVoid (builtInTranslation m keepVoid -> Just hty) =
hty
coreTypeToHWType builtInTranslation m keepVoid (coreView m -> Just ty) =
coreTypeToHWType builtInTranslation m keepVoid ty
coreTypeToHWType builtInTranslation m keepVoid ty@(tyView -> TyConApp tc args) =
mkADT builtInTranslation m (showDoc ty) keepVoid tc args
coreTypeToHWType _ _ _ ty = Left $ "Can't translate non-tycon type: " ++ showDoc ty
mkADT
:: (HashMap TyConOccName TyCon -> Bool -> Type -> Maybe (Either String HWType))
-> HashMap TyConOccName TyCon
-> String
-> Bool
-> TyConName
-> [Type]
-> Either String HWType
mkADT _ m tyString _ tc _
| isRecursiveTy m tc
= Left $ $(curLoc) ++ "Can't translate recursive type: " ++ tyString
mkADT builtInTranslation m _tyString keepVoid tc args = case tyConDataCons (m HashMap.! nameOcc tc) of
[] -> return (Void Nothing)
dcs -> do
let tcName = pack $ name2String tc
argTyss = map dcArgTys dcs
argTVss = map dcUnivTyVars dcs
argSubts = map ((`zip` args) . map nameOcc) argTVss
substArgTyss = zipWith (\s tys -> map (substTys s) tys) argSubts argTyss
argHTyss <- mapM (mapM (coreTypeToHWType builtInTranslation m keepVoid)) substArgTyss
let argHTyss' = if keepVoid
then argHTyss
else map (filter (not . isVoid)) argHTyss
case (dcs,argHTyss') of
(_:[],[[elemTy]]) -> return elemTy
(_:[],[elemTys@(_:_)]) -> return $ Product tcName elemTys
(_ ,concat -> [])
| length dcs < 2 -> return (Void Nothing)
| otherwise -> return $ Sum tcName $ map (pack . name2String . dcName) dcs
(_ ,elemHTys) -> return $ SP tcName
$ zipWith (\dc tys ->
( pack . name2String $ dcName dc
, tys
)
) dcs elemHTys
isRecursiveTy :: HashMap TyConOccName TyCon -> TyConName -> Bool
isRecursiveTy m tc = case tyConDataCons (m HashMap.! nameOcc tc) of
[] -> False
dcs -> let argTyss = map dcArgTys dcs
argTycons = (map fst . catMaybes) $ (concatMap . map) splitTyConAppM argTyss
in tc `elem` argTycons
representableType
:: (HashMap TyConOccName TyCon -> Bool -> Type -> Maybe (Either String HWType))
-> Bool
-> Bool
-> HashMap TyConOccName TyCon
-> Type
-> Bool
representableType builtInTranslation _allowZero stringRepresentable m =
either (const False) isRepresentable . coreTypeToHWType builtInTranslation m False
where
isRepresentable hty = case hty of
String -> stringRepresentable
Vector _ elTy -> isRepresentable elTy
RTree _ elTy -> isRepresentable elTy
Product _ elTys -> all isRepresentable elTys
SP _ elTyss -> all (all isRepresentable . snd) elTyss
_ -> True
typeSize :: HWType
-> Int
typeSize (Void {}) = 0
typeSize String = 1
typeSize Bool = 1
typeSize Bit = 1
typeSize (Clock {}) = 1
typeSize (Reset {}) = 1
typeSize (BitVector i) = i
typeSize (Index 0) = 0
typeSize (Index 1) = 1
typeSize (Index u) = fromMaybe 0 (clogBase 2 u)
typeSize (Signed i) = i
typeSize (Unsigned i) = i
typeSize (Vector n el) = n * typeSize el
typeSize (RTree d el) = (2^d) * typeSize el
typeSize t@(SP _ cons) = conSize t +
maximum (map (sum . map typeSize . snd) cons)
typeSize (Sum _ dcs) = fromMaybe 0 . clogBase 2 . toInteger $ length dcs
typeSize (Product _ tys) = sum $ map typeSize tys
conSize :: HWType
-> Int
conSize (SP _ cons) = fromMaybe 0 . clogBase 2 . toInteger $ length cons
conSize t = typeSize t
typeLength :: HWType
-> Int
typeLength (Vector n _) = n
typeLength _ = 0
termHWType :: String
-> Term
-> NetlistMonad HWType
termHWType loc e = do
m <- Lens.use tcCache
ty <- termType m e
unsafeCoreTypeToHWTypeM loc ty
termHWTypeM :: Term
-> NetlistMonad (Maybe HWType)
termHWTypeM e = do
m <- Lens.use tcCache
ty <- termType m e
coreTypeToHWTypeM ty
mkUniqueNormalized
:: Maybe (Maybe TopEntity)
-> ([Id],[LetBinding],Id)
-> NetlistMonad
([(Identifier,HWType)]
,[Declaration]
,[(Identifier,HWType)]
,[Declaration]
,[LetBinding]
,TmName)
mkUniqueNormalized topMM (args,binds,res) = do
(iports,iwrappers,substArgs) <- mkUniqueArguments topMM args
(oports,owrappers,res1,substRes) <- mkUniqueResult topMM res
let subst' = substRes:substArgs
bndrs = map fst binds
exprs = map (unembed . snd) binds
usesOutput = concatMap (filter ( == (nameOcc . varName) res)
. Lens.toListOf termFreeIds
) exprs
(res2,subst'',extraBndr) <- case usesOutput of
[] -> return (varName res1
,(nameOcc $ varName res, Var (unembed $ varType res1) (varName res1)):subst'
,[] :: [(Id, Embed Term)])
_ -> do
([res3],_) <- mkUnique [] [modifyVarName (`appendToName` "_rec") res]
return (varName res3,(nameOcc $ varName res,Var (unembed $ varType res3) (varName res3)):subst'
,[(res1,embed $ Var (unembed $ varType res) (varName res3))])
let resN = varName res
bndrs' = map (\i -> if varName i == resN then modifyVarName (const res2) i else i) bndrs
(bndrsL,r:bndrsR) = break ((== res2).varName) bndrs'
(bndrsL',substL) <- mkUnique subst'' bndrsL
(bndrsR',substR) <- mkUnique substL bndrsR
let exprs' = map (embed . substTms substR) exprs
return (iports,iwrappers,oports,owrappers,zip (bndrsL' ++ r:bndrsR') exprs' ++ extraBndr,varName res1)
mkUniqueArguments
:: Maybe (Maybe TopEntity)
-> [Id]
-> NetlistMonad
([(Identifier,HWType)]
,[Declaration]
,[(TmOccName,Term)]
)
mkUniqueArguments Nothing args = do
(args',subst) <- mkUnique [] args
ports <- mapM idToPort args'
return (ports,[],subst)
mkUniqueArguments (Just teM) args = do
let iPortSupply = maybe (repeat Nothing) (extendPorts . t_inputs) teM
(ports,decls,subst) <- unzip3 . catMaybes <$> zipWithM go iPortSupply args
let ports' = concat ports
return (ports', concat decls, subst)
where
go pM var = do
tcm <- Lens.use tcCache
typeTrans <- Lens.use typeTranslator
(_,sp) <- Lens.use curCompNm
let i = varName var
i' = pack (name2String i)
ty = unembed (varType var)
hwty = unsafeCoreTypeToHWType sp $(curLoc) typeTrans tcm True ty
(ports,decls,_,pN) <- mkInput pM (i',hwty)
if isVoid hwty
then return Nothing
else return (Just (ports,decls,(nameOcc i, Var ty (repName (unpack pN) i))))
mkUniqueResult
:: Maybe (Maybe TopEntity)
-> Id
-> NetlistMonad ([(Identifier,HWType)],[Declaration],Id,(TmOccName,Term))
mkUniqueResult Nothing res = do
([res'],[subst]) <- mkUnique [] [res]
port <- idToPort res'
return ([port],[],res',subst)
mkUniqueResult (Just teM) res = do
tcm <- Lens.use tcCache
typeTrans <- Lens.use typeTranslator
(_,sp) <- Lens.use curCompNm
let o = varName res
o' = pack (name2String o)
ty = unembed (varType res)
hwty = unsafeCoreTypeToHWType sp $(curLoc) typeTrans tcm True ty
oPortSupply = fmap t_output teM
(ports,decls,pN) <- mkOutput oPortSupply (o',hwty)
let pO = repName (unpack pN) o
return (ports,decls,Id pO (embed ty),(nameOcc o,Var ty pO))
idToPort :: Id -> NetlistMonad (Identifier,HWType)
idToPort var = do
tcm <- Lens.use tcCache
typeTrans <- Lens.use typeTranslator
(_,sp) <- Lens.use curCompNm
let i = varName var
ty = unembed (varType var)
return
( pack $ name2String i
, unsafeCoreTypeToHWType sp $(curLoc) typeTrans tcm False ty
)
repName :: String -> Name a -> Name a
repName s (Name sort _ loc) = Name sort (Unbound.string2Name s) loc
mkUnique
:: [(TmOccName,Term)]
-> [Id]
-> NetlistMonad ([Id],[(TmOccName,Term)])
mkUnique = go []
where
go :: [Id] -> [(TmOccName,Term)] -> [Id] -> NetlistMonad ([Id],[(TmOccName,Term)])
go processed subst [] = return (reverse processed,subst)
go processed subst (i:is) = do
iN <- mkUniqueIdentifier Extended . pack . name2String $ varName i
let iN_unpacked = unpack iN
i' = modifyVarName (repName iN_unpacked) i
go (i':processed)
((nameOcc . varName $ i,Var (unembed $ varType i') (varName i')):subst)
is
mkUniqueIdentifier
:: IdType
-> Identifier
-> NetlistMonad Identifier
mkUniqueIdentifier typ nm = do
seen <- Lens.use seenIds
seenC <- Lens.use seenComps
i <- mkIdentifier typ nm
let s = seenC ++ seen
if i `elem` s
then go 0 s i
else do
seenIds %= (i:)
return i
where
go :: Integer -> [Identifier] -> Identifier -> NetlistMonad Identifier
go n s i = do
i' <- extendIdentifier typ i (pack ('_':show n))
if i' `elem` s
then go (n+1) s i
else do
seenIds %= (i':)
return i'
preserveVarEnv :: NetlistMonad a
-> NetlistMonad a
preserveVarEnv action = do
vCnt <- Lens.use varCount
vComp <- Lens.use curCompNm
vSeen <- Lens.use seenIds
val <- action
varCount .= vCnt
curCompNm .= vComp
seenIds .= vSeen
return val
dcToLiteral :: HWType -> Int -> Literal
dcToLiteral Bool 1 = BoolLit False
dcToLiteral Bool 2 = BoolLit True
dcToLiteral _ i = NumLit (toInteger i-1)
extendPorts :: [PortName] -> [Maybe PortName]
extendPorts ps = map Just ps ++ repeat Nothing
appendNumber
:: (Identifier,HWType)
-> Int
-> (Identifier,HWType)
appendNumber (nm,hwty) i =
(nm `append` "_" `append` pack (show i),hwty)
portName
:: String
-> Identifier
-> Identifier
portName [] i = i
portName x _ = pack x
appendIdentifier
:: (Identifier,HWType)
-> Int
-> NetlistMonad (Identifier,HWType)
appendIdentifier (nm,hwty) i =
(,hwty) <$> extendIdentifier Extended nm (pack ('_':show i))
uniquePortName
:: String
-> Identifier
-> NetlistMonad Identifier
uniquePortName [] i = mkUniqueIdentifier Extended i
uniquePortName x _ = do
let x' = pack x
seenIds %= (x':)
return x'
mkInput
:: Maybe PortName
-> (Identifier,HWType)
-> NetlistMonad ([(Identifier,HWType)],[Declaration],Expr,Identifier)
mkInput pM = case pM of
Nothing -> go
Just p -> go' p
where
go (i,hwty) = do
i' <- mkUniqueIdentifier Extended i
case hwty of
Vector sz hwty' -> do
arguments <- mapM (appendIdentifier (i',hwty')) [0..sz-1]
(ports,_,exprs,_) <- unzip4 <$> mapM (mkInput Nothing) arguments
let hwty2 = filterVoid hwty'
netdecl = NetDecl Nothing i' (Vector sz hwty2)
vecExpr = mkVectorChain sz hwty2 exprs
netassgn = Assignment i' vecExpr
return (concat ports,[netdecl,netassgn],vecExpr,i')
RTree d hwty' -> do
arguments <- mapM (appendIdentifier (i',hwty')) [0..2^d-1]
(ports,_,exprs,_) <- unzip4 <$> mapM (mkInput Nothing) arguments
let hwty2 = filterVoid hwty'
netdecl = NetDecl Nothing i' (RTree d hwty2)
trExpr = mkRTreeChain d hwty2 exprs
netassgn = Assignment i' trExpr
return (concat ports,[netdecl,netassgn],trExpr,i')
Product _ hwtys -> do
arguments <- zipWithM appendIdentifier (map (i',) hwtys) [0..]
let argumentsBundled = zip hwtys arguments
argumentsFiltered = filter (not . isVoid . fst) argumentsBundled
argumentsFiltered' = map snd argumentsFiltered
(ports,_,exprs,_) <- unzip4 <$> mapM (mkInput Nothing) argumentsFiltered'
case exprs of
[expr] ->
let hwty' = filterVoid hwty
netdecl = NetDecl Nothing i' hwty'
dcExpr = expr
netassgn = Assignment i' expr
in return (concat ports,[netdecl,netassgn],dcExpr,i')
_ ->
let hwty' = filterVoid hwty
netdecl = NetDecl Nothing i' hwty'
dcExpr = DataCon hwty' (DC (hwty',0)) exprs
netassgn = Assignment i' dcExpr
in return (concat ports,[netdecl,netassgn],dcExpr,i')
Clock nm rt Gated -> do
let hwtys = [Clock nm rt Source,Bool]
arguments <- zipWithM appendIdentifier (map (i',) hwtys) [0..]
(ports,_,exprs,_) <- unzip4 <$> mapM (mkInput Nothing) arguments
let netdecl = NetDecl Nothing i' hwty
dcExpr = DataCon hwty (DC (hwty,0)) exprs
netassgn = Assignment i' dcExpr
return (concat ports,[netdecl,netassgn],dcExpr,i')
_ -> return ([(i',hwty)],[],Identifier i' Nothing,i')
go' (PortName p) (i,hwty) = do
pN <- uniquePortName p i
return ([(pN,hwty)],[],Identifier pN Nothing,pN)
go' (PortProduct p ps) (i,hwty) = do
pN <- uniquePortName p i
case hwty of
Vector sz hwty' -> do
arguments <- mapM (appendIdentifier (pN,hwty')) [0..sz-1]
(ports,_,exprs,_) <- unzip4 <$> zipWithM mkInput (extendPorts ps) arguments
let hwty2 = filterVoid hwty'
netdecl = NetDecl Nothing pN (Vector sz hwty2)
vecExpr = mkVectorChain sz hwty2 exprs
netassgn = Assignment pN vecExpr
return (concat ports,[netdecl,netassgn],vecExpr,pN)
RTree d hwty' -> do
arguments <- mapM (appendIdentifier (pN,hwty')) [0..2^d-1]
(ports,_,exprs,_) <- unzip4 <$> zipWithM mkInput (extendPorts ps) arguments
let hwty2 = filterVoid hwty'
netdecl = NetDecl Nothing pN (RTree d hwty2)
trExpr = mkRTreeChain d hwty2 exprs
netassgn = Assignment pN trExpr
return (concat ports,[netdecl,netassgn],trExpr,pN)
Product _ hwtys -> do
arguments <- zipWithM appendIdentifier (map (pN,) hwtys) [0..]
let argumentsBundled = zip hwtys (zip (extendPorts ps) arguments)
argumentsFiltered = filter (not . isVoid . fst) argumentsBundled
argumentsFiltered' = unzip (map snd argumentsFiltered)
(ports,_,exprs,_) <- unzip4 <$> uncurry (zipWithM mkInput) argumentsFiltered'
case exprs of
[expr] ->
let hwty' = filterVoid hwty
netdecl = NetDecl Nothing pN hwty'
dcExpr = expr
netassgn = Assignment pN expr
in return (concat ports,[netdecl,netassgn],dcExpr,pN)
_ -> let hwty' = filterVoid hwty
netdecl = NetDecl Nothing pN hwty'
dcExpr = DataCon hwty' (DC (hwty',0)) exprs
netassgn = Assignment pN dcExpr
in return (concat ports,[netdecl,netassgn],dcExpr,pN)
Clock nm rt Gated -> do
let hwtys = [Clock nm rt Source, Bool]
arguments <- zipWithM appendIdentifier (map (pN,) hwtys) [0..]
(ports,_,exprs,_) <- unzip4 <$> zipWithM mkInput (extendPorts ps) arguments
let netdecl = NetDecl Nothing pN hwty
dcExpr = DataCon hwty (DC (hwty,0)) exprs
netassgn = Assignment pN dcExpr
return (concat ports,[netdecl,netassgn],dcExpr,pN)
_ -> return ([(pN,hwty)],[],Identifier pN Nothing,pN)
filterVoid
:: HWType
-> HWType
filterVoid t = case t of
Product nm hwtys
| null hwtys' -> Void Nothing
| length hwtys' == 1 -> head hwtys'
| otherwise -> Product nm hwtys'
where
hwtys' = filter (not . isVoid) (map filterVoid hwtys)
_ -> t
mkVectorChain :: Int
-> HWType
-> [Expr]
-> Expr
mkVectorChain _ elTy [] = DataCon (Vector 0 elTy) VecAppend []
mkVectorChain _ elTy [e] = DataCon (Vector 1 elTy) VecAppend
[e]
mkVectorChain sz elTy (e:es) = DataCon (Vector sz elTy) VecAppend
[ e
, mkVectorChain (sz-1) elTy es
]
mkRTreeChain :: Int
-> HWType
-> [Expr]
-> Expr
mkRTreeChain _ elTy [e] = DataCon (RTree 0 elTy) RTreeAppend
[e]
mkRTreeChain d elTy es =
let (esL,esR) = splitAt (length es `div` 2) es
in DataCon (RTree d elTy) RTreeAppend
[ mkRTreeChain (d-1) elTy esL
, mkRTreeChain (d-1) elTy esR
]
genComponentName :: [Identifier] -> (IdType -> Identifier -> Identifier) -> TmName -> Identifier
genComponentName seen mkId nm =
let nm' = Text.splitOn (Text.pack ".") (Text.pack (name2String nm))
fn = mkId Basic (stripDollarPrefixes (last nm'))
fn' = if Text.null fn then Text.pack "Component" else fn
nm2 = Text.concat (intersperse (Text.pack "_") (init nm' ++ [fn']))
nm3 = mkId Basic nm2
in if nm3 `elem` seen then go 0 nm3 else nm3
where
go :: Integer -> Identifier -> Identifier
go n i =
let i' = mkId Basic (i `Text.append` Text.pack ('_':show n))
in if i' `elem` seen
then go (n+1) i
else i'
mkOutput
:: Maybe PortName
-> (Identifier,HWType)
-> NetlistMonad ([(Identifier,HWType)],[Declaration],Identifier)
mkOutput pM = case pM of
Nothing -> go
Just p -> go' p
where
go (o,hwty) = do
o' <- mkUniqueIdentifier Extended o
case hwty of
Vector sz hwty' -> do
results <- mapM (appendIdentifier (o',hwty')) [0..sz-1]
(ports,decls,ids) <- unzip3 <$> mapM (mkOutput Nothing) results
let hwty2 = Vector sz (filterVoid hwty')
netdecl = NetDecl Nothing o' hwty2
assigns = zipWith (assignId o' hwty2 10) ids [0..]
return (concat ports,netdecl:assigns ++ concat decls,o')
RTree d hwty' -> do
results <- mapM (appendIdentifier (o',hwty')) [0..2^d-1]
(ports,decls,ids) <- unzip3 <$> mapM (mkOutput Nothing) results
let hwty2 = RTree d (filterVoid hwty')
netdecl = NetDecl Nothing o' hwty2
assigns = zipWith (assignId o' hwty2 10) ids [0..]
return (concat ports,netdecl:assigns ++ concat decls,o')
Product _ hwtys -> do
results <- zipWithM appendIdentifier (map (o,) hwtys) [0..]
let resultsBundled = zip hwtys results
resultsFiltered = filter (not . isVoid . fst) resultsBundled
resultsFiltered' = map snd resultsFiltered
(ports,decls,ids) <- unzip3 <$> mapM (mkOutput Nothing) resultsFiltered'
case ids of
[i] ->
let hwty' = filterVoid hwty
netdecl = NetDecl Nothing o' hwty'
assign = Assignment i (Identifier o' Nothing)
in return (concat ports,netdecl:assign:concat decls,o')
_ ->
let hwty' = filterVoid hwty
netdecl = NetDecl Nothing o' hwty'
assigns = zipWith (assignId o' hwty' 0) ids [0..]
in return (concat ports,netdecl:assigns ++ concat decls,o')
_ -> return ([(o',hwty)],[],o')
go' (PortName p) (o,hwty) = do
pN <- uniquePortName p o
return ([(pN,hwty)],[],pN)
go' (PortProduct p ps) (o,hwty) = do
pN <- uniquePortName p o
case hwty of
Vector sz hwty' -> do
results <- mapM (appendIdentifier (pN,hwty')) [0..sz-1]
(ports,decls,ids) <- unzip3 <$> zipWithM mkOutput (extendPorts ps) results
let hwty2 = Vector sz (filterVoid hwty')
netdecl = NetDecl Nothing pN hwty2
assigns = zipWith (assignId pN hwty2 10) ids [0..]
return (concat ports,netdecl:assigns ++ concat decls,pN)
RTree d hwty' -> do
results <- mapM (appendIdentifier (pN,hwty')) [0..2^d-1]
(ports,decls,ids) <- unzip3 <$> zipWithM mkOutput (extendPorts ps) results
let hwty2 = RTree d (filterVoid hwty')
netdecl = NetDecl Nothing pN hwty2
assigns = zipWith (assignId pN hwty2 10) ids [0..]
return (concat ports,netdecl:assigns ++ concat decls,pN)
Product _ hwtys -> do
results <- zipWithM appendIdentifier (map (pN,) hwtys) [0..]
let resultsBundled = zip hwtys (zip (extendPorts ps) results)
resultsFiltered = filter (not . isVoid . fst) resultsBundled
resultsFiltered' = unzip (map snd resultsFiltered)
(ports,decls,ids) <- unzip3 <$> uncurry (zipWithM mkOutput) resultsFiltered'
case ids of
[i] -> let hwty' = filterVoid hwty
netdecl = NetDecl Nothing pN hwty'
assign = Assignment i (Identifier pN Nothing)
in return (concat ports,netdecl:assign:concat decls,pN)
_ -> let hwty' = filterVoid hwty
netdecl = NetDecl Nothing pN hwty'
assigns = zipWith (assignId pN hwty' 0) ids [0..]
in return (concat ports,netdecl:assigns ++ concat decls,pN)
_ -> return ([(pN,hwty)],[],pN)
assignId p hwty con i n =
Assignment i (Identifier p (Just (Indexed (hwty,con,n))))
mkTopUnWrapper
:: TmName
-> Maybe TopEntity
-> Manifest
-> (Identifier,HWType)
-> [(Expr,HWType)]
-> NetlistMonad [Declaration]
mkTopUnWrapper topEntity annM man dstId args = do
let inTys = portInTypes man
outTys = portOutTypes man
inNames = portInNames man
outNames = portOutNames man
mkId <- Lens.use mkIdentifierFn
let topName = genComponentName [] mkId topEntity
topName' = maybe topName (pack . t_name) annM
topM = fmap (const topName') annM
let iPortSupply = maybe (repeat Nothing)
(extendPorts . t_inputs)
annM
arguments <- zipWithM appendIdentifier (map (first (const "input")) args) [0..]
(_,arguments1) <- mapAccumLM (\acc (p,i) -> mkTopInput topM acc p i)
(zip inNames inTys)
(zip iPortSupply arguments)
let (iports,wrappers,idsI) = unzip3 arguments1
inpAssigns = zipWith (argBV topM) idsI (map fst args)
let oPortSupply = maybe (repeat Nothing)
(extendPorts . (:[]) . t_output)
annM
result = ("result",snd dstId)
(_,(oports,unwrappers,idsO)) <- mkTopOutput topM (zip outNames outTys)
(head oPortSupply) result
let outpAssign = Assignment (fst dstId) (resBV topM idsO)
instLabel <- extendIdentifier Basic topName' ("_" `append` fst dstId)
let topCompDecl =
InstDecl
(Just topName')
topName'
instLabel
(map (\(p,i,t) -> (Identifier p Nothing,In, t,Identifier i Nothing)) (concat iports) ++
map (\(p,o,t) -> (Identifier p Nothing,Out,t,Identifier o Nothing)) oports)
return (inpAssigns ++ concat wrappers ++ (topCompDecl:unwrappers) ++ [outpAssign])
argBV
:: Maybe Identifier
-> Either Identifier (Identifier, HWType)
-> Expr
-> Declaration
argBV _ (Left i) e = Assignment i e
argBV topM (Right (i,t)) e = Assignment i
. doConv t (fmap Just topM) False
$ doConv t (fmap (const Nothing) topM) True e
resBV
:: Maybe Identifier
-> Either Identifier (Identifier, HWType)
-> Expr
resBV _ (Left i) = Identifier i Nothing
resBV topM (Right (i,t)) = doConv t (fmap (const Nothing) topM) False
. doConv t (fmap Just topM) True
$ Identifier i Nothing
doConv
:: HWType
-> Maybe (Maybe Identifier)
-> Bool
-> Expr
-> Expr
doConv _ Nothing _ e = e
doConv hwty (Just topM) b e = case hwty of
Vector {} -> ConvBV topM hwty b e
RTree {} -> ConvBV topM hwty b e
Product {} -> ConvBV topM hwty b e
Clock _ _ Gated -> ConvBV topM hwty b e
_ -> e
mkTopInput
:: Maybe Identifier
-> [(Identifier,Identifier)]
-> Maybe PortName
-> (Identifier,HWType)
-> NetlistMonad ([(Identifier,Identifier)]
,([(Identifier,Identifier,HWType)]
,[Declaration]
,Either Identifier (Identifier,HWType)))
mkTopInput topM inps pM = case pM of
Nothing -> go inps
Just p -> go' p inps
where
go inps'@((iN,_):rest) (i,hwty) = do
i' <- mkUniqueIdentifier Basic i
let iDecl = NetDecl Nothing i' hwty
case hwty of
Vector sz hwty' -> do
arguments <- mapM (appendIdentifier (i',hwty')) [0..sz-1]
(inps'',arguments1) <- mapAccumLM go inps' arguments
let (ports,decls,ids) = unzip3 arguments1
assigns = zipWith (argBV topM) ids
[ Identifier i' (Just (Indexed (hwty,10,n)))
| n <- [0..]]
return (inps'',(concat ports,iDecl:assigns++concat decls,Left i'))
RTree d hwty' -> do
arguments <- mapM (appendIdentifier (i',hwty')) [0..2^d-1]
(inps'',arguments1) <- mapAccumLM go inps' arguments
let (ports,decls,ids) = unzip3 arguments1
assigns = zipWith (argBV topM) ids
[ Identifier i' (Just (Indexed (hwty,10,n)))
| n <- [0..]]
return (inps'',(concat ports,iDecl:assigns++concat decls,Left i'))
Product _ hwtys -> do
arguments <- zipWithM appendIdentifier (map (i,) hwtys) [0..]
(inps'',arguments1) <- mapAccumLM go inps' arguments
let (ports,decls,ids) = unzip3 arguments1
assigns = zipWith (argBV topM) ids
[ Identifier i' (Just (Indexed (hwty,0,n)))
| n <- [0..]]
return (inps'',(concat ports,iDecl:assigns++concat decls,Left i'))
Clock nm rt Gated -> do
let hwtys = [Clock nm rt Source,Bool]
arguments <- zipWithM appendIdentifier (map (i,) hwtys) [0..]
(inps'',arguments1) <- mapAccumLM go inps' arguments
let (ports,decls,ids) = unzip3 arguments1
assigns = zipWith (argBV topM) ids
[ Identifier i' (Just (Indexed (hwty,0,n)))
| n <- [0..]]
return (inps'',(concat ports,iDecl:assigns++concat decls,Left i'))
_ -> return (rest,([(iN,i',hwty)],[iDecl],Left i'))
go [] _ = error "This shouldn't happen"
go' (PortName _) ((iN,iTy):inps') (_,hwty) = do
iN' <- mkUniqueIdentifier Extended iN
return (inps',([(iN,iN',hwty)]
,[NetDecl' Nothing Wire iN' (Left iTy)]
,Right (iN',hwty)))
go' (PortName _) [] _ = error "This shouldnt happen"
go' (PortProduct p ps) inps' (i,hwty) = do
let pN = portName p i
pN' <- mkUniqueIdentifier Extended pN
let pDecl = NetDecl Nothing pN' hwty
case hwty of
Vector sz hwty' -> do
arguments <- mapM (appendIdentifier (pN',hwty')) [0..sz-1]
(inps'',arguments1) <-
mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'
(zip (extendPorts ps) arguments)
let (ports,decls,ids) = unzip3 arguments1
assigns = zipWith (argBV topM) ids
[ Identifier pN' (Just (Indexed (hwty,10,n)))
| n <- [0..]]
return (inps'',(concat ports,pDecl:assigns ++ concat decls,Left pN'))
RTree d hwty' -> do
arguments <- mapM (appendIdentifier (pN',hwty')) [0..2^d-1]
(inps'',arguments1) <-
mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'
(zip (extendPorts ps) arguments)
let (ports,decls,ids) = unzip3 arguments1
assigns = zipWith (argBV topM) ids
[ Identifier pN' (Just (Indexed (hwty,10,n)))
| n <- [0..]]
return (inps'',(concat ports,pDecl:assigns ++ concat decls,Left pN'))
Product _ hwtys -> do
arguments <- zipWithM appendIdentifier (map (pN',) hwtys) [0..]
(inps'',arguments1) <-
mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'
(zip (extendPorts ps) arguments)
let (ports,decls,ids) = unzip3 arguments1
assigns = zipWith (argBV topM) ids
[ Identifier pN' (Just (Indexed (hwty,0,n)))
| n <- [0..]]
return (inps'',(concat ports,pDecl:assigns ++ concat decls,Left pN'))
Clock nm rt Gated -> do
let hwtys = [Clock nm rt Source,Bool]
arguments <- zipWithM appendIdentifier (map (pN',) hwtys) [0..]
(inps'',arguments1) <-
mapAccumLM (\acc (p',o') -> mkTopInput topM acc p' o') inps'
(zip (extendPorts ps) arguments)
let (ports,decls,ids) = unzip3 arguments1
assigns = zipWith (argBV topM) ids
[ Identifier pN' (Just (Indexed (hwty,0,n)))
| n <- [0..]]
return (inps'',(concat ports,pDecl:assigns ++ concat decls,Left pN'))
_ -> return (tail inps',([(pN,pN',hwty)],[pDecl],Left pN'))
mkTopOutput
:: Maybe Identifier
-> [(Identifier,Identifier)]
-> Maybe PortName
-> (Identifier,HWType)
-> NetlistMonad ([(Identifier,Identifier)]
,([(Identifier,Identifier,HWType)]
,[Declaration]
,Either Identifier (Identifier,HWType))
)
mkTopOutput topM outps pM = case pM of
Nothing -> go outps
Just p -> go' p outps
where
go outps'@((oN,_):rest) (o,hwty) = do
o' <- mkUniqueIdentifier Extended o
let oDecl = NetDecl Nothing o' hwty
case hwty of
Vector sz hwty' -> do
results <- mapM (appendIdentifier (o',hwty')) [0..sz-1]
(outps'',results1) <- mapAccumLM go outps' results
let (ports,decls,ids) = unzip3 results1
ids' = map (resBV topM) ids
netassgn = Assignment o' (mkVectorChain sz hwty' ids')
return (outps'',(concat ports,oDecl:netassgn:concat decls,Left o'))
RTree d hwty' -> do
results <- mapM (appendIdentifier (o',hwty')) [0..2^d-1]
(outps'',results1) <- mapAccumLM go outps' results
let (ports,decls,ids) = unzip3 results1
ids' = map (resBV topM) ids
netassgn = Assignment o' (mkRTreeChain d hwty' ids')
return (outps'',(concat ports,oDecl:netassgn:concat decls,Left o'))
Product _ hwtys -> do
results <- zipWithM appendIdentifier (map (o',) hwtys) [0..]
(outps'',results1) <- mapAccumLM go outps' results
let (ports,decls,ids) = unzip3 results1
ids' = map (resBV topM) ids
netassgn = Assignment o' (DataCon hwty (DC (hwty,0)) ids')
return (outps'',(concat ports,oDecl:netassgn:concat decls,Left o'))
_ -> return (rest,([(oN,o',hwty)],[oDecl],Left o'))
go [] _ = error "This shouldn't happen"
go' (PortName _) ((oN,oTy):outps') (_,hwty) = do
oN' <- mkUniqueIdentifier Extended oN
return (outps',([(oN,oN',hwty)]
,[NetDecl' Nothing Wire oN' (Left oTy)]
,Right (oN',hwty)))
go' (PortName _) [] _ = error "This shouldnt happen"
go' (PortProduct p ps) outps' (o,hwty) = do
let pN = portName p o
pN' <- mkUniqueIdentifier Extended pN
let pDecl = NetDecl Nothing pN' hwty
case hwty of
Vector sz hwty' -> do
results <- mapM (appendIdentifier (pN',hwty')) [0..sz-1]
(outps'',results1) <-
mapAccumLM (\acc (p',o') -> mkTopOutput topM acc p' o') outps'
(zip (extendPorts ps) results)
let (ports,decls,ids) = unzip3 results1
ids' = map (resBV topM) ids
netassgn = Assignment pN' (mkVectorChain sz hwty' ids')
return (outps'',(concat ports,pDecl:netassgn:concat decls,Left pN'))
RTree d hwty' -> do
results <- mapM (appendIdentifier (pN',hwty')) [0..2^d-1]
(outps'',results1) <-
mapAccumLM (\acc (p',o') -> mkTopOutput topM acc p' o') outps'
(zip (extendPorts ps) results)
let (ports,decls,ids) = unzip3 results1
ids' = map (resBV topM) ids
netassgn = Assignment pN' (mkRTreeChain d hwty' ids')
return (outps'',(concat ports,pDecl:netassgn:concat decls,Left pN'))
Product _ hwtys -> do
results <- zipWithM appendIdentifier (map (pN',) hwtys) [0..]
(outps'',results1) <-
mapAccumLM (\acc (p',o') -> mkTopOutput topM acc p' o') outps'
(zip (extendPorts ps) results)
let (ports,decls,ids) = unzip3 results1
ids' = map (resBV topM) ids
netassgn = Assignment pN' (DataCon hwty (DC (hwty,0)) ids')
return (outps'',(concat ports,pDecl:netassgn:concat decls,Left pN'))
_ -> return (tail outps',([(pN,pN',hwty)],[pDecl],Left pN'))
concatPortDecls3
:: [([(Identifier,Identifier,HWType)]
,[Declaration]
,Either Identifier (Identifier,HWType))]
-> ([(Identifier,Identifier,HWType)]
,[Declaration]
,[Either Identifier (Identifier,HWType)])
concatPortDecls3 portDecls = case unzip3 portDecls of
(ps,decls,ids) -> (concat ps, concat decls, ids)