Commit 8eb3a251 by Zachary Snow

package conversion overhaul

- full import and export support
- simplify AST representation of import and export
- allow package-scoped identifiers invoked as subroutines
- use scoped name resolution for identifiers in packages
- merge package item nesting conversion into package conversion
- fix handling of colliding enum items in separate modules
- fix visiting enum item exprs in types
parent 40df9028
...@@ -102,8 +102,9 @@ Other: ...@@ -102,8 +102,9 @@ Other:
## Supported Features ## Supported Features
sv2v supports most synthesizable SystemVerilog features. Current notable sv2v supports most synthesizable SystemVerilog features. Current notable
exceptions include `export` and interface arrays. Assertions are also supported, exceptions include `defparam` on interface instances and references to typedefs
but are simply dropped during conversion. within interface instances. Assertions are also supported, but are simply
dropped during conversion.
If you find a bug or have a feature request, please create an issue. Preference If you find a bug or have a feature request, please create an issue. Preference
will be given to issues which include examples or test cases. will be given to issues which include examples or test cases.
......
...@@ -31,7 +31,6 @@ import qualified Convert.Logic ...@@ -31,7 +31,6 @@ import qualified Convert.Logic
import qualified Convert.LogOp import qualified Convert.LogOp
import qualified Convert.MultiplePacked import qualified Convert.MultiplePacked
import qualified Convert.NamedBlock import qualified Convert.NamedBlock
import qualified Convert.NestPI
import qualified Convert.Package import qualified Convert.Package
import qualified Convert.ParamNoDefault import qualified Convert.ParamNoDefault
import qualified Convert.ParamType import qualified Convert.ParamType
...@@ -86,9 +85,7 @@ phases excludes = ...@@ -86,9 +85,7 @@ phases excludes =
, Convert.Unsigned.convert , Convert.Unsigned.convert
, Convert.SignCast.convert , Convert.SignCast.convert
, Convert.Wildcard.convert , Convert.Wildcard.convert
, Convert.Package.convert
, Convert.Enum.convert , Convert.Enum.convert
, Convert.NestPI.convert
, Convert.ForDecl.convert , Convert.ForDecl.convert
, Convert.Jump.convert , Convert.Jump.convert
, Convert.Foreach.convert , Convert.Foreach.convert
...@@ -111,7 +108,7 @@ run excludes = foldr (.) id $ phases excludes ...@@ -111,7 +108,7 @@ run excludes = foldr (.) id $ phases excludes
convert :: [Job.Exclude] -> Phase convert :: [Job.Exclude] -> Phase
convert excludes = convert excludes =
convert' convert'
. Convert.NestPI.reorder . Convert.Package.convert
. Convert.ParamNoDefault.convert . Convert.ParamNoDefault.convert
where where
convert' :: Phase convert' :: Phase
......
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
- -
- Conversion for `enum` - Conversion for `enum`
- -
- This conversion replaces the enum items with localparams declared at the - This conversion replaces the enum items with localparams. The localparams are
- global scope. We leave it to the package item nesting conversion to determine - explicitly sized to match the size of the converted enum type. For packages
- where the generated localparams are needed. The localparams are explicitly - and enums used in the global scope, these localparams are inserted in place.
- sized to match the size of the converted enum type. - For enums used within a module or interface, the localparams are injected as
- needed using a nesting procedure from the package conversion.
- -
- SystemVerilog allows for enums to have any number of the items' values - SystemVerilog allows for enums to have any number of the items' values
- specified or unspecified. If the first one is unspecified, it is 0. All other - specified or unspecified. If the first one is unspecified, it is 0. All other
...@@ -24,6 +25,7 @@ import Data.List (elemIndices) ...@@ -24,6 +25,7 @@ import Data.List (elemIndices)
import qualified Data.Set as Set import qualified Data.Set as Set
import Convert.ExprUtils import Convert.ExprUtils
import Convert.Package (inject)
import Convert.Traverse import Convert.Traverse
import Language.SystemVerilog.AST import Language.SystemVerilog.AST
...@@ -36,9 +38,14 @@ convert = map $ concatMap convertDescription ...@@ -36,9 +38,14 @@ convert = map $ concatMap convertDescription
convertDescription :: Description -> [Description] convertDescription :: Description -> [Description]
convertDescription (Package ml name items) = convertDescription (Package ml name items) =
[Package ml name $ concatMap convertPackageItem items] [Package ml name $ concatMap convertPackageItem items]
convertDescription description = convertDescription (description @ Part{}) =
(map PackageItem enumItems) ++ [description'] [Part attrs extern kw lifetime name ports items']
where (description', enumItems) = convertDescription' description where
items' = inject enumItems items -- only keep what's used
Part attrs extern kw lifetime name ports items = description'
(description', enumItems) = convertDescription' description
convertDescription (PackageItem item) =
map PackageItem $ convertPackageItem item
-- explode a package item with its corresponding enum items -- explode a package item with its corresponding enum items
convertPackageItem :: PackageItem -> [PackageItem] convertPackageItem :: PackageItem -> [PackageItem]
......
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for moving top-level package items into modules
-}
module Convert.NestPI (convert, reorder) where
import Control.Monad.Writer.Strict
import Data.Maybe (mapMaybe)
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Convert.Traverse
import Language.SystemVerilog.AST
type PIs = Map.Map Identifier PackageItem
type Idents = Set.Set Identifier
convert :: [AST] -> [AST]
convert =
map (filter (not . isPI)) . nest
where
nest :: [AST] -> [AST]
nest = traverseFiles
(collectDescriptionsM collectDescriptionM)
(traverseDescriptions . convertDescription)
isPI :: Description -> Bool
isPI (PackageItem Import{}) = False
isPI (PackageItem item) = piName item /= ""
isPI _ = False
reorder :: [AST] -> [AST]
reorder = map $ traverseDescriptions reorderDescription
-- collects packages items missing
collectDescriptionM :: Description -> Writer PIs ()
collectDescriptionM (PackageItem item) = do
case piName item of
"" -> return ()
ident -> tell $ Map.singleton ident item
collectDescriptionM _ = return ()
-- nests packages items missing from modules
convertDescription :: PIs -> Description -> Description
convertDescription pis (orig @ Part{}) =
if Map.null pis
then orig
else Part attrs extern kw lifetime name ports items'
where
Part attrs extern kw lifetime name ports items = orig
items' = addItems pis Set.empty (map addUsedPIs items)
convertDescription _ other = other
-- attempt to fix simple declaration order issues
reorderDescription :: Description -> Description
reorderDescription (Part attrs extern kw lifetime name ports items) =
Part attrs extern kw lifetime name ports items'
where
items' = addItems localPIs Set.empty (map addUsedPIs items)
localPIs = Map.fromList $ mapMaybe toPIElem items
toPIElem :: ModuleItem -> Maybe (Identifier, PackageItem)
toPIElem (MIPackageItem item) = Just (piName item, item)
toPIElem _ = Nothing
reorderDescription other = other
-- iteratively inserts missing package items exactly where they are needed
addItems :: PIs -> Idents -> [(ModuleItem, Idents)] -> [ModuleItem]
addItems pis existingPIs ((item, usedPIs) : items) =
if not $ Set.disjoint existingPIs thisPI then
-- this item was re-imported earlier in the module
addItems pis existingPIs items
else if null itemsToAdd then
-- this item has no additional dependencies
item : addItems pis (Set.union existingPIs thisPI) items
else
-- this item has at least one un-met dependency
addItems pis existingPIs (addUsedPIs chosen : (item, usedPIs) : items)
where
thisPI = execWriter $ collectPIsM item
neededPIs = Set.difference (Set.difference usedPIs existingPIs) thisPI
itemsToAdd = map MIPackageItem $ Map.elems $
Map.restrictKeys pis neededPIs
chosen = head itemsToAdd
addItems _ _ [] = []
-- augment a module item with the set of identifiers it uses
addUsedPIs :: ModuleItem -> (ModuleItem, Idents)
addUsedPIs item =
(item, usedPIs)
where
usedPIs = execWriter $
traverseNestedModuleItemsM (traverseIdentsM writeIdent) item
writeIdent :: Identifier -> Writer Idents Identifier
writeIdent x = tell (Set.singleton x) >> return x
-- writes down the names of package items
collectPIsM :: ModuleItem -> Writer Idents ()
collectPIsM (MIPackageItem item) =
case piName item of
"" -> return ()
ident -> tell $ Set.singleton ident
collectPIsM _ = return ()
-- visits all identifiers in a module item
traverseIdentsM :: Monad m => MapperM m Identifier -> MapperM m ModuleItem
traverseIdentsM identMapper = traverseNodesM
(traverseExprIdentsM identMapper)
(traverseDeclIdentsM identMapper)
(traverseTypeIdentsM identMapper)
(traverseLHSIdentsM identMapper)
(traverseStmtIdentsM identMapper)
-- visits all identifiers in an expression
traverseExprIdentsM :: Monad m => MapperM m Identifier -> MapperM m Expr
traverseExprIdentsM identMapper = fullMapper
where
fullMapper = exprMapper >=> traverseSinglyNestedExprsM fullMapper
exprMapper (Call (Ident x) args) =
identMapper x >>= \x' -> return $ Call (Ident x') args
exprMapper (Ident x) = identMapper x >>= return . Ident
exprMapper other = return other
-- visits all identifiers in a type
traverseTypeIdentsM :: Monad m => MapperM m Identifier -> MapperM m Type
traverseTypeIdentsM identMapper = fullMapper
where
fullMapper = typeMapper
>=> traverseTypeExprsM (traverseExprIdentsM identMapper)
>=> traverseSinglyNestedTypesM fullMapper
typeMapper (Alias x t) = aliasHelper (Alias ) x t
typeMapper (PSAlias p x t) = aliasHelper (PSAlias p ) x t
typeMapper (CSAlias c p x t) = aliasHelper (CSAlias c p) x t
typeMapper other = return other
aliasHelper constructor x t =
identMapper x >>= \x' -> return $ constructor x' t
-- visits all identifiers in an LHS
traverseLHSIdentsM :: Monad m => MapperM m Identifier -> MapperM m LHS
traverseLHSIdentsM identMapper = fullMapper
where
fullMapper = lhsMapper
>=> traverseLHSExprsM (traverseExprIdentsM identMapper)
>=> traverseSinglyNestedLHSsM fullMapper
lhsMapper (LHSIdent x) = identMapper x >>= return . LHSIdent
lhsMapper other = return other
-- visits all identifiers in a statement
traverseStmtIdentsM :: Monad m => MapperM m Identifier -> MapperM m Stmt
traverseStmtIdentsM identMapper = fullMapper
where
fullMapper = stmtMapper
>=> traverseStmtExprsM (traverseExprIdentsM identMapper)
>=> traverseStmtLHSsM (traverseLHSIdentsM identMapper)
>=> traverseSinglyNestedStmtsM fullMapper
stmtMapper (Subroutine (Ident x) args) =
identMapper x >>= \x' -> return $ Subroutine (Ident x') args
stmtMapper other = return other
-- visits all identifiers in a declaration
traverseDeclIdentsM :: Monad m => MapperM m Identifier -> MapperM m Decl
traverseDeclIdentsM identMapper =
traverseDeclExprsM (traverseExprIdentsM identMapper) >=>
traverseDeclTypesM (traverseTypeIdentsM identMapper)
-- returns the "name" of a package item, if it has one
piName :: PackageItem -> Identifier
piName (Function _ _ ident _ _) = ident
piName (Task _ ident _ _) = ident
piName (Typedef _ ident ) = ident
piName (Decl (Variable _ _ ident _ _)) = ident
piName (Decl (Param _ _ ident _)) = ident
piName (Decl (ParamType _ ident _)) = ident
piName (Decl (CommentDecl _)) = ""
piName (Import x y) = show $ Import x y
piName (Export _) = ""
piName (Directive _) = ""
{-# LANGUAGE TupleSections #-}
{- sv2v {- sv2v
- Author: Zachary Snow <zach@zachjs.com> - Author: Zachary Snow <zach@zachjs.com>
- -
- Conversion for packages, exports, and imports - Conversion for packages and global declarations
- -
- TODO: We do not yet handle exports. - This conversion first makes a best-effort pass at resolving any simple
- TODO: The scoping rules are not being entirely followed yet. - declaration ordering issues in the input. Many conversions require that
- TODO: Explicit imports may introduce name conflicts because of carried items. - declarations precede their first usage.
- -
- The SystemVerilog scoping rules for exports and imports are not entirely - The main phase elaborates packages and resolves imported identifiers. An
- trivial. We do not explicitly handle the "error" scenarios detailed Table - identifier (perhaps implicitly) referring to `P::X` is rewritten to `P_X`.
- 26-1 of Section 26-3 of IEEE 1800-2017. Users generally shouldn't be relying - This conversion assumes such renaming will not cause conflicts. The full
- on this tool to catch and report such wild naming conflicts that are outlined - semantics of imports and exports are followed.
- there.
- -
- Summary: - Finally, because Verilog doesn't allow declarations to exist outside of
- * In scopes which have a local declaration of an identifier, that identifier - modules, declarations within packages and in the global scope are injected
- refers to that local declaration. - into modules and interfaces as needed.
- * If there is no local declaration, the identifier refers to the imported
- declaration.
- * If there is an explicit import of that identifier, the identifier refers to
- the imported declaration.
- * Usages of conflicting wildcard imports are not allowed.
-} -}
module Convert.Package (convert) where module Convert.Package
( convert
, inject
) where
import Control.Monad.State.Strict import Control.Monad.State.Strict
import Control.Monad.Writer.Strict import Control.Monad.Writer.Strict
import Data.List (insert, intercalate)
import Data.Maybe (mapMaybe)
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import qualified Data.Set as Set import qualified Data.Set as Set
...@@ -34,112 +34,296 @@ import Convert.Scoper ...@@ -34,112 +34,296 @@ import Convert.Scoper
import Convert.Traverse import Convert.Traverse
import Language.SystemVerilog.AST import Language.SystemVerilog.AST
type Packages = Map.Map Identifier PackageItems type Packages = Map.Map Identifier Package
type PackageItems = [(Identifier, PackageItem)] type Package = (IdentStateMap, [PackageItem])
type Idents = Set.Set Identifier type Idents = Set.Set Identifier
type PIs = Map.Map Identifier PackageItem
convert :: [AST] -> [AST] convert :: [AST] -> [AST]
convert = step convert files =
map (traverseDescriptions $ convertDescription pis) files'
where where
step :: [AST] -> [AST] (files', packages') = convertPackages files
step curr = pis = Map.fromList $
if next == curr concatMap (concatMap toPackageItems . snd) $
then curr filter (not . Map.null . fst) $
else step next Map.elems packages'
toPackageItems :: PackageItem -> [(Identifier, PackageItem)]
toPackageItems item = map (, item) (piNames item)
-- utility for inserting package items into a set of module items as needed
inject :: [PackageItem] -> [ModuleItem] -> [ModuleItem]
inject packageItems items =
addItems localPIs Set.empty (map addUsedPIs items)
where
localPIs = Map.fromList $ concatMap toPIElem packageItems
toPIElem :: PackageItem -> [(Identifier, PackageItem)]
toPIElem item = map (, item) (piNames item)
-- collect packages and global package items
collectPackageM :: Description -> Writer (Packages, [PackageItem]) ()
collectPackageM (PackageItem item) =
when (not $ null $ piNames item) $
tell (Map.empty, [item])
collectPackageM (Package _ name items) =
tell (Map.singleton name (Map.empty, items), [])
collectPackageM _ = return ()
-- elaborate all packages and their usages
convertPackages :: [AST] -> ([AST], Packages)
convertPackages files =
(files', packages')
where where
next = traverseFiles (files', ([], packages')) = runState op ([], packages)
(collectDescriptionsM collectDescriptionM) op = mapM (traverseDescriptionsM traverseDescriptionM) files
convertFile curr packages = Map.insert "" (Map.empty, globalItems) realPackages
(realPackages, globalItems) =
convertFile :: Packages -> AST -> AST execWriter $ mapM (collectDescriptionsM collectPackageM) files
convertFile packages ast =
(++) globalItems $ type PackagesState = State ([Identifier], Packages)
filter (not . isCollected) $
concatMap (traverseDescription packages) $ traverseDescriptionM :: Description -> PackagesState Description
ast traverseDescriptionM (PackageItem item) = do
return $ PackageItem $ case piNames item of
[] -> item
idents -> Decl $ CommentDecl $ "removed " ++ show idents
traverseDescriptionM (Package _ name _) =
return $ PackageItem $ Decl $ CommentDecl $ "removed package " ++ show name
traverseDescriptionM (Part attrs extern kw liftetime name ports items) = do
(_, items') <- processItems name "" items
return $ Part attrs extern kw liftetime name ports items'
data IdentState
= Available [Identifier]
| Imported Identifier
| Declared
deriving Eq
isImported :: IdentState -> Bool
isImported Imported{} = True
isImported _ = False
isDeclared :: IdentState -> Bool
isDeclared Declared{} = True
isDeclared _ = False
type IdentStateMap = Map.Map Identifier IdentState
type Scope = ScoperT IdentState PackagesState
-- produce the partial mapping for a particular export and ensure its validity
resolveExport
:: IdentStateMap -> Identifier -> Identifier -> PackagesState IdentStateMap
resolveExport mapping "" "" =
return $ Map.filter isImported mapping
resolveExport mapping pkg "" =
fmap (Map.mapMaybeWithKey checkExport . fst) (findPackage pkg)
where where
globalItems = map PackageItem $ checkExport :: Identifier -> IdentState -> Maybe IdentState
concatMap (uncurry globalPackageItems) $ Map.toList packages checkExport ident exportedIdentState =
isCollected :: Description -> Bool if localIdentState == expectedIdentState
isCollected (Package _ name _) = Map.member name packages then localIdentState
isCollected _ = False else Nothing
globalPackageItems :: Identifier -> PackageItems -> [PackageItem]
globalPackageItems name items =
prefixPackageItems name (packageItemIdents items) (map snd items)
packageItemIdents :: PackageItems -> Idents
packageItemIdents items =
Set.union
(Set.fromList $ map fst items)
(Set.unions $ map (packageItemSubIdents . snd) items)
where where
packageItemSubIdents :: PackageItem -> Idents localIdentState = Map.lookup ident mapping
packageItemSubIdents (Typedef (Enum _ enumItems _) _) = expectedIdentState = Just $ Imported $
Set.fromList $ map fst enumItems toRootPackage pkg exportedIdentState
packageItemSubIdents _ = Set.empty resolveExport mapping pkg ident =
case Map.lookup ident mapping of
prefixPackageItems :: Identifier -> Idents -> [PackageItem] -> [PackageItem] Just (Imported importedPkg) -> do
prefixPackageItems packageName idents items = exportedPkg <- resolveRootPackage pkg ident
map unwrap $ evalScoper if importedPkg == exportedPkg
then return $ Map.singleton ident $ Imported importedPkg
else error $ "export of " ++ pkg ++ "::" ++ ident
++ " differs from import of " ++ importedPkg
++ "::" ++ ident
_ -> error $ "export of " ++ pkg ++ "::" ++ ident
++ ", but " ++ ident ++ " was never imported"
-- lookup the state of the identifier only within the current scope
lookupLocalIdentState :: Identifier -> Scope (Maybe IdentState)
lookupLocalIdentState =
fmap (fmap thd3) . lookupLocalIdentM
where thd3 (_, _, c) = c
-- make a particular identifier within a package available for import
wildcardImport :: Identifier -> Identifier -> Scope ()
wildcardImport pkg ident = do
rootPkg <- lift $ resolveRootPackage pkg ident
maybeIdentState <- lookupLocalIdentState ident
insertElem ident $
case maybeIdentState of
Nothing -> Available [rootPkg]
Just Declared -> Declared
Just (Imported existingRootPkg) -> Imported existingRootPkg
Just (Available rootPkgs) ->
if elem rootPkg rootPkgs
then Available rootPkgs
else Available $ insert rootPkg rootPkgs
-- make all exported identifiers within a package available for import
wildcardImports :: Identifier -> Scope ()
wildcardImports pkg = do
(exports, _) <- lift $ findPackage pkg
_ <- mapM (wildcardImport pkg) (Map.keys exports)
return ()
-- resolve and store an explicit (non-wildcard) import
explicitImport :: Identifier -> Identifier -> Scope ()
explicitImport pkg ident = do
rootPkg <- lift $ resolveRootPackage pkg ident
maybeIdentState <- lookupLocalIdentState ident
insertElem ident $
case maybeIdentState of
Nothing -> Imported rootPkg
Just Declared ->
error $ "import of " ++ pkg ++ "::" ++ ident
++ " conflicts with prior declaration of " ++ ident
Just Available{} -> Imported rootPkg
Just (Imported otherPkg) ->
if otherPkg == rootPkg
then Imported rootPkg
else error $ "import of " ++ pkg ++ "::" ++ ident
++ " conflicts with prior import of "
++ otherPkg ++ "::" ++ ident
-- main logic responsible for translating packages, resolving imports and
-- exports, and rewriting identifiers referring to package declarations
processItems :: Identifier -> Identifier -> [ModuleItem]
-> PackagesState (IdentStateMap, [ModuleItem])
processItems topName packageName moduleItems = do
(moduleItems', scopes) <- runScoperT
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
packageName $ map (wrap . initialPrefix) items topName (reorderItems moduleItems)
let rawIdents = extractMapping scopes
externalIdentMaps <- mapM (resolveExportMI rawIdents) moduleItems
let externalIdents = Map.unions externalIdentMaps
let declaredIdents = Map.filter isDeclared rawIdents
let exports = Map.union declaredIdents externalIdents
let exports' = if null packageName
then rawIdents
else exports
seq exports return (exports', moduleItems')
where where
wrap :: PackageItem -> ModuleItem -- produces partial mappings of exported identifiers, while also
wrap = MIPackageItem -- checking the validity of the exports
unwrap :: ModuleItem -> PackageItem resolveExportMI :: IdentStateMap -> ModuleItem -> PackagesState IdentStateMap
unwrap (MIPackageItem item) = item resolveExportMI mapping (MIPackageItem (item @ (Export pkg ident))) =
unwrap _ = error "unwrap invariant violated" if null packageName
then error $ "invalid " ++ (init $ show item)
initialPrefix :: PackageItem -> PackageItem ++ " outside of package"
initialPrefix item = else resolveExport mapping pkg ident
case item of resolveExportMI _ _ = return Map.empty
Function a b x c d -> Function a b (prefix x) c d
Task a x c d -> Task a (prefix x) c d -- declare an identifier, prefixing it if within a package
Typedef a x -> Typedef a (prefix x) prefixIdent :: Identifier -> Scope Identifier
Decl (Variable a b x c d) -> Decl (Variable a b (prefix x) c d) prefixIdent x = do
Decl (Param a b x c ) -> Decl (Param a b (prefix x) c ) inProcedure <- withinProcedureM
Decl (ParamType a x b ) -> Decl (ParamType a (prefix x) b ) maybeIdentState <- lookupLocalIdentState x
other -> other case maybeIdentState of
Just (Imported rootPkg) -> error $ "declaration of " ++ x
prefix :: Identifier -> Identifier ++ " conflicts with prior import of " ++ rootPkg
prefix x = ++ "::" ++ x
if Set.member x idents _ -> do
then packageName ++ '_' : x insertElem x Declared
else x if inProcedure || null packageName
prefixM :: Identifier -> Scoper () Identifier then return x
prefixM x = do else return $ packageName ++ '_' : x
-- check the global scope for declarations or imports
resolveGlobalIdent :: Identifier -> Scope Identifier
resolveGlobalIdent x = do
(exports, _) <- lift $ findPackage ""
case Map.lookup x exports of
Nothing -> return x
Just identState -> do
-- inject the exact state outside of the module scope,
-- allowing wildcard imports to be handled correctly
insertElem [Access x Nil] identState
resolveIdent x
-- remap an identifier if needed based on declarations, explicit
-- imports, or names available for import
resolveIdent :: Identifier -> Scope Identifier
resolveIdent x = do
details <- lookupElemM x details <- lookupElemM x
if details == Nothing case details of
then return $ prefix x Nothing ->
else return x if null topName
then return x
else resolveGlobalIdent x
Just ([_, _], _, Declared) ->
if null packageName
then return x
else return $ packageName ++ '_' : x
Just (_, _, Declared) -> return x
Just (_, _, Imported rootPkg) ->
return $ rootPkg ++ '_' : x
Just (accesses, _, Available [rootPkg]) -> do
insertElem accesses $ Imported rootPkg
return $ rootPkg ++ '_' : x
Just (_, _, Available rootPkgs) ->
error $ "identifier " ++ show x
++ " ambiguously refers to the definitions in any of "
++ intercalate ", " rootPkgs
traversePackageItemM :: PackageItem -> Scope PackageItem
-- TODO: fold this in with type parameters
traversePackageItemM (Typedef t x) = do
t' <- traverseTypeM t
x' <- prefixIdent x
t'' <- traverseNestedTypesM (traverseTypeExprsM traverseExprM) t'
return $ Typedef t'' x'
traversePackageItemM (orig @ (Import pkg ident)) = do
if null ident
then wildcardImports pkg
else explicitImport pkg ident
return $ Decl $ CommentDecl $ "removed " ++ show orig
traversePackageItemM (orig @ (Export pkg ident)) = do
() <- when (not (null pkg || null ident)) $ do
localName <- resolveIdent ident
rootPkg <- lift $ resolveRootPackage pkg ident
localName `seq` rootPkg `seq` return ()
return $ Decl $ CommentDecl $ "removed " ++ show orig
traversePackageItemM other = return other
traverseDeclM :: Decl -> Scoper () Decl traverseDeclM :: Decl -> Scope Decl
traverseDeclM decl = do traverseDeclM decl = do
case decl of decl' <- case decl of
Variable _ _ x _ _ -> insertElem x () Variable d t x a e -> declHelp x $ \x' -> Variable d t x' a e
Param _ _ x _ -> insertElem x () Param p t x e -> declHelp x $ \x' -> Param p t x' e
ParamType _ x _ -> insertElem x () ParamType p x t -> declHelp x $ \x' -> ParamType p x' t
CommentDecl{} -> return () CommentDecl c -> return $ CommentDecl c
traverseDeclTypesM traverseTypeM decl >>= traverseDeclTypesM traverseTypeM decl' >>=
traverseDeclExprsM traverseExprM traverseDeclExprsM traverseExprM
where declHelp x f = prefixIdent x >>= return . f
traverseTypeM :: Type -> Scoper () Type traverseTypeM :: Type -> Scope Type
traverseTypeM (PSAlias p x rs) = do
x' <- lift $ resolvePSIdent p x
return $ Alias x' rs
traverseTypeM (Alias x rs) = traverseTypeM (Alias x rs) =
prefixM x >>= \x' -> return $ Alias x' rs resolveIdent x >>= \x' -> return $ Alias x' rs
traverseTypeM (Enum t enumItems rs) = do traverseTypeM (Enum t enumItems rs) = do
enumItems' <- mapM prefixEnumItem enumItems enumItems' <- mapM prefixEnumItem enumItems
return $ Enum t enumItems' rs return $ Enum t enumItems' rs
where prefixEnumItem (x, e) = prefixM x >>= \x' -> return (x', e) where prefixEnumItem (x, e) = prefixIdent x >>= \x' -> return (x', e)
traverseTypeM other = traverseSinglyNestedTypesM traverseTypeM other traverseTypeM other = traverseSinglyNestedTypesM traverseTypeM other
traverseExprM (Ident x) = prefixM x >>= return . Ident traverseExprM (PSIdent p x) = do
x' <- lift $ resolvePSIdent p x
return $ Ident x'
traverseExprM (Ident x) = resolveIdent x >>= return . Ident
traverseExprM other = traverseSinglyNestedExprsM traverseExprM other traverseExprM other = traverseSinglyNestedExprsM traverseExprM other
traverseLHSM (LHSIdent x) = prefixM x >>= return . LHSIdent traverseLHSM (LHSIdent x) = resolveIdent x >>= return . LHSIdent
traverseLHSM other = traverseSinglyNestedLHSsM traverseLHSM other traverseLHSM other = traverseSinglyNestedLHSsM traverseLHSM other
traverseGenItemM = error "not possible" traverseGenItemM = traverseGenItemExprsM traverseExprM
traverseModuleItemM = traverseModuleItemM (MIPackageItem item) = do
item' <- traversePackageItemM item
return $ MIPackageItem item'
traverseModuleItemM other =
traverseModuleItemM' other
traverseModuleItemM' =
traverseTypesM traverseTypeM >=> traverseTypesM traverseTypeM >=>
traverseExprsM traverseExprM >=> traverseExprsM traverseExprM >=>
traverseLHSsM traverseLHSM traverseLHSsM traverseLHSM
...@@ -147,84 +331,200 @@ prefixPackageItems packageName idents items = ...@@ -147,84 +331,200 @@ prefixPackageItems packageName idents items =
traverseStmtExprsM traverseExprM >=> traverseStmtExprsM traverseExprM >=>
traverseStmtLHSsM traverseLHSM traverseStmtLHSsM traverseLHSM
collectDescriptionM :: Description -> Writer Packages () -- locate a package by name, processing its contents if necessary
collectDescriptionM (Package _ name items) = findPackage :: Identifier -> PackagesState Package
if any isImport items findPackage packageName = do
then return () (stack, packages) <- get
else tell $ Map.singleton name itemList let maybePackage = Map.lookup packageName packages
assertMsg (maybePackage /= Nothing) $
"could not find package " ++ show packageName
-- because this conversion doesn't enforce declaration ordering of packages,
-- it must check for dependency loops to avoid infinite recursion
let first : rest = reverse $ packageName : stack
assertMsg (not $ elem packageName stack) $
"package dependency loop: " ++ show first ++ " depends on "
++ intercalate ", which depends on " (map show rest)
let Just (package @ (exports, _))= maybePackage
if Map.null exports
then do
-- process and resolve this package
put (packageName : stack, packages)
package' <- processPackage packageName $ snd package
packages' <- gets snd
put (stack, Map.insert packageName package' packages')
return package'
else return package
-- helper for elaborating a package when it is first referenced
processPackage :: Identifier -> [PackageItem] -> PackagesState Package
processPackage packageName packageItems = do
(exports, moduleItems') <- processItems packageName packageName wrapped
let packageItems' = map unwrap moduleItems'
let package' = (exports, packageItems')
return package'
where
wrapped = map wrap packageItems
wrap :: PackageItem -> ModuleItem
wrap = MIPackageItem
unwrap :: ModuleItem -> PackageItem
unwrap packageItem = item
where MIPackageItem item = packageItem
-- resolve a package scoped identifier to its unique global name
resolvePSIdent :: Identifier -> Identifier -> PackagesState Identifier
resolvePSIdent packageName itemName = do
rootPkg <- resolveRootPackage packageName itemName
return $ rootPkg ++ '_' : itemName
-- determines the root package contained the given package scoped identifier
resolveRootPackage :: Identifier -> Identifier -> PackagesState Identifier
resolveRootPackage packageName itemName = do
(exports, _) <- findPackage packageName
let maybeIdentState = Map.lookup itemName exports
assertMsg (maybeIdentState /= Nothing) $
"could not find " ++ show itemName ++ " in package " ++ show packageName
let Just identState = maybeIdentState
return $ toRootPackage packageName identState
-- errors with the given message when the check is false
assertMsg :: Monad m => Bool -> String -> m ()
assertMsg check msg = when (not check) $ error msg
-- helper for taking an ident which is either declared or exported form a
-- package and determine its true root source package
toRootPackage :: Identifier -> IdentState -> Identifier
toRootPackage sourcePackage identState =
if identState == Declared
then sourcePackage
else rootPackage
where Imported rootPackage = identState
-- nests packages items missing from modules
convertDescription :: PIs -> Description -> Description
convertDescription pis (orig @ Part{}) =
if Map.null pis
then orig
else Part attrs extern kw lifetime name ports items'
where
Part attrs extern kw lifetime name ports items = orig
items' = addItems pis Set.empty (map addUsedPIs items)
convertDescription _ other = other
-- attempt to fix simple declaration order issues
reorderItems :: [ModuleItem] -> [ModuleItem]
reorderItems items =
addItems localPIs Set.empty (map addUsedPIs items)
where where
itemList = concatMap toPackageItems items localPIs = Map.fromList $ concat $ mapMaybe toPIElem items
toPackageItems :: PackageItem -> PackageItems toPIElem :: ModuleItem -> Maybe [(Identifier, PackageItem)]
toPackageItems item = toPIElem (MIPackageItem item) = Just $ map (, item) (piNames item)
case piName item of toPIElem _ = Nothing
"" -> []
x -> [(x, item)] -- iteratively inserts missing package items exactly where they are needed
isImport :: PackageItem -> Bool addItems :: PIs -> Idents -> [(ModuleItem, Idents)] -> [ModuleItem]
isImport (Import _ _) = True addItems pis existingPIs ((item, usedPIs) : items) =
isImport _ = False if not $ Set.disjoint existingPIs thisPI then
collectDescriptionM _ = return () -- this item was re-imported earlier in the module
addItems pis existingPIs items
traverseDescription :: Packages -> Description -> [Description] else if null itemsToAdd then
traverseDescription packages (PackageItem (Import x y)) = -- this item has no additional dependencies
map (\(MIPackageItem item) -> PackageItem item) items item : addItems pis (Set.union existingPIs thisPI) items
else
-- this item has at least one un-met dependency
addItems pis existingPIs (addUsedPIs chosen : (item, usedPIs) : items)
where where
orig = Part [] False Module Inherit "DNE" [] thisPI = case item of
[MIPackageItem $ Import x y] MIPackageItem packageItem ->
[orig'] = traverseDescription packages orig Set.fromList $ piNames packageItem
Part [] False Module Inherit "DNE" [] items = orig' _ -> Set.empty
traverseDescription packages description = neededPIs = Set.difference (Set.difference usedPIs existingPIs) thisPI
[description'] itemsToAdd = map MIPackageItem $ Map.elems $
Map.restrictKeys pis neededPIs
chosen = head itemsToAdd
addItems _ _ [] = []
-- augment a module item with the set of identifiers it uses
addUsedPIs :: ModuleItem -> (ModuleItem, Idents)
addUsedPIs item =
(item, usedPIs)
where where
description' = traverseModuleItems usedPIs = execWriter $
(traverseModuleItem existingItemNames packages) traverseNestedModuleItemsM (traverseIdentsM writeIdent) item
description writeIdent :: Identifier -> Writer Idents Identifier
existingItemNames = execWriter $ writeIdent x = tell (Set.singleton x) >> return x
collectModuleItemsM writePIName description
writePIName :: ModuleItem -> Writer Idents () -- visits all identifiers in a module item
writePIName (MIPackageItem (Import _ (Just x))) = traverseIdentsM :: Monad m => MapperM m Identifier -> MapperM m ModuleItem
tell $ Set.singleton x traverseIdentsM identMapper = traverseNodesM
writePIName (MIPackageItem item) = (traverseExprIdentsM identMapper)
case piName item of (traverseDeclIdentsM identMapper)
"" -> return () (traverseTypeIdentsM identMapper)
x -> tell $ Set.singleton x (traverseLHSIdentsM identMapper)
writePIName _ = return () (traverseStmtIdentsM identMapper)
traverseModuleItem :: Idents -> Packages -> ModuleItem -> ModuleItem -- visits all identifiers in an expression
traverseModuleItem existingItemNames packages (MIPackageItem (Import x y)) = traverseExprIdentsM :: Monad m => MapperM m Identifier -> MapperM m Expr
if Map.member x packages traverseExprIdentsM identMapper = fullMapper
then Generate $ map (GenModuleItem . MIPackageItem) itemsRenamed
else MIPackageItem $ Import x y
where where
packageItems = packages Map.! x fullMapper = exprMapper >=> traverseSinglyNestedExprsM fullMapper
namesToAvoid = case y of exprMapper (Call (Ident x) args) =
Nothing -> existingItemNames identMapper x >>= \x' -> return $ Call (Ident x') args
Just ident -> Set.delete ident existingItemNames exprMapper (Ident x) = identMapper x >>= return . Ident
itemsRenamed = exprMapper other = return other
prefixPackageItems x namesToAvoid
(map snd packageItems) -- visits all identifiers in a type
traverseModuleItem _ _ item = traverseTypeIdentsM :: Monad m => MapperM m Identifier -> MapperM m Type
(traverseExprs $ traverseNestedExprs traverseExpr) $ traverseTypeIdentsM identMapper = fullMapper
(traverseTypes $ traverseNestedTypes traverseType) $
item
where where
fullMapper = typeMapper
>=> traverseTypeExprsM (traverseExprIdentsM identMapper)
>=> traverseSinglyNestedTypesM fullMapper
typeMapper (Alias x t) = aliasHelper (Alias ) x t
typeMapper (PSAlias p x t) = aliasHelper (PSAlias p ) x t
typeMapper (CSAlias c p x t) = aliasHelper (CSAlias c p) x t
typeMapper other = return other
aliasHelper constructor x t =
identMapper x >>= \x' -> return $ constructor x' t
-- visits all identifiers in an LHS
traverseLHSIdentsM :: Monad m => MapperM m Identifier -> MapperM m LHS
traverseLHSIdentsM identMapper = fullMapper
where
fullMapper = lhsMapper
>=> traverseLHSExprsM (traverseExprIdentsM identMapper)
>=> traverseSinglyNestedLHSsM fullMapper
lhsMapper (LHSIdent x) = identMapper x >>= return . LHSIdent
lhsMapper other = return other
-- visits all identifiers in a statement
traverseStmtIdentsM :: Monad m => MapperM m Identifier -> MapperM m Stmt
traverseStmtIdentsM identMapper = fullMapper
where
fullMapper = stmtMapper
>=> traverseStmtExprsM (traverseExprIdentsM identMapper)
>=> traverseStmtLHSsM (traverseLHSIdentsM identMapper)
>=> traverseSinglyNestedStmtsM fullMapper
stmtMapper (Subroutine (Ident x) args) =
identMapper x >>= \x' -> return $ Subroutine (Ident x') args
stmtMapper other = return other
-- visits all identifiers in a declaration
traverseDeclIdentsM :: Monad m => MapperM m Identifier -> MapperM m Decl
traverseDeclIdentsM identMapper =
traverseDeclExprsM (traverseExprIdentsM identMapper) >=>
traverseDeclTypesM (traverseTypeIdentsM identMapper)
traverseExpr :: Expr -> Expr -- returns any names defined by a package item
traverseExpr (PSIdent x y) = Ident $ x ++ "_" ++ y piNames :: PackageItem -> [Identifier]
traverseExpr other = other piNames (Function _ _ ident _ _) = [ident]
piNames (Task _ ident _ _) = [ident]
traverseType :: Type -> Type piNames (Decl (Variable _ _ ident _ _)) = [ident]
traverseType (PSAlias ps xx rs) = Alias (ps ++ "_" ++ xx) rs piNames (Decl (Param _ _ ident _)) = [ident]
traverseType other = other piNames (Decl (ParamType _ ident _)) = [ident]
piNames (Decl (CommentDecl _)) = []
-- returns the "name" of a package item, if it has one piNames (Import x y) = [show $ Import x y]
piName :: PackageItem -> Identifier piNames (Export x y) = [show $ Export x y]
piName (Function _ _ ident _ _) = ident piNames (Directive _) = []
piName (Task _ ident _ _) = ident piNames (Typedef (Enum _ enumItems _) ident) =
piName (Typedef _ ident ) = ident ident : map fst enumItems
piName (Decl (Variable _ _ ident _ _)) = ident piNames (Typedef _ ident) = [ident]
piName (Decl (Param _ _ ident _)) = ident
piName (Decl (ParamType _ ident _)) = ident
piName (Decl (CommentDecl _)) = ""
piName (Import _ _) = ""
piName (Export _) = ""
piName (Directive _) = ""
...@@ -27,6 +27,7 @@ module Convert.Scoper ...@@ -27,6 +27,7 @@ module Convert.Scoper
, ScoperT , ScoperT
, evalScoper , evalScoper
, evalScoperT , evalScoperT
, runScoperT
, partScoper , partScoper
, partScoperT , partScoperT
, insertElem , insertElem
...@@ -36,9 +37,12 @@ module Convert.Scoper ...@@ -36,9 +37,12 @@ module Convert.Scoper
, Access(..) , Access(..)
, ScopeKey , ScopeKey
, Scopes , Scopes
, extractMapping
, embedScopes , embedScopes
, withinProcedure , withinProcedure
, withinProcedureM , withinProcedureM
, lookupLocalIdent
, lookupLocalIdentM
, scopeModuleItemT , scopeModuleItemT
, Replacements , Replacements
) where ) where
...@@ -82,6 +86,12 @@ data Scopes a = Scopes ...@@ -82,6 +86,12 @@ data Scopes a = Scopes
, sInjected :: [ModuleItem] , sInjected :: [ModuleItem]
} deriving Show } deriving Show
extractMapping :: Scopes a -> Map.Map Identifier a
extractMapping =
Map.mapMaybe eElement .
eMapping . snd .
Map.findMin . sMapping
embedScopes :: Monad m => (Scopes a -> b -> c) -> b -> ScoperT a m c embedScopes :: Monad m => (Scopes a -> b -> c) -> b -> ScoperT a m c
embedScopes func x = do embedScopes func x = do
scopes <- get scopes <- get
...@@ -142,13 +152,26 @@ exprToAccesses (Dot e x) = do ...@@ -142,13 +152,26 @@ exprToAccesses (Dot e x) = do
Just $ accesses ++ [Access x Nil] Just $ accesses ++ [Access x Nil]
exprToAccesses _ = Nothing exprToAccesses _ = Nothing
insertElem :: Monad m => Identifier -> a -> ScoperT a m () class ScopePath k where
insertElem name element = do toTiers :: Scopes a -> k -> [Tier]
instance ScopePath Identifier where
toTiers scopes name = sCurrent scopes ++ [Tier name ""]
instance ScopePath [Access] where
toTiers _ = map toTier
where
toTier :: Access -> Tier
toTier (Access x Nil) = Tier x ""
toTier (Access x iy) = Tier x y
where Ident y = iy
insertElem :: Monad m => ScopePath k => k -> a -> ScoperT a m ()
insertElem key element = do
s <- get s <- get
let current = sCurrent s
let mapping = sMapping s let mapping = sMapping s
let entry = Entry (Just element) "" Map.empty let entry = Entry (Just element) "" Map.empty
let mapping' = setScope (current ++ [Tier name ""]) entry mapping let mapping' = setScope (toTiers s key) entry mapping
put $ s { sMapping = mapping' } put $ s { sMapping = mapping' }
injectItem :: Monad m => ModuleItem -> ScoperT a m () injectItem :: Monad m => ModuleItem -> ScoperT a m ()
...@@ -218,6 +241,19 @@ lookupAccesses scopes accesses = do ...@@ -218,6 +241,19 @@ lookupAccesses scopes accesses = do
let side = resolveInScope (sMapping scopes) [] accesses let side = resolveInScope (sMapping scopes) [] accesses
if isNothing deep then side else deep if isNothing deep then side else deep
lookupLocalIdent :: Scopes a -> Identifier -> LookupResult a
lookupLocalIdent scopes ident = do
(replacements, element) <- directResolve (sMapping scopes) accesses
Just (accesses, replacements, element)
where
accesses = map toAccess (sCurrent scopes) ++ [Access ident Nil]
toAccess :: Tier -> Access
toAccess (Tier x "") = Access x Nil
toAccess (Tier x y) = Access x (Ident y)
lookupLocalIdentM :: Monad m => Identifier -> ScoperT a m (LookupResult a)
lookupLocalIdentM = embedScopes lookupLocalIdent
withinProcedureM :: Monad m => ScoperT a m Bool withinProcedureM :: Monad m => ScoperT a m Bool
withinProcedureM = gets sProcedure withinProcedureM = gets sProcedure
...@@ -245,8 +281,23 @@ evalScoperT ...@@ -245,8 +281,23 @@ evalScoperT
-> Identifier -> Identifier
-> [ModuleItem] -> [ModuleItem]
-> m [ModuleItem] -> m [ModuleItem]
evalScoperT declMapper moduleItemMapper genItemMapper stmtMapper topName items = evalScoperT declMapper moduleItemMapper genItemMapper stmtMapper topName items = do
evalStateT operation initialState (items', _) <- runScoperT
declMapper moduleItemMapper genItemMapper stmtMapper
topName items
return items'
runScoperT
:: forall a m. Monad m
=> MapperM (ScoperT a m) Decl
-> MapperM (ScoperT a m) ModuleItem
-> MapperM (ScoperT a m) GenItem
-> MapperM (ScoperT a m) Stmt
-> Identifier
-> [ModuleItem]
-> m ([ModuleItem], Scopes a)
runScoperT declMapper moduleItemMapper genItemMapper stmtMapper topName items =
runStateT operation initialState
where where
operation :: ScoperT a m [ModuleItem] operation :: ScoperT a m [ModuleItem]
operation = do operation = do
......
...@@ -613,8 +613,8 @@ traverseNodesM exprMapper declMapper typeMapper lhsMapper stmtMapper = ...@@ -613,8 +613,8 @@ traverseNodesM exprMapper declMapper typeMapper lhsMapper stmtMapper =
return $ MIPackageItem $ Directive c return $ MIPackageItem $ Directive c
moduleItemMapper (MIPackageItem (Import x y)) = moduleItemMapper (MIPackageItem (Import x y)) =
return $ MIPackageItem $ Import x y return $ MIPackageItem $ Import x y
moduleItemMapper (MIPackageItem (Export x)) = moduleItemMapper (MIPackageItem (Export x y)) =
return $ MIPackageItem $ Export x return $ MIPackageItem $ Export x y
moduleItemMapper (AssertionItem (mx, a)) = do moduleItemMapper (AssertionItem (mx, a)) = do
a' <- traverseAssertionStmtsM stmtMapper a a' <- traverseAssertionStmtsM stmtMapper a
a'' <- traverseAssertionExprsM exprMapper a' a'' <- traverseAssertionExprsM exprMapper a'
...@@ -864,6 +864,11 @@ traverseTypeExprsM exprMapper = ...@@ -864,6 +864,11 @@ traverseTypeExprsM exprMapper =
let pm' = zip (map fst pm) vals' let pm' = zip (map fst pm) vals'
rs' <- mapM (mapBothM exprMapper) rs rs' <- mapM (mapBothM exprMapper) rs
return $ CSAlias ps pm' xx rs' return $ CSAlias ps pm' xx rs'
typeMapper (Enum t enumItems rs) = do
enumItems' <- mapM enumItemMapper enumItems
rs' <- mapM (mapBothM exprMapper) rs
return $ Enum t enumItems' rs'
where enumItemMapper (x, e) = exprMapper e >>= \e' -> return (x, e')
typeMapper t = do typeMapper t = do
let (tf, rs) = typeRanges t let (tf, rs) = typeRanges t
rs' <- mapM (mapBothM exprMapper) rs rs' <- mapM (mapBothM exprMapper) rs
......
...@@ -12,7 +12,6 @@ module Language.SystemVerilog.AST.Description ...@@ -12,7 +12,6 @@ module Language.SystemVerilog.AST.Description
, Lifetime (..) , Lifetime (..)
) where ) where
import Data.Maybe (fromMaybe)
import Text.Printf (printf) import Text.Printf (printf)
import Language.SystemVerilog.AST.ShowHelp import Language.SystemVerilog.AST.ShowHelp
...@@ -56,8 +55,8 @@ data PackageItem ...@@ -56,8 +55,8 @@ data PackageItem
= Typedef Type Identifier = Typedef Type Identifier
| Function Lifetime Type Identifier [Decl] [Stmt] | Function Lifetime Type Identifier [Decl] [Stmt]
| Task Lifetime Identifier [Decl] [Stmt] | Task Lifetime Identifier [Decl] [Stmt]
| Import Identifier (Maybe Identifier) | Import Identifier Identifier
| Export (Maybe (Identifier, Maybe Identifier)) | Export Identifier Identifier
| Decl Decl | Decl Decl
| Directive String | Directive String
deriving Eq deriving Eq
...@@ -70,12 +69,15 @@ instance Show PackageItem where ...@@ -70,12 +69,15 @@ instance Show PackageItem where
show (Task ml x i b) = show (Task ml x i b) =
printf "task %s%s;\n%s\nendtask" printf "task %s%s;\n%s\nendtask"
(showPad ml) x (showBlock i b) (showPad ml) x (showBlock i b)
show (Import x y) = printf "import %s::%s;" x (fromMaybe "*" y) show (Import x y) = printf "import %s::%s;" x (showWildcard y)
show (Export Nothing) = "export *::*"; show (Export x y) = printf "export %s::%s;" (showWildcard x) (showWildcard y)
show (Export (Just (x, y))) = printf "export %s::%s;" x (fromMaybe "*" y)
show (Decl decl) = show decl show (Decl decl) = show decl
show (Directive str) = str show (Directive str) = str
showWildcard :: Identifier -> String
showWildcard "" = "*"
showWildcard x = x
data PartKW data PartKW
= Module = Module
| Interface | Interface
......
...@@ -843,8 +843,8 @@ NonDeclPackageItem :: { [PackageItem] } ...@@ -843,8 +843,8 @@ NonDeclPackageItem :: { [PackageItem] }
| "function" Lifetime "void" Identifier TFItems DeclsAndStmts "endfunction" opt(Tag) { [Task $2 $4 (map defaultFuncInput $ $5 ++ fst $6) (snd $6)] } | "function" Lifetime "void" Identifier TFItems DeclsAndStmts "endfunction" opt(Tag) { [Task $2 $4 (map defaultFuncInput $ $5 ++ fst $6) (snd $6)] }
| "task" Lifetime Identifier TFItems DeclsAndStmts "endtask" opt(Tag) { [Task $2 $3 (map defaultFuncInput $ $4 ++ fst $5) (snd $5)] } | "task" Lifetime Identifier TFItems DeclsAndStmts "endtask" opt(Tag) { [Task $2 $3 (map defaultFuncInput $ $4 ++ fst $5) (snd $5)] }
| "import" PackageImportItems ";" { map (uncurry Import) $2 } | "import" PackageImportItems ";" { map (uncurry Import) $2 }
| "export" PackageImportItems ";" { map (Export . Just) $2 } | "export" PackageImportItems ";" { map (uncurry Export) $2 }
| "export" "*" "::" "*" ";" { [Export Nothing] } -- "Nothing" being no restrictions | "export" "*" "::" "*" ";" { [Export "" ""] }
| ForwardTypedef ";" { $1 } | ForwardTypedef ";" { $1 }
| TimeunitsDeclaration { $1 } | TimeunitsDeclaration { $1 }
| Directive { [Directive $1] } | Directive { [Directive $1] }
...@@ -872,12 +872,12 @@ DefaultNetType :: { String } ...@@ -872,12 +872,12 @@ DefaultNetType :: { String }
: NetType { show $1 } : NetType { show $1 }
| Identifier { $1 } | Identifier { $1 }
PackageImportItems :: { [(Identifier, Maybe Identifier)] } PackageImportItems :: { [(Identifier, Identifier)] }
: PackageImportItem { [$1] } : PackageImportItem { [$1] }
| PackageImportItems "," PackageImportItem { $1 ++ [$3] } | PackageImportItems "," PackageImportItem { $1 ++ [$3] }
PackageImportItem :: { (Identifier, Maybe Identifier) } PackageImportItem :: { (Identifier, Identifier) }
: Identifier "::" Identifier { ($1, Just $3) } : Identifier "::" Identifier { ($1, $3) }
| Identifier "::" "*" { ($1, Nothing) } | Identifier "::" "*" { ($1, "") }
FuncRetAndName :: { (Type, Identifier) } FuncRetAndName :: { (Type, Identifier) }
: Type Identifier { ($1 , $2) } : Type Identifier { ($1 , $2) }
...@@ -987,6 +987,8 @@ StmtAsgn :: { Stmt } ...@@ -987,6 +987,8 @@ StmtAsgn :: { Stmt }
| IncOrDecOperator LHS ";" { Asgn (AsgnOp $1) Nothing $2 (RawNum 1) } | IncOrDecOperator LHS ";" { Asgn (AsgnOp $1) Nothing $2 (RawNum 1) }
| LHS ";" { Subroutine (lhsToExpr $1) (Args [] []) } | LHS ";" { Subroutine (lhsToExpr $1) (Args [] []) }
| LHS CallArgs ";" { Subroutine (lhsToExpr $1) $2 } | LHS CallArgs ";" { Subroutine (lhsToExpr $1) $2 }
| Identifier "::" Identifier ";" { Subroutine (PSIdent $1 $3) (Args [] []) }
| Identifier "::" Identifier CallArgs ";" { Subroutine (PSIdent $1 $3) $4 }
StmtNonAsgn :: { Stmt } StmtNonAsgn :: { Stmt }
: StmtBlock(BlockKWSeq, "end" ) { $1 } : StmtBlock(BlockKWSeq, "end" ) { $1 }
| StmtBlock(BlockKWPar, "join") { $1 } | StmtBlock(BlockKWPar, "join") { $1 }
......
...@@ -81,7 +81,6 @@ executable sv2v ...@@ -81,7 +81,6 @@ executable sv2v
Convert.LogOp Convert.LogOp
Convert.MultiplePacked Convert.MultiplePacked
Convert.NamedBlock Convert.NamedBlock
Convert.NestPI
Convert.Package Convert.Package
Convert.ParamNoDefault Convert.ParamNoDefault
Convert.ParamType Convert.ParamType
......
module ExampleA;
typedef enum logic {
A = 1,
B = 0,
C = 2
} Enum;
Enum x = A;
initial $display("ExampleA: x=%b, A=%b, B=%b", x, A, B);
endmodule
module ExampleB;
typedef enum logic {
A = 0,
B = 1
} Enum;
Enum x = A;
initial $display("ExampleB: x=%b, A=%b, B=%b", x, A, B);
endmodule
module ExampleA;
localparam [0:0] A = 1;
localparam [0:0] B = 0;
reg x = A;
initial $display("ExampleA: x=%b, A=%b, B=%b", x, A, B);
endmodule
module ExampleB;
localparam [0:0] A = 0;
localparam [0:0] B = 1;
reg x = A;
initial $display("ExampleB: x=%b, A=%b, B=%b", x, A, B);
endmodule
module top;
ExampleA a();
ExampleB b();
endmodule
package Q;
localparam W = 5;
localparam unrelated = 1;
endpackage
package P;
import Q::*;
export Q::W;
endpackage
module Example
import P::*;
(
input logic [W - 1:0] inp
);
import Q::unrelated;
initial $display("%b %0d %0d", inp, $bits(inp), unrelated);
endmodule
module Example(inp);
localparam W = 5;
localparam unrelated = 1;
input wire [W - 1:0] inp;
initial $display("%b %0d %0d", inp, $bits(inp), unrelated);
endmodule
module top;
Example e(5'b00000);
endmodule
package Pkg;
localparam integer X = func(1);
function automatic integer func;
input integer inp;
func = inp * 2;
endfunction
endpackage
module top;
initial $display(Pkg::X);
endmodule
module top;
function automatic integer func;
input integer inp;
func = inp * 2;
endfunction
localparam integer X = func(1);
initial $display(X);
endmodule
package P;
localparam X = 1;
localparam Y = 2;
typedef enum {
A = X,
B = Y
} Enum;
endpackage
module top;
import P::*;
initial $display("%0d %0d %0d", X, A, B);
endmodule
module top;
localparam X = 1;
localparam Y = 2;
localparam A = X;
localparam B = Y;
initial $display("%0d %0d %0d", X, A, B);
endmodule
package PkgA;
localparam Foo = 1;
endpackage
package PkgB;
export PkgA::*;
localparam Bar = 2;
endpackage
module top;
initial $display(PkgB::Bar);
endmodule
module top;
localparam Bar = 2;
initial $display(Bar);
endmodule
package P;
localparam X = 1;
endpackage
package Q;
import P::X;
export P::*;
localparam Y = 2;
endpackage
package R;
import Q::X;
export Q::*;
localparam Z = 3;
endpackage
package S;
import P::X;
import Q::Y;
import R::Z;
export *::*;
endpackage
module top;
import S::*;
initial $display(X, Y, Z);
endmodule
module top;
localparam X = 1;
localparam Y = 2;
localparam Z = 3;
initial $display(X, Y, Z);
endmodule
package PkgA;
localparam X = 1;
localparam Y = 2;
endpackage
package PkgB;
localparam X = 3;
localparam Z = 4;
endpackage
import PkgA::*;
import PkgB::*;
localparam X = 5;
module top;
initial $display(X, Y, Z);
endmodule
module top;
localparam X = 5;
localparam Y = 2;
localparam Z = 4;
initial $display(X, Y, Z);
endmodule
`define DUMP(key) initial $display(`"key %0d`", X);
package P;
localparam X = 1;
endpackage
package Q;
localparam X = 2;
endpackage
module ExampleA;
import P::*;
localparam X = 3;
`DUMP(A)
endmodule
module ExampleB;
localparam X = 3;
import P::*;
`DUMP(B)
endmodule
module ExampleC;
import P::*;
`DUMP(C)
endmodule
module ExampleD;
import Q::*;
`DUMP(D)
endmodule
module ExampleE;
import P::*;
import Q::X;
`DUMP(E)
endmodule
module ExampleF;
import Q::X;
import P::*;
`DUMP(F)
endmodule
module ExampleG;
import P::*;
import Q::*;
// allowed but can't reference C
endmodule
package R;
import P::X;
export P::X;
endpackage
package S;
import P::X;
export R::X; // oof but it's allowed
endpackage
module ExampleH;
import R::*;
import S::*;
`DUMP(H)
endmodule
module ExampleI;
import R::X;
import S::X;
`DUMP(I)
endmodule
module ExampleJ;
import R::*;
`DUMP(J)
import S::X;
endmodule
module ExampleK;
import P::X;
if (1) begin : blk1
import P::X;
`DUMP(K1)
end
if (1) begin : blk2
import Q::X;
`DUMP(K2)
end
if (1) begin : blk3
localparam X = 3;
`DUMP(K3)
end
if (1) begin : blk4
import Q::*;
`DUMP(K4)
end
`DUMP(K0)
endmodule
module ExampleL;
import P::X;
import R::X;
`DUMP(L)
endmodule
package T;
import P::X;
export P::*;
endpackage
package U;
import P::*;
export P::X;
endpackage
package V;
import P::*;
export P::*;
localparam Y = X;
endpackage
package W;
import P::*;
export P::*;
task help;
$display("W::help() %0d", X);
endtask
endpackage
module ExampleM;
if (1) begin : blk1
import T::X;
`DUMP(M1)
end
if (1) begin : blk2
import U::X;
`DUMP(M2)
end
if (1) begin : blk3
import V::X;
`DUMP(M3)
end
if (1) begin : blk4
import W::X;
`DUMP(M4)
initial W::help;
initial W::help();
end
endmodule
module ExampleN;
import P::*;
if (1) begin : blk1
import P::X;
`DUMP(N1)
end
import Q::X;
`DUMP(N2)
endmodule
module ExampleO;
import P::*;
if (1) begin : blk1
import P::*;
`DUMP(O1)
end
import Q::X;
`DUMP(O2)
endmodule
module top;
endmodule
module top;
initial begin
$display("A 3");
$display("B 3");
$display("C 1");
$display("D 2");
$display("E 2");
$display("F 2");
// G doesn't print
$display("H 1");
$display("I 1");
$display("J 1");
$display("K1 1");
$display("K2 2");
$display("K3 3");
$display("K4 2");
$display("K0 1");
$display("L 1");
$display("M1 1");
$display("M2 1");
$display("M3 1");
$display("M4 1");
$display("W::help() 1");
$display("W::help() 1");
$display("N1 1");
$display("N2 2");
$display("O1 1");
$display("O2 2");
end
endmodule
// pattern: invalid export Pkg::Foo outside of package
package Pkg;
localparam Foo = 1;
endpackage
import Pkg::Foo;
export Pkg::Foo;
module top;
initial $display(Foo);
endmodule
// pattern: invalid export Pkg::Foo outside of package
package Pkg;
localparam Foo = 1;
endpackage
module top;
import Pkg::Foo;
export Pkg::Foo;
initial $display(Foo);
endmodule
// pattern: invalid export \*::\* outside of package
package Pkg;
localparam Foo = 1;
endpackage
import Pkg::Foo;
export *::*;
module top;
initial $display(Foo);
endmodule
// pattern: could not find package "PackageThatDoesNotExist"
module top;
import PackageThatDoesNotExist::*;
endmodule
// pattern: could not find "ItemThatDoesNotExist" in package "Pkg"
package Pkg;
localparam Foo = 1;
endpackage
module top;
import Pkg::ItemThatDoesNotExist;
endmodule
// pattern: could not find "X" in package "Q"
package P;
localparam X = 1;
endpackage
package Q;
import P::*;
export P::*;
localparam Y = P::X;
endpackage
module top;
initial $display(Q::X);
endmodule
// pattern: could not find "X" in package "Q"
package P;
localparam X = 1;
localparam Y = 2;
endpackage
package Q;
import P::*;
export *::*;
localparam Z = P::Y;
endpackage
module top;
initial $display(Q::X);
endmodule
// pattern: export of PkgA::Bar, but Bar was never imported
package PkgA;
localparam Bar = 2;
endpackage
package PkgB;
export PkgA::Bar;
localparam Foo = 1;
endpackage
module top;
initial $display(PkgB::Foo);
endmodule
// pattern: export of Bar::Foo differs from import of Foo::Foo
package Bar;
localparam Bar = 1;
localparam Foo = 3;
endpackage
package Foo;
localparam Foo = 2;
endpackage
package Pkg;
import Foo::Foo;
import Bar::Bar;
export Bar::Foo;
endpackage
module top;
initial $display(Pkg::Foo);
endmodule
// pattern: could not find "Foo" in package "Bar"
package Bar;
localparam Bar = 1;
endpackage
package Pkg;
import Bar::*;
export Bar::Foo;
endpackage
module top;
initial $display(Pkg::Foo);
endmodule
// pattern: could not find package "PackageThatDoesNotExist"
package Wrap;
import PackageThatDoesNotExist::*;
localparam Foo = Bar;
endpackage
module top;
import Wrap::*;
endmodule
// pattern: could not find "ItemThatDoesNotExist" in package "Pkg"
package Pkg;
localparam Foo = 1;
endpackage
package Wrap;
localparam Foo = Pkg::ItemThatDoesNotExist;
endpackage
module top;
import Wrap::*;
endmodule
// pattern: package dependency loop: "PkgA" depends on "PkgB", which depends on "PkgA"
package PkgA;
import PkgB::Foo;
export PkgB::Foo;
endpackage
package PkgB;
import PkgA::Foo;
export PkgA::Foo;
endpackage
module top;
initial $display(PkgA::Foo);
endmodule
// pattern: package dependency loop: "PkgA" depends on "PkgC", which depends on "PkgB", which depends on "PkgA"
package PkgA;
import PkgC::Foo;
export PkgC::Foo;
endpackage
package PkgB;
import PkgA::Foo;
export PkgA::Foo;
endpackage
package PkgC;
import PkgB::Foo;
export PkgB::Foo;
endpackage
module top;
initial $display(PkgA::Foo);
endmodule
// pattern: identifier "X" ambiguously refers to the definitions in any of P, Q
package P;
localparam X = 1;
endpackage
package Q;
localparam X = 2;
endpackage
module top;
import P::*;
import Q::*;
initial $display(X);
endmodule
// pattern: import of Q::X conflicts with prior import of P::X
package P;
localparam X = 1;
endpackage
package Q;
localparam X = 2;
endpackage
module top;
import P::X;
import Q::X;
endmodule
// pattern: declaration of X conflicts with prior import of P::X
package P;
localparam X = 1;
endpackage
module top;
import P::X;
localparam X = 2;
endmodule
// pattern: import of P::X conflicts with prior declaration of X
package P;
localparam X = 1;
endpackage
module top;
localparam X = 2;
import P::X;
endmodule
// pattern: import of P::X conflicts with prior import of Q::X
package P;
localparam X = 1;
endpackage
package Q;
localparam X = 2;
endpackage
module top;
import Q::*;
initial $display(X); // imports Q::X
import P::X; // illegal
endmodule
// pattern: import of Q::X conflicts with prior import of P::X
package P;
localparam X = 1;
endpackage
package Q;
localparam X = 2;
endpackage
package W;
import P::*;
export P::*;
task help;
$display("W::help() %0d", X);
endtask
import Q::X;
endpackage
module top;
import W::*;
initial $display(X);
endmodule
// pattern: import of Q::X conflicts with prior import of P::X
package P;
localparam X = 1;
endpackage
package Q;
localparam X = 2;
endpackage
module top;
import P::*;
if (1) begin : blk1
// forces import of P::X at the top level
initial $display(X);
end
import Q::X; // illegal
endmodule
// pattern: identifier "X" ambiguously refers to the definitions in any of PkgA, PkgB
package PkgA;
localparam X = 1;
endpackage
package PkgB;
localparam X = 3;
endpackage
import PkgA::*;
import PkgB::*;
module top;
initial $display(X);
endmodule
// pattern: package dependency loop: "Pkg" depends on "Pkg"
package Pkg;
localparam Foo = 1;
export Pkg::Foo;
endpackage
module top;
initial $display(Pkg::Foo);
endmodule
// pattern: package dependency loop: "P" depends on "P"
package P;
import P::*;
localparam Foo = 1;
endpackage
module top;
import P::*;
initial $display(Foo);
endmodule
// pattern: package dependency loop: "P" depends on "P"
package P;
localparam Foo = P::Foo;
endpackage
module top;
import P::*;
initial $display(Foo);
endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment