2019-03-07 02:30:47 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
|
|
|
|
- Conversion for interfaces
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Convert.Interface (convert) where
|
|
|
|
|
|
2019-04-23 21:46:08 +02:00
|
|
|
import Data.Maybe (fromJust, 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 Instances = Map.Map Identifier Identifier
|
|
|
|
|
type Interface = ([Identifier], [ModuleItem])
|
|
|
|
|
type Interfaces = Map.Map Identifier Interface
|
|
|
|
|
type Modports = Map.Map Identifier [ModportDecl]
|
2019-04-01 07:23:44 +02:00
|
|
|
type Modules = Map.Map (Identifier, Identifier) Type
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-04-24 00:44:45 +02:00
|
|
|
convert :: [AST] -> [AST]
|
2019-03-07 02:30:47 +01:00
|
|
|
convert descriptions =
|
2019-04-24 00:44:45 +02:00
|
|
|
map (
|
|
|
|
|
filter (not . isInterface) .
|
|
|
|
|
traverseDescriptions (convertDescription interfaces modules)
|
|
|
|
|
) descriptions
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
2019-04-01 07:23:44 +02:00
|
|
|
(interfaces, modules) =
|
2019-04-24 00:44:45 +02:00
|
|
|
execWriter $ collectDescriptionsM collectDesc $ concat descriptions
|
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) ()
|
|
|
|
|
collectDesc (orig @ (Part False kw _ name ports items)) = do
|
|
|
|
|
if kw == Interface
|
|
|
|
|
then tell (Map.singleton name (ports, items), Map.empty)
|
|
|
|
|
else collectModuleItemsM (collectDeclsM $ collectDecl name) orig
|
2019-03-07 02:30:47 +01:00
|
|
|
collectDesc _ = return ()
|
2019-04-01 07:23:44 +02:00
|
|
|
collectDecl :: Identifier -> Decl -> Writer (Interfaces, Modules) ()
|
|
|
|
|
collectDecl name (Variable _ t ident _ _) = do
|
|
|
|
|
tell (Map.empty, Map.singleton (name, ident) t)
|
|
|
|
|
collectDecl _ _ = return ()
|
2019-03-07 02:30:47 +01:00
|
|
|
isInterface :: Description -> Bool
|
2019-03-26 20:10:16 +01:00
|
|
|
isInterface (Part False Interface _ _ _ _) = True
|
2019-03-07 02:30:47 +01:00
|
|
|
isInterface _ = False
|
|
|
|
|
|
2019-04-01 07:23:44 +02:00
|
|
|
convertDescription :: Interfaces -> Modules -> Description -> Description
|
|
|
|
|
convertDescription interfaces modules (Part extern Module lifetime name ports items) =
|
2019-03-26 20:10:16 +01:00
|
|
|
Part 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
|
|
|
|
|
(collectNestedModuleItemsM collectInterface) items
|
|
|
|
|
collectInterface :: ModuleItem -> Writer (Instances, Modports) ()
|
2019-04-23 23:12:56 +02:00
|
|
|
collectInterface (MIPackageItem (Decl (Variable _ t ident _ _))) =
|
2019-03-07 03:55:27 +01:00
|
|
|
case t of
|
|
|
|
|
InterfaceT interfaceName (Just modportName) [] ->
|
|
|
|
|
tell (Map.empty, Map.singleton ident modportDecls)
|
2019-03-31 04:15:48 +02:00
|
|
|
where Just modportDecls = lookupModport Nothing interfaceName modportName
|
2019-03-07 03:55:27 +01:00
|
|
|
_ -> return ()
|
2019-03-25 23:53:55 +01:00
|
|
|
collectInterface (Instance part _ ident Nothing _) =
|
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 ()
|
2019-03-07 03:55:27 +01:00
|
|
|
collectInterface _ = return ()
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-03-07 03:55:27 +01:00
|
|
|
mapInterface :: ModuleItem -> ModuleItem
|
2019-04-23 23:12:56 +02:00
|
|
|
mapInterface (orig @ (MIPackageItem (Decl (Variable Local t ident _ _)))) =
|
2019-03-07 03:55:27 +01:00
|
|
|
case Map.lookup ident modports of
|
|
|
|
|
Just modportDecls -> Generate $
|
2019-04-23 23:12:56 +02:00
|
|
|
map (GenModuleItem . MIPackageItem . Decl . mapper)
|
|
|
|
|
modportDecls
|
2019-03-07 03:55:27 +01:00
|
|
|
Nothing -> orig
|
|
|
|
|
where
|
|
|
|
|
InterfaceT interfaceName (Just _) [] = t
|
|
|
|
|
interfaceItems = snd $ interfaces Map.! interfaceName
|
2019-04-23 21:46:08 +02:00
|
|
|
mapper (dir, port, expr) =
|
|
|
|
|
Variable dir mpt (ident ++ "_" ++ port) mprs Nothing
|
|
|
|
|
where (mpt, mprs) = lookupType interfaceItems (fromJust expr)
|
2019-03-25 23:53:55 +01:00
|
|
|
mapInterface (Instance part params ident Nothing instancePorts) =
|
2019-03-07 02:30:47 +01:00
|
|
|
case Map.lookup part interfaces of
|
|
|
|
|
Just interface ->
|
2019-04-17 07:44:03 +02:00
|
|
|
-- TODO: Add support for interfaces with parameter bindings.
|
|
|
|
|
if not $ null params
|
|
|
|
|
then error $ "interface instantiations with parameter "
|
|
|
|
|
++ "bindings are not yet supported: "
|
|
|
|
|
++ show (part, params, ident)
|
|
|
|
|
else Generate $ map GenModuleItem $
|
|
|
|
|
inlineInterface interface (ident, expandedPorts)
|
2019-03-25 23:53:55 +01:00
|
|
|
Nothing -> Instance part params ident Nothing expandedPorts
|
2019-04-01 07:23:44 +02:00
|
|
|
where expandedPorts = concatMap (expandPortBinding part) instancePorts
|
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
|
|
|
|
|
convertTF decls orig =
|
|
|
|
|
traverseExprs (traverseNestedExprs $ convertExpr its mps) $
|
|
|
|
|
traverseLHSs (traverseNestedLHSs $ convertLHS its mps) $
|
|
|
|
|
orig
|
|
|
|
|
where
|
|
|
|
|
locals = Set.fromList $ mapMaybe declVarIdent decls
|
|
|
|
|
its = Map.withoutKeys instances locals
|
|
|
|
|
mps = Map.withoutKeys modports locals
|
|
|
|
|
declVarIdent :: Decl -> Maybe Identifier
|
|
|
|
|
declVarIdent (Variable _ _ x _ _) = Just x
|
|
|
|
|
declVarIdent _ = Nothing
|
|
|
|
|
|
2019-04-01 07:23:44 +02:00
|
|
|
expandPortBinding :: Identifier -> PortBinding -> [PortBinding]
|
|
|
|
|
expandPortBinding _ (origBinding @ (portName, Just (Dot (Ident instanceName) modportName))) =
|
2019-03-07 02:30:47 +01:00
|
|
|
case Map.lookup instanceName instances of
|
2019-04-01 07:23:44 +02:00
|
|
|
Nothing ->
|
|
|
|
|
case Map.lookup instanceName modports of
|
|
|
|
|
Nothing -> [origBinding]
|
|
|
|
|
Just _ -> [(portName, Just $ Ident $ instanceName ++ "_" ++ modportName)]
|
2019-03-07 02:30:47 +01:00
|
|
|
Just interfaceName ->
|
2019-03-31 04:15:48 +02:00
|
|
|
case modportDecls of
|
|
|
|
|
Nothing -> [(portName, Just $ Ident $ instanceName ++ "_" ++ modportName)]
|
|
|
|
|
Just decls -> map mapper decls
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
2019-03-07 03:55:27 +01:00
|
|
|
modportDecls = lookupModport (Just instanceName) interfaceName modportName
|
2019-03-07 02:30:47 +01:00
|
|
|
mapper (_, x, me) = (portName ++ "_" ++ x, me)
|
2019-04-01 07:23:44 +02:00
|
|
|
expandPortBinding moduleName (origBinding @ (portName, Just (Ident instanceName))) =
|
|
|
|
|
case (instances Map.!? instanceName, modports Map.!? instanceName) of
|
|
|
|
|
(Nothing, Nothing) -> [origBinding]
|
|
|
|
|
(Just _, _) ->
|
|
|
|
|
map mapper modportDecls
|
|
|
|
|
where
|
|
|
|
|
InterfaceT interfaceName (Just modportName) [] =
|
|
|
|
|
modules Map.! (moduleName, portName)
|
|
|
|
|
Just modportDecls = lookupModport (Just instanceName) interfaceName modportName
|
|
|
|
|
mapper (_, x, me) = (portName ++ "_" ++ x, me)
|
|
|
|
|
(_, Just decls) ->
|
|
|
|
|
map mapper decls
|
|
|
|
|
where mapper (_, x, _) =
|
|
|
|
|
( portName ++ "_" ++ x
|
|
|
|
|
, Just $ Ident $ instanceName ++ "_" ++ x )
|
|
|
|
|
expandPortBinding _ other = [other]
|
2019-03-07 02:30:47 +01:00
|
|
|
|
2019-03-31 04:15:48 +02:00
|
|
|
lookupModport :: Maybe Identifier -> Identifier -> Identifier -> Maybe [ModportDecl]
|
|
|
|
|
lookupModport instanceName interfaceName = (Map.!?) modportMap
|
2019-03-07 02:30:47 +01:00
|
|
|
where
|
2019-03-07 03:55:27 +01:00
|
|
|
prefix = maybe "" (++ "_") instanceName
|
2019-03-07 02:30:47 +01:00
|
|
|
interfaceItems =
|
2019-03-07 03:55:27 +01:00
|
|
|
map (prefixModuleItems prefix) $
|
2019-03-07 02:30:47 +01:00
|
|
|
snd $ interfaces Map.! interfaceName
|
|
|
|
|
modportMap = execWriter $
|
|
|
|
|
mapM (collectNestedModuleItemsM collectModport) $
|
|
|
|
|
interfaceItems
|
|
|
|
|
collectModport :: ModuleItem -> Writer Modports ()
|
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 ()
|
|
|
|
|
|
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 its mps (LHSBit l e) =
|
|
|
|
|
LHSBit l (traverseNestedExprs (convertExpr its mps) e)
|
2019-04-05 19:53:52 +02:00
|
|
|
convertLHS its mps (LHSRange l m (e1, e2)) =
|
|
|
|
|
LHSRange l m (traverseNestedExprs (convertExpr its mps) e1, traverseNestedExprs (convertExpr its mps) e2)
|
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]
|
|
|
|
|
Just decls -> map (\(_, x, _) -> ident ++ "_" ++ x) decls
|
|
|
|
|
|
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
|
|
|
|
|
prefixModuleItems :: Identifier -> ModuleItem -> ModuleItem
|
|
|
|
|
prefixModuleItems prefix =
|
|
|
|
|
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
|
|
|
|
|
prefixDecl (Variable d t x a me) = Variable d t (prefix ++ x) a me
|
|
|
|
|
prefixDecl (Parameter t x e) = Parameter t (prefix ++ x) e
|
|
|
|
|
prefixDecl (Localparam t x e) = Localparam t (prefix ++ x) e
|
|
|
|
|
prefixExpr :: Expr -> Expr
|
|
|
|
|
prefixExpr (Ident x) = Ident (prefix ++ x)
|
|
|
|
|
prefixExpr other = other
|
|
|
|
|
prefixLHS :: LHS -> LHS
|
|
|
|
|
prefixLHS (LHSIdent x) = LHSIdent (prefix ++ x)
|
|
|
|
|
prefixLHS other = other
|
|
|
|
|
|
2019-04-23 21:46:08 +02:00
|
|
|
lookupType :: [ModuleItem] -> Expr -> (Type, [Range])
|
2019-03-07 03:55:27 +01:00
|
|
|
lookupType items (Ident ident) =
|
2019-04-23 21:46:08 +02:00
|
|
|
case mapMaybe findType items of
|
|
|
|
|
[] -> error $ "unable to locate type of " ++ ident
|
|
|
|
|
ts -> head ts
|
2019-03-07 03:55:27 +01:00
|
|
|
where
|
2019-04-23 21:46:08 +02:00
|
|
|
findType :: ModuleItem -> Maybe (Type, [Range])
|
2019-04-23 23:12:56 +02:00
|
|
|
findType (MIPackageItem (Decl (Variable _ t x rs Nothing))) =
|
2019-04-23 21:46:08 +02:00
|
|
|
if x == ident then Just (t, rs) else Nothing
|
2019-03-07 03:55:27 +01:00
|
|
|
findType _ = Nothing
|
2019-04-17 07:44:03 +02:00
|
|
|
lookupType _ expr =
|
|
|
|
|
-- TODO: Add support for non-Ident modport expressions.
|
|
|
|
|
error $ "interface conversion does not support modport expressions that "
|
|
|
|
|
++ " are not identifiers: " ++ show expr
|
2019-03-07 03:55:27 +01:00
|
|
|
|
2019-03-07 02:30:47 +01:00
|
|
|
-- convert an interface instantiation into a series of equivalent module items
|
|
|
|
|
inlineInterface :: Interface -> (Identifier, [PortBinding]) -> [ModuleItem]
|
|
|
|
|
inlineInterface (ports, items) (instanceName, instancePorts) =
|
2019-03-07 19:19:31 +01:00
|
|
|
(:) (MIPackageItem $ Comment $ "expanded instance: " ++ instanceName) $
|
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
|
|
|
|
|
prefix = instanceName ++ "_"
|
2019-04-11 20:08:50 +02:00
|
|
|
itemsPrefixed = map (prefixModuleItems prefix) $ 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
|
|
|
|
|
removeDeclDir (MIPackageItem (Decl (Variable _ t x a me))) =
|
|
|
|
|
MIPackageItem $ Decl $ Variable Local t x a me
|
|
|
|
|
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 _) =
|
|
|
|
|
MIPackageItem $ Comment $ "removed modport " ++ x
|
2019-03-07 02:30:47 +01:00
|
|
|
removeModport other = other
|
2019-04-11 20:08:50 +02:00
|
|
|
|
|
|
|
|
portBindingItem :: PortBinding -> Maybe ModuleItem
|
|
|
|
|
portBindingItem (ident, Just expr) =
|
|
|
|
|
Just $ if declDirs Map.! ident == Input
|
|
|
|
|
then Assign Nothing (LHSIdent ident) expr
|
2019-04-23 02:44:35 +02:00
|
|
|
else Assign Nothing (toLHS expr) (Ident ident)
|
2019-04-11 20:08:50 +02:00
|
|
|
portBindingItem (_, Nothing) = Nothing
|
|
|
|
|
|
|
|
|
|
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"
|