2019-03-07 02:30:47 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
|
|
|
|
- Conversion for interfaces
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Convert.Interface (convert) where
|
|
|
|
|
|
2020-06-20 20:39:57 +02:00
|
|
|
import Data.Maybe (mapMaybe)
|
2019-03-07 02:30:47 +01:00
|
|
|
import Control.Monad.Writer
|
|
|
|
|
import qualified Data.Map.Strict as Map
|
2019-04-02 19:33:18 +02:00
|
|
|
import qualified Data.Set as Set
|
2019-03-07 02:30:47 +01:00
|
|
|
|
|
|
|
|
import Convert.Traverse
|
|
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
|
|
|
|
type Interface = ([Identifier], [ModuleItem])
|
|
|
|
|
type Interfaces = Map.Map Identifier Interface
|
2020-06-20 20:39:57 +02:00
|
|
|
type Module = ([Identifier], [(Identifier, Type)])
|
|
|
|
|
type Modules = Map.Map Identifier Module
|
|
|
|
|
type Instances = Map.Map Identifier Identifier
|
|
|
|
|
type Modports = Map.Map Identifier (Identifier, Identifier)
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-04-24 00:44:45 +02:00
|
|
|
convert :: [AST] -> [AST]
|
2019-04-30 21:44:52 +02:00
|
|
|
convert =
|
2020-04-14 04:23:03 +02:00
|
|
|
map (filter $ not . isInterface) .
|
|
|
|
|
repeatedConverter
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
2020-04-14 04:23:03 +02:00
|
|
|
repeatedConverter :: [AST] -> [AST]
|
|
|
|
|
repeatedConverter files =
|
|
|
|
|
if files == files'
|
|
|
|
|
then files
|
|
|
|
|
else repeatedConverter files'
|
|
|
|
|
where
|
|
|
|
|
files' =
|
|
|
|
|
traverseFiles (collectDescriptionsM collectDesc)
|
|
|
|
|
(map . uncurry convertDescription)
|
|
|
|
|
files
|
2019-03-26 20:10:16 +01:00
|
|
|
-- we can only collect/map non-extern interfaces
|
2019-04-01 07:23:44 +02:00
|
|
|
collectDesc :: Description -> Writer (Interfaces, Modules) ()
|
2019-09-16 05:17:14 +02:00
|
|
|
collectDesc (orig @ (Part _ False kw _ name ports items)) = do
|
2020-06-20 02:32:37 +02:00
|
|
|
if kw == Interface then
|
|
|
|
|
if all fullyResolved items
|
|
|
|
|
then tell (Map.singleton name (ports, items), Map.empty)
|
|
|
|
|
else return ()
|
2020-06-15 04:54:23 +02:00
|
|
|
else tell (Map.empty, Map.singleton name (params, decls))
|
2019-10-21 04:06:10 +02:00
|
|
|
where
|
2020-06-15 04:54:23 +02:00
|
|
|
params = map fst $ parameters items
|
2020-02-09 19:42:45 +01:00
|
|
|
decls = execWriter $
|
|
|
|
|
collectModuleItemsM (collectDeclsM collectDecl) orig
|
|
|
|
|
collectDecl :: Decl -> Writer [(Identifier, Type)] ()
|
2019-10-21 04:06:10 +02:00
|
|
|
collectDecl (Variable _ t ident _ _) =
|
2020-02-09 19:42:45 +01:00
|
|
|
tell [(ident, t)]
|
2019-10-21 04:06:10 +02:00
|
|
|
collectDecl _ = return ()
|
2019-03-07 02:30:47 +01:00
|
|
|
collectDesc _ = return ()
|
|
|
|
|
isInterface :: Description -> Bool
|
2020-06-20 02:32:37 +02:00
|
|
|
isInterface (Part _ False Interface _ _ _ items) =
|
|
|
|
|
all fullyResolved items
|
2019-03-07 02:30:47 +01:00
|
|
|
isInterface _ = False
|
2020-06-20 02:32:37 +02:00
|
|
|
-- returns whether a ModuleItem still contains TypeOf
|
|
|
|
|
fullyResolved :: ModuleItem -> Bool
|
|
|
|
|
fullyResolved =
|
|
|
|
|
not . any isTypeOf . execWriter .
|
|
|
|
|
collectNestedModuleItemsM (collectTypesM collectType)
|
|
|
|
|
where
|
|
|
|
|
collectType :: Type -> Writer [Type] ()
|
|
|
|
|
collectType t = tell [t]
|
|
|
|
|
isTypeOf TypeOf{} = True
|
|
|
|
|
isTypeOf _ = False
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-04-01 07:23:44 +02:00
|
|
|
convertDescription :: Interfaces -> Modules -> Description -> Description
|
2019-09-16 05:17:14 +02:00
|
|
|
convertDescription interfaces modules (Part attrs extern Module lifetime name ports items) =
|
|
|
|
|
Part attrs extern Module lifetime name ports' items'
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
2019-03-07 03:55:27 +01:00
|
|
|
items' =
|
2019-04-02 19:33:18 +02:00
|
|
|
map (traverseNestedModuleItems $ traverseExprs' ExcludeTFs (traverseNestedExprs $ convertExpr instances modports)) $
|
|
|
|
|
map (traverseNestedModuleItems $ traverseLHSs' ExcludeTFs (traverseNestedLHSs $ convertLHS instances modports)) $
|
2019-03-07 03:55:27 +01:00
|
|
|
map (traverseNestedModuleItems mapInterface) $
|
|
|
|
|
items
|
|
|
|
|
ports' = concatMap convertPort ports
|
2019-03-07 02:30:47 +01:00
|
|
|
|
|
|
|
|
-- collect the interface type of all interface instances in this module
|
2019-03-07 03:55:27 +01:00
|
|
|
(instances, modports) = execWriter $ mapM
|
2020-06-20 20:39:57 +02:00
|
|
|
(collectNestedModuleItemsM collectInstanceM) items
|
|
|
|
|
collectInstanceM :: ModuleItem -> Writer (Instances, Modports) ()
|
|
|
|
|
collectInstanceM (MIPackageItem (Decl (Variable _ t ident _ _))) =
|
2019-03-07 03:55:27 +01:00
|
|
|
case t of
|
|
|
|
|
InterfaceT interfaceName (Just modportName) [] ->
|
2020-06-20 02:32:37 +02:00
|
|
|
if Map.member interfaceName interfaces
|
2020-06-20 20:39:57 +02:00
|
|
|
then writeModport interfaceName modportName
|
2020-06-20 02:32:37 +02:00
|
|
|
else return ()
|
2020-06-04 02:18:14 +02:00
|
|
|
Alias Nothing interfaceName [] ->
|
2020-06-20 20:39:57 +02:00
|
|
|
if Map.member interfaceName interfaces
|
|
|
|
|
then writeModport interfaceName ""
|
|
|
|
|
else return ()
|
2019-03-07 03:55:27 +01:00
|
|
|
_ -> return ()
|
2020-06-20 20:39:57 +02:00
|
|
|
where
|
|
|
|
|
writeModport :: Identifier -> Identifier ->
|
|
|
|
|
Writer (Instances, Modports) ()
|
|
|
|
|
writeModport interfaceName modportName =
|
|
|
|
|
tell (Map.empty, Map.singleton ident modport)
|
|
|
|
|
where modport = (interfaceName, modportName)
|
|
|
|
|
collectInstanceM (Instance part _ ident [] _) =
|
2019-03-07 02:30:47 +01:00
|
|
|
if Map.member part interfaces
|
2019-03-07 03:55:27 +01:00
|
|
|
then tell (Map.singleton ident part, Map.empty)
|
2019-03-07 02:30:47 +01:00
|
|
|
else return ()
|
2020-06-20 20:39:57 +02:00
|
|
|
collectInstanceM _ = return ()
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-03-07 03:55:27 +01:00
|
|
|
mapInterface :: ModuleItem -> ModuleItem
|
2020-06-20 20:39:57 +02:00
|
|
|
mapInterface (orig @ (MIPackageItem (Decl (Variable _ _ ident _ _)))) =
|
2019-10-21 04:06:10 +02:00
|
|
|
-- expand instantiation of a modport
|
2020-06-20 20:39:57 +02:00
|
|
|
if Map.member ident modports
|
|
|
|
|
then Generate $ map GenModuleItem $
|
2020-06-20 02:32:37 +02:00
|
|
|
filter shouldKeep interfaceItems ++ map makePortDecl
|
2020-06-20 20:39:57 +02:00
|
|
|
modportDecls
|
|
|
|
|
else orig
|
2019-03-07 03:55:27 +01:00
|
|
|
where
|
2020-06-20 20:39:57 +02:00
|
|
|
Just (interfaceName, modportName) = Map.lookup ident modports
|
2020-06-20 00:26:45 +02:00
|
|
|
interfaceItems = prefixInterface ident $
|
2020-06-20 20:39:57 +02:00
|
|
|
snd $ lookupInterface interfaceName
|
|
|
|
|
modportDecls = lookupModport interfaceItems modportName
|
2020-06-20 00:26:45 +02:00
|
|
|
shouldKeep (MIPackageItem (Decl Param{})) = True
|
|
|
|
|
shouldKeep (MIPackageItem Task{}) = True
|
|
|
|
|
shouldKeep (MIPackageItem Function{}) = True
|
|
|
|
|
shouldKeep _ = False
|
|
|
|
|
makePortDecl :: ModportDecl -> ModuleItem
|
2020-06-20 02:32:37 +02:00
|
|
|
makePortDecl (dir, port, typ, _) =
|
2020-06-20 20:39:57 +02:00
|
|
|
MIPackageItem $ Decl $ Variable dir typ port' [] Nil
|
|
|
|
|
where port' = if null modportName
|
|
|
|
|
then port
|
|
|
|
|
else ident ++ '_' : port
|
2020-06-18 04:01:59 +02:00
|
|
|
mapInterface (Instance part params ident [] instancePorts) =
|
2019-10-21 04:06:10 +02:00
|
|
|
-- expand modport port bindings
|
2019-03-07 02:30:47 +01:00
|
|
|
case Map.lookup part interfaces of
|
|
|
|
|
Just interface ->
|
2019-10-21 04:06:10 +02:00
|
|
|
-- inline instantiation of an interface
|
2019-10-20 21:58:37 +02:00
|
|
|
Generate $ map GenModuleItem $
|
2020-06-15 04:54:23 +02:00
|
|
|
inlineInterface interface (ident, params, instancePorts)
|
|
|
|
|
Nothing ->
|
|
|
|
|
if Map.member part modules
|
2020-06-18 04:01:59 +02:00
|
|
|
then Instance part params' ident [] expandedPorts
|
|
|
|
|
else Instance part params ident [] instancePorts
|
2020-06-15 04:54:23 +02:00
|
|
|
where
|
|
|
|
|
expandedBindings = map (uncurry $ expandPortBinding part) (zip instancePorts [0..])
|
|
|
|
|
expandedPorts = concatMap snd expandedBindings
|
|
|
|
|
Just (moduleParamNames, _) = Map.lookup part modules
|
|
|
|
|
addedParams = concatMap fst expandedBindings
|
|
|
|
|
paramsNamed = resolveParams moduleParamNames params
|
|
|
|
|
params' =
|
|
|
|
|
if null addedParams
|
|
|
|
|
then params
|
|
|
|
|
else paramsNamed ++ addedParams
|
2019-04-02 19:33:18 +02:00
|
|
|
mapInterface (orig @ (MIPackageItem (Function _ _ _ decls _))) =
|
|
|
|
|
convertTF decls orig
|
|
|
|
|
mapInterface (orig @ (MIPackageItem (Task _ _ decls _))) =
|
|
|
|
|
convertTF decls orig
|
2019-03-07 03:55:27 +01:00
|
|
|
mapInterface other = other
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-04-02 19:33:18 +02:00
|
|
|
convertTF :: [Decl] -> ModuleItem -> ModuleItem
|
2019-10-21 04:06:10 +02:00
|
|
|
convertTF decls =
|
|
|
|
|
traverseExprs (traverseNestedExprs $ convertExpr its mps) .
|
|
|
|
|
traverseLHSs (traverseNestedLHSs $ convertLHS its mps)
|
2019-04-02 19:33:18 +02:00
|
|
|
where
|
2020-06-14 21:56:09 +02:00
|
|
|
locals = Set.fromList $ map declVarIdent decls
|
2019-04-02 19:33:18 +02:00
|
|
|
its = Map.withoutKeys instances locals
|
|
|
|
|
mps = Map.withoutKeys modports locals
|
2020-06-14 21:56:09 +02:00
|
|
|
declVarIdent :: Decl -> Identifier
|
|
|
|
|
declVarIdent (Variable _ _ x _ _) = x
|
|
|
|
|
declVarIdent _ = ""
|
2019-04-02 19:33:18 +02:00
|
|
|
|
2020-06-15 04:54:23 +02:00
|
|
|
expandPortBinding :: Identifier -> PortBinding -> Int -> ([ParamBinding], [PortBinding])
|
2020-06-20 00:26:45 +02:00
|
|
|
expandPortBinding moduleName ("", binding) idx =
|
|
|
|
|
case Map.lookup moduleName modules of
|
|
|
|
|
Nothing -> error $ "could not find module: " ++ moduleName
|
|
|
|
|
Just (_, decls) ->
|
|
|
|
|
if idx < length decls
|
|
|
|
|
then expandPortBinding moduleName
|
|
|
|
|
(fst $ decls !! idx, binding) idx
|
|
|
|
|
else error $ "could not infer port for "
|
|
|
|
|
++ show binding ++ " in module " ++ show moduleName
|
2020-06-14 21:56:09 +02:00
|
|
|
expandPortBinding _ (origBinding @ (portName, Dot (Ident instanceName) modportName)) _ =
|
2019-10-21 04:06:10 +02:00
|
|
|
-- expand instance modport bound to a modport
|
2020-06-20 20:39:57 +02:00
|
|
|
if Map.member instanceName instances
|
2020-06-15 04:54:23 +02:00
|
|
|
then expandPortBinding' interfaceName portName instanceName
|
2020-06-20 20:39:57 +02:00
|
|
|
modportDecls
|
2020-06-15 04:54:23 +02:00
|
|
|
else ([], [origBinding])
|
2019-10-21 04:06:10 +02:00
|
|
|
where
|
|
|
|
|
interfaceName = instances Map.! instanceName
|
2020-06-20 20:39:57 +02:00
|
|
|
interfaceItems = snd $ lookupInterface interfaceName
|
|
|
|
|
modportDecls = lookupModport interfaceItems modportName
|
2020-06-20 00:26:45 +02:00
|
|
|
expandPortBinding moduleName (origBinding @ (portName, Ident ident)) _ =
|
2019-10-21 04:06:10 +02:00
|
|
|
case (instances Map.!? ident, modports Map.!? ident) of
|
2020-06-15 04:54:23 +02:00
|
|
|
(Nothing, Nothing) -> ([], [origBinding])
|
2020-06-04 02:18:14 +02:00
|
|
|
(Just interfaceName, _) ->
|
2019-10-21 04:06:10 +02:00
|
|
|
-- given entire interface, but just bound to a modport
|
2020-06-04 02:18:14 +02:00
|
|
|
if Map.notMember moduleName modules then
|
|
|
|
|
error $ "could not find module " ++ show moduleName
|
|
|
|
|
else
|
2020-06-15 04:54:23 +02:00
|
|
|
expandPortBinding' interfaceName portName ident
|
2020-06-20 20:39:57 +02:00
|
|
|
modportDecls
|
2019-04-01 07:23:44 +02:00
|
|
|
where
|
2020-06-15 04:54:23 +02:00
|
|
|
Just (_, decls) = Map.lookup moduleName modules
|
2020-06-04 02:18:14 +02:00
|
|
|
portType =
|
2020-06-20 00:26:45 +02:00
|
|
|
case lookup portName decls of
|
2020-06-04 02:18:14 +02:00
|
|
|
Nothing -> error $ "could not find port "
|
|
|
|
|
++ show portName ++ " in module "
|
|
|
|
|
++ show moduleName
|
|
|
|
|
Just t -> t
|
2020-06-20 20:39:57 +02:00
|
|
|
interfaceItems = snd $ lookupInterface interfaceName
|
|
|
|
|
modportDecls = lookupModport interfaceItems modportName
|
|
|
|
|
modportName = case portType of
|
|
|
|
|
InterfaceT _ (Just x) [] -> x
|
|
|
|
|
Alias Nothing _ [] -> ""
|
|
|
|
|
_ -> error $ "can't deduce modport for interface "
|
|
|
|
|
++ interfaceName ++ " bound to port "
|
|
|
|
|
++ portName ++ " of module " ++ moduleName
|
|
|
|
|
(_, Just (interfaceName, modportName)) ->
|
2019-10-21 04:06:10 +02:00
|
|
|
-- modport directly bound to a modport
|
2020-06-15 04:54:23 +02:00
|
|
|
expandPortBinding' interfaceName portName ident
|
|
|
|
|
(map redirect modportDecls)
|
2020-06-20 20:39:57 +02:00
|
|
|
where
|
|
|
|
|
interfaceItems = snd $ lookupInterface interfaceName
|
|
|
|
|
modportDecls = lookupModport interfaceItems modportName
|
|
|
|
|
redirect (d, x, t, _) = (d, x, t, Ident x)
|
2020-06-15 04:54:23 +02:00
|
|
|
expandPortBinding _ other _ = ([], [other])
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2020-06-15 04:54:23 +02:00
|
|
|
expandPortBinding' :: Identifier -> Identifier -> Identifier ->
|
|
|
|
|
[ModportDecl] -> ([ParamBinding], [PortBinding])
|
|
|
|
|
expandPortBinding' interfaceName portName instanceName modportDecls =
|
|
|
|
|
(paramBindings, portBindings)
|
2020-06-04 02:18:14 +02:00
|
|
|
where
|
2020-06-15 04:54:23 +02:00
|
|
|
paramBindings = map toParamBinding interfaceParamNames
|
2020-06-20 20:39:57 +02:00
|
|
|
interfaceItems = snd $ lookupInterface interfaceName
|
2020-06-15 04:54:23 +02:00
|
|
|
interfaceParamNames = map fst $ parameters interfaceItems
|
2020-06-20 00:26:45 +02:00
|
|
|
toParamBinding x = (portName ++ '_' : x, Right $ Ident $ instanceName ++ '_' : x)
|
2020-06-15 04:54:23 +02:00
|
|
|
portBindings = map toPortBinding modportDecls
|
2020-06-20 02:32:37 +02:00
|
|
|
toPortBinding (_, x, _, e) = (x', e')
|
2020-06-04 02:18:14 +02:00
|
|
|
where
|
2020-06-20 00:26:45 +02:00
|
|
|
x' = portName ++ '_' : x
|
2020-06-14 21:56:09 +02:00
|
|
|
e' = traverseNestedExprs prefixExpr e
|
2020-06-04 02:18:14 +02:00
|
|
|
prefixExpr :: Expr -> Expr
|
|
|
|
|
prefixExpr (Ident x) = Ident (instanceName ++ '_' : x)
|
|
|
|
|
prefixExpr other = other
|
|
|
|
|
|
2020-06-20 20:39:57 +02:00
|
|
|
lookupInterface :: Identifier -> Interface
|
|
|
|
|
lookupInterface interfaceName =
|
|
|
|
|
case Map.lookup interfaceName interfaces of
|
|
|
|
|
Just res -> res
|
|
|
|
|
Nothing -> error $ "could not find interface " ++ show interfaceName
|
|
|
|
|
|
|
|
|
|
lookupModport :: [ModuleItem] -> Identifier -> [ModportDecl]
|
|
|
|
|
lookupModport interfaceItems "" = impliedModport interfaceItems
|
|
|
|
|
lookupModport interfaceItems modportName =
|
|
|
|
|
case Map.lookup modportName modportMap of
|
|
|
|
|
Just modportDecls -> modportDecls
|
|
|
|
|
Nothing -> error $ "could not find modport " ++ show modportName
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
|
|
|
|
modportMap = execWriter $
|
|
|
|
|
mapM (collectNestedModuleItemsM collectModport) $
|
|
|
|
|
interfaceItems
|
2020-06-15 04:54:23 +02:00
|
|
|
collectModport :: ModuleItem -> Writer (Map.Map Identifier [ModportDecl]) ()
|
2019-03-07 03:55:27 +01:00
|
|
|
collectModport (Modport ident l) = tell $ Map.singleton ident l
|
2019-03-07 02:30:47 +01:00
|
|
|
collectModport _ = return ()
|
|
|
|
|
|
2020-06-20 20:39:57 +02:00
|
|
|
impliedModport :: [ModuleItem] -> [ModportDecl]
|
|
|
|
|
impliedModport =
|
|
|
|
|
execWriter . mapM (collectNestedModuleItemsM collectModportDecls)
|
2020-06-04 02:18:14 +02:00
|
|
|
where
|
|
|
|
|
collectModportDecls :: ModuleItem -> Writer [ModportDecl] ()
|
2020-06-20 02:32:37 +02:00
|
|
|
collectModportDecls (MIPackageItem (Decl (Variable d t x _ _))) =
|
|
|
|
|
tell [(d', x, t, Ident x)]
|
2020-06-04 02:18:14 +02:00
|
|
|
where d' = if d == Local then Inout else d
|
|
|
|
|
collectModportDecls _ = return ()
|
|
|
|
|
|
2019-04-02 19:33:18 +02:00
|
|
|
convertExpr :: Instances -> Modports -> Expr -> Expr
|
|
|
|
|
convertExpr its mps (orig @ (Dot (Ident x) y)) =
|
|
|
|
|
if Map.member x mps || Map.member x its
|
2019-03-07 03:55:27 +01:00
|
|
|
then Ident (x ++ "_" ++ y)
|
|
|
|
|
else orig
|
2019-04-02 19:33:18 +02:00
|
|
|
convertExpr _ _ other = other
|
|
|
|
|
convertLHS :: Instances -> Modports -> LHS -> LHS
|
|
|
|
|
convertLHS its mps (orig @ (LHSDot (LHSIdent x) y)) =
|
|
|
|
|
if Map.member x mps || Map.member x its
|
2019-03-07 03:55:27 +01:00
|
|
|
then LHSIdent (x ++ "_" ++ y)
|
|
|
|
|
else orig
|
2019-04-02 19:33:18 +02:00
|
|
|
convertLHS _ _ other = other
|
2019-03-07 03:55:27 +01:00
|
|
|
convertPort :: Identifier -> [Identifier]
|
|
|
|
|
convertPort ident =
|
|
|
|
|
case Map.lookup ident modports of
|
|
|
|
|
Nothing -> [ident]
|
2020-06-20 20:39:57 +02:00
|
|
|
Just (interfaceName, modportName) ->
|
|
|
|
|
map (\(_, x, _, _) ->
|
|
|
|
|
ident ++ "_" ++ x) modportDecls
|
|
|
|
|
where
|
|
|
|
|
interfaceItems = snd $ lookupInterface interfaceName
|
|
|
|
|
modportDecls = lookupModport interfaceItems modportName
|
2019-03-07 03:55:27 +01:00
|
|
|
|
2019-04-01 07:23:44 +02:00
|
|
|
convertDescription _ _ other = other
|
2019-03-07 02:30:47 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
-- add a prefix to all standard identifiers in a module item
|
2020-02-10 03:57:09 +01:00
|
|
|
prefixModuleItems :: (Identifier -> Identifier) -> ModuleItem -> ModuleItem
|
2019-03-07 02:30:47 +01:00
|
|
|
prefixModuleItems prefix =
|
2020-02-10 03:57:09 +01:00
|
|
|
prefixOtherItem .
|
2019-03-07 02:30:47 +01:00
|
|
|
traverseDecls prefixDecl .
|
2019-03-18 19:27:14 +01:00
|
|
|
traverseExprs (traverseNestedExprs prefixExpr) .
|
|
|
|
|
traverseLHSs (traverseNestedLHSs prefixLHS )
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
|
|
|
|
prefixDecl :: Decl -> Decl
|
2020-06-14 21:56:09 +02:00
|
|
|
prefixDecl (Variable d t x a e) = Variable d t (prefix x) a e
|
|
|
|
|
prefixDecl (Param s t x e) = Param s t (prefix x) e
|
|
|
|
|
prefixDecl (ParamType s x mt) = ParamType s (prefix x) mt
|
|
|
|
|
prefixDecl (CommentDecl c) = CommentDecl c
|
2019-03-07 02:30:47 +01:00
|
|
|
prefixExpr :: Expr -> Expr
|
2020-02-10 03:57:09 +01:00
|
|
|
prefixExpr (Ident x) = Ident (prefix x)
|
2019-03-07 02:30:47 +01:00
|
|
|
prefixExpr other = other
|
|
|
|
|
prefixLHS :: LHS -> LHS
|
2020-02-10 03:57:09 +01:00
|
|
|
prefixLHS (LHSIdent x) = LHSIdent (prefix x)
|
2019-03-07 02:30:47 +01:00
|
|
|
prefixLHS other = other
|
2020-04-14 04:23:03 +02:00
|
|
|
prefixOtherItem :: ModuleItem -> ModuleItem
|
2020-02-10 03:57:09 +01:00
|
|
|
prefixOtherItem (MIPackageItem item) =
|
2019-10-19 22:22:39 +02:00
|
|
|
MIPackageItem $ prefixPackageItem prefix item
|
2020-04-14 04:23:03 +02:00
|
|
|
prefixOtherItem (Instance m params name rs ports) =
|
|
|
|
|
Instance m params (prefix name) rs ports
|
2020-02-10 03:57:09 +01:00
|
|
|
prefixOtherItem (Genvar x) = Genvar $ prefix x
|
|
|
|
|
prefixOtherItem other = other
|
2019-10-19 22:22:39 +02:00
|
|
|
|
|
|
|
|
-- add a prefix to all standard identifiers in a package item
|
2020-02-10 03:57:09 +01:00
|
|
|
prefixPackageItem :: (Identifier -> Identifier) -> PackageItem -> PackageItem
|
2019-10-19 22:22:39 +02:00
|
|
|
prefixPackageItem prefix (Function lifetime t x decls stmts) =
|
|
|
|
|
Function lifetime t x' decls stmts
|
2020-02-10 03:57:09 +01:00
|
|
|
where x' = prefix x
|
2019-10-19 22:22:39 +02:00
|
|
|
prefixPackageItem prefix (Task lifetime x decls stmts) =
|
|
|
|
|
Task lifetime x' decls stmts
|
2020-02-10 03:57:09 +01:00
|
|
|
where x' = prefix x
|
2019-10-19 22:22:39 +02:00
|
|
|
prefixPackageItem _ other = other
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2020-02-10 03:57:09 +01:00
|
|
|
-- collect all identifiers defined within a module item
|
|
|
|
|
collectIdentsM :: ModuleItem -> Writer (Set.Set Identifier) ()
|
|
|
|
|
collectIdentsM (MIPackageItem (Function _ _ x _ _)) = tell $ Set.singleton x
|
|
|
|
|
collectIdentsM (MIPackageItem (Task _ x _ _)) = tell $ Set.singleton x
|
2020-04-14 04:23:03 +02:00
|
|
|
collectIdentsM (Instance _ _ x _ _) = tell $ Set.singleton x
|
2020-02-10 03:57:09 +01:00
|
|
|
collectIdentsM (Genvar x) = tell $ Set.singleton x
|
|
|
|
|
collectIdentsM item = collectDeclsM collectDecl item
|
|
|
|
|
where
|
|
|
|
|
collectDecl :: Decl -> Writer (Set.Set Identifier) ()
|
|
|
|
|
collectDecl (Variable _ _ x _ _) = tell $ Set.singleton x
|
|
|
|
|
collectDecl (Param _ _ x _) = tell $ Set.singleton x
|
|
|
|
|
collectDecl (ParamType _ x _) = tell $ Set.singleton x
|
|
|
|
|
collectDecl (CommentDecl _) = return ()
|
|
|
|
|
|
2019-03-07 02:30:47 +01:00
|
|
|
-- convert an interface instantiation into a series of equivalent module items
|
2019-10-20 21:58:37 +02:00
|
|
|
inlineInterface :: Interface -> (Identifier, [ParamBinding], [PortBinding]) -> [ModuleItem]
|
|
|
|
|
inlineInterface (ports, items) (instanceName, instanceParams, instancePorts) =
|
2020-01-31 04:17:17 +01:00
|
|
|
(:) comment $
|
2019-03-09 00:23:38 +01:00
|
|
|
flip (++) portBindings $
|
2019-03-07 02:30:47 +01:00
|
|
|
map (traverseNestedModuleItems removeModport) $
|
2019-04-23 23:12:56 +02:00
|
|
|
map (traverseNestedModuleItems removeDeclDir) $
|
2019-04-11 20:08:50 +02:00
|
|
|
itemsPrefixed
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
2020-01-31 04:17:17 +01:00
|
|
|
comment = MIPackageItem $ Decl $ CommentDecl $
|
|
|
|
|
"expanded instance: " ++ instanceName
|
2019-03-07 02:30:47 +01:00
|
|
|
prefix = instanceName ++ "_"
|
2019-10-20 21:58:37 +02:00
|
|
|
itemsPrefixed =
|
|
|
|
|
map (traverseDecls overrideParam) $
|
2020-06-20 00:26:45 +02:00
|
|
|
prefixInterface instanceName items
|
2019-03-07 02:30:47 +01:00
|
|
|
origInstancePortNames = map fst instancePorts
|
|
|
|
|
instancePortExprs = map snd instancePorts
|
|
|
|
|
instancePortNames =
|
|
|
|
|
map (prefix ++) $
|
|
|
|
|
if all ("" ==) origInstancePortNames
|
|
|
|
|
then ports
|
|
|
|
|
else origInstancePortNames
|
|
|
|
|
portBindings =
|
2019-04-11 20:08:50 +02:00
|
|
|
mapMaybe portBindingItem $
|
2019-03-07 02:30:47 +01:00
|
|
|
zip instancePortNames instancePortExprs
|
|
|
|
|
|
2019-04-23 23:12:56 +02:00
|
|
|
removeDeclDir :: ModuleItem -> ModuleItem
|
2020-06-14 21:56:09 +02:00
|
|
|
removeDeclDir (MIPackageItem (Decl (Variable _ t x a e))) =
|
2020-06-20 02:32:37 +02:00
|
|
|
MIPackageItem $ Decl $ Variable Local t' x a e
|
|
|
|
|
where t' = case t of
|
|
|
|
|
Implicit Unspecified rs ->
|
|
|
|
|
IntegerVector TLogic Unspecified rs
|
|
|
|
|
_ -> t
|
2019-04-23 23:12:56 +02:00
|
|
|
removeDeclDir other = other
|
2019-03-07 02:30:47 +01:00
|
|
|
removeModport :: ModuleItem -> ModuleItem
|
2019-03-07 19:19:31 +01:00
|
|
|
removeModport (Modport x _) =
|
2020-01-31 04:17:17 +01:00
|
|
|
MIPackageItem $ Decl $ CommentDecl $ "removed modport " ++ x
|
2019-03-07 02:30:47 +01:00
|
|
|
removeModport other = other
|
2019-04-11 20:08:50 +02:00
|
|
|
|
2020-06-15 04:54:23 +02:00
|
|
|
interfaceParamNames = map fst $ parameters items
|
2020-06-20 00:26:45 +02:00
|
|
|
instanceParamMap = Map.mapKeys (prefix ++) $
|
2020-06-15 04:54:23 +02:00
|
|
|
Map.fromList $ resolveParams interfaceParamNames instanceParams
|
2019-10-20 21:58:37 +02:00
|
|
|
overrideParam :: Decl -> Decl
|
|
|
|
|
overrideParam (Param Parameter t x e) =
|
|
|
|
|
case Map.lookup x instanceParamMap of
|
|
|
|
|
Nothing -> Param Parameter t x e
|
|
|
|
|
Just (Right e') -> Param Parameter t x e'
|
|
|
|
|
Just (Left t') ->
|
|
|
|
|
error $ "interface param expected expression, found type: "
|
|
|
|
|
++ show t'
|
|
|
|
|
overrideParam (ParamType Parameter x mt) =
|
|
|
|
|
case Map.lookup x instanceParamMap of
|
|
|
|
|
Nothing -> ParamType Parameter x mt
|
|
|
|
|
Just (Left t') -> ParamType Parameter x (Just t')
|
|
|
|
|
Just (Right e') ->
|
|
|
|
|
error $ "interface param expected type, found expression: "
|
|
|
|
|
++ show e'
|
|
|
|
|
overrideParam other = other
|
|
|
|
|
|
2019-04-11 20:08:50 +02:00
|
|
|
portBindingItem :: PortBinding -> Maybe ModuleItem
|
2020-06-14 21:56:09 +02:00
|
|
|
portBindingItem (_, Nil) = Nothing
|
|
|
|
|
portBindingItem (ident, expr) =
|
2019-04-11 20:08:50 +02:00
|
|
|
Just $ if declDirs Map.! ident == Input
|
2020-03-21 02:13:57 +01:00
|
|
|
then Assign AssignOptionNone (LHSIdent ident) expr
|
|
|
|
|
else Assign AssignOptionNone (toLHS expr) (Ident ident)
|
2019-04-11 20:08:50 +02:00
|
|
|
|
|
|
|
|
declDirs = execWriter $
|
|
|
|
|
mapM (collectDeclsM collectDeclDir) itemsPrefixed
|
|
|
|
|
collectDeclDir :: Decl -> Writer (Map.Map Identifier Direction) ()
|
|
|
|
|
collectDeclDir (Variable dir _ ident _ _) =
|
|
|
|
|
if dir /= Local
|
|
|
|
|
then tell $ Map.singleton ident dir
|
|
|
|
|
else return ()
|
|
|
|
|
collectDeclDir _ = return ()
|
|
|
|
|
|
2019-04-23 02:44:35 +02:00
|
|
|
toLHS :: Expr -> LHS
|
|
|
|
|
toLHS expr =
|
|
|
|
|
case exprToLHS expr of
|
|
|
|
|
Just lhs -> lhs
|
|
|
|
|
Nothing -> error $ "trying to bind an interface output to " ++
|
|
|
|
|
show expr ++ " but that can't be an LHS"
|
2020-06-15 04:54:23 +02:00
|
|
|
|
2020-06-20 00:26:45 +02:00
|
|
|
-- convert an interface instantiation into a series of equivalent module items
|
|
|
|
|
prefixInterface :: Identifier -> [ModuleItem] -> [ModuleItem]
|
|
|
|
|
prefixInterface instanceName items =
|
|
|
|
|
map prefixItem items
|
|
|
|
|
where
|
|
|
|
|
prefix = instanceName ++ "_"
|
|
|
|
|
idents = execWriter $
|
|
|
|
|
mapM (collectNestedModuleItemsM collectIdentsM) items
|
|
|
|
|
prefixIfNecessary :: Identifier -> Identifier
|
|
|
|
|
prefixIfNecessary x =
|
|
|
|
|
if Set.member x idents
|
|
|
|
|
then prefix ++ x
|
|
|
|
|
else x
|
|
|
|
|
prefixItem = traverseNestedModuleItems $
|
|
|
|
|
prefixModuleItems prefixIfNecessary
|
|
|
|
|
|
2020-06-15 04:54:23 +02:00
|
|
|
-- give a set of param bindings explicit names
|
|
|
|
|
resolveParams :: [Identifier] -> [ParamBinding] -> [ParamBinding]
|
|
|
|
|
resolveParams available bindings =
|
|
|
|
|
map (uncurry resolveParam) $ zip bindings [0..]
|
|
|
|
|
where
|
|
|
|
|
resolveParam :: ParamBinding -> Int -> ParamBinding
|
|
|
|
|
resolveParam ("", e) idx =
|
|
|
|
|
if idx < length available
|
|
|
|
|
then (available !! idx, e)
|
|
|
|
|
else error $ "interface param binding " ++ (show e)
|
|
|
|
|
++ " is out of range"
|
|
|
|
|
resolveParam other _ = other
|
|
|
|
|
|
|
|
|
|
-- given a list of module items, produces the parameters in order
|
|
|
|
|
parameters :: [ModuleItem] -> [(Identifier, Decl)]
|
|
|
|
|
parameters =
|
|
|
|
|
execWriter . mapM (collectNestedModuleItemsM $ collectDeclsM collectDeclM)
|
|
|
|
|
where
|
|
|
|
|
collectDeclM :: Decl -> Writer [(Identifier, Decl)] ()
|
|
|
|
|
collectDeclM (decl @ (Param Parameter _ x _)) = tell [(x, decl)]
|
|
|
|
|
collectDeclM (decl @ (ParamType Parameter x _)) = tell [(x, decl)]
|
|
|
|
|
collectDeclM _ = return ()
|