From d2c06b58bc3e99cc8b6fb4e3fb01a6c66a10175f Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 30 Apr 2019 01:57:04 -0400 Subject: [PATCH] initial work towards fleshing out package conversion --- src/Convert/NestPI.hs | 3 +- src/Convert/Package.hs | 76 +++++++++++++++---- src/Convert/Traverse.hs | 2 + src/Language/SystemVerilog/AST/Description.hs | 3 + src/Language/SystemVerilog/Parser/Parse.y | 2 + test/basic/package.sv | 29 +++++++ test/basic/package.v | 16 ++++ 7 files changed, 115 insertions(+), 16 deletions(-) diff --git a/src/Convert/NestPI.hs b/src/Convert/NestPI.hs index 132ff7e..8c078a5 100644 --- a/src/Convert/NestPI.hs +++ b/src/Convert/NestPI.hs @@ -49,7 +49,7 @@ traverseDescriptionM (orig @ (Part extern kw lifetime name ports items)) = do existingPIs let newItems = map MIPackageItem $ Map.elems $ Map.restrictKeys tfs neededPIs - return $ Part extern kw lifetime name ports (items ++ newItems) + return $ Part extern kw lifetime name ports (newItems ++ items) where existingPIs = execWriter $ collectModuleItemsM collectPIsM orig runner f = execWriter $ collectModuleItemsM f orig @@ -97,4 +97,5 @@ piName (Decl (Variable _ _ ident _ _)) = Just ident piName (Decl (Parameter _ ident _)) = Just ident piName (Decl (Localparam _ ident _)) = Just ident piName (Import x y) = Just $ show $ Import x y +piName (Export _) = Nothing piName (Comment _) = Nothing diff --git a/src/Convert/Package.hs b/src/Convert/Package.hs index d148abf..c880512 100644 --- a/src/Convert/Package.hs +++ b/src/Convert/Package.hs @@ -1,7 +1,32 @@ {- sv2v - Author: Zachary Snow - - - Conversion for packages and imports + - Conversion for packages, exports, and imports + - + - TODO: We do not yet handle exports. + - TODO: The scoping rules are not being entirely followed yet. + - TODO: Explicit imports may introduce name conflicts because of carried items. + - + - The SystemVerilog scoping rules for exports and imports are not entirely + - trivial. We do not explicitly handle the "error" scenarios detailed Table + - 26-1 of Section 26-3 of IEEE 1800-2017. Users generally shouldn't be relying + - on this tool to catch and report such wild naming conflicts that are outlined + - there. + - + - Summary: + - * In scopes which have a local declaration of an identifier, that identifier + - refers to that local declaration. + - * 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. + - + - If a package cannot be found within a file that references it (including + - through files it imports), we fall back to an arbitrary package with the + - given name, if it exists. While this isn't foolproof, some projects do rely + - on their toolchain to locate their packages in other files, much like modules + - or interfaces. -} module Convert.Package (convert) where @@ -29,13 +54,23 @@ convert asts = where packages = execWriter $ collectDescriptionsM collectDescriptionM $ concat curr - globalItems = map PackageItem $ - concatMap (uncurry globalPackageItems) $ Map.toList packages - next = map ((++) globalItems) $ map (filter shouldntRemove) $ map - (traverseDescriptions $ traverseDescription packages) curr - shouldntRemove :: Description -> Bool - shouldntRemove (Package _ name _) = Map.notMember name packages - shouldntRemove _ = True + next = map (convertFile packages) curr + +convertFile :: Packages -> AST -> AST +convertFile globalPackages ast = + (++) globalItems $ + filter (not . isCollected) $ + traverseDescriptions (traverseDescription packages) $ + ast + where + globalItems = map PackageItem $ + concatMap (uncurry globalPackageItems) $ Map.toList packages + localPackages = execWriter $ + collectDescriptionsM collectDescriptionM ast + packages = Map.union localPackages globalPackages + isCollected :: Description -> Bool + isCollected (Package _ name _) = Map.member name localPackages + isCollected _ = False globalPackageItems :: Identifier -> PackageItems -> [PackageItem] globalPackageItems name items = @@ -86,20 +121,30 @@ collectDescriptionM _ = return () traverseDescription :: Packages -> Description -> Description traverseDescription packages description = - traverseModuleItems (traverseModuleItem packages) description + traverseModuleItems (traverseModuleItem existingItemNames packages) + description + where + existingItemNames = execWriter $ + collectModuleItemsM writePIName description + writePIName :: ModuleItem -> Writer Idents () + writePIName (MIPackageItem item) = + case piName item of + Nothing -> return () + Just x -> tell $ Set.singleton x + writePIName _ = return () -traverseModuleItem :: Packages -> ModuleItem -> ModuleItem -traverseModuleItem packages (MIPackageItem (Import x y)) = +traverseModuleItem :: Idents -> Packages -> ModuleItem -> ModuleItem +traverseModuleItem existingItemNames packages (MIPackageItem (Import x y)) = if Map.member x packages then Generate $ map (GenModuleItem . MIPackageItem) items else MIPackageItem $ Import x y where packageItems = packages Map.! x - filterer = case y of - Nothing -> \_ -> True - Just ident -> (==) ident + filterer itemName = case y of + Nothing -> Set.notMember itemName existingItemNames + Just ident -> ident == itemName items = map snd $ filter (filterer . fst) $ Map.toList packageItems -traverseModuleItem _ item = +traverseModuleItem _ _ item = (traverseExprs $ traverseNestedExprs traverseExpr) $ (traverseStmts traverseStmt) $ (traverseTypes traverseType) $ @@ -131,4 +176,5 @@ piName (Decl (Variable _ _ ident _ _)) = Just ident piName (Decl (Parameter _ ident _)) = Just ident piName (Decl (Localparam _ ident _)) = Just ident piName (Import _ _) = Nothing +piName (Export _) = Nothing piName (Comment _) = Nothing diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index 9b26e7d..daf9417 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -564,6 +564,8 @@ traverseExprsM' strat exprMapper = moduleItemMapper return $ MIPackageItem $ Comment c moduleItemMapper (MIPackageItem (Import x y)) = return $ MIPackageItem $ Import x y + moduleItemMapper (MIPackageItem (Export x)) = + return $ MIPackageItem $ Export x moduleItemMapper (AssertionItem (mx, a)) = do a' <- traverseAssertionStmtsM stmtMapper a a'' <- traverseAssertionExprsM exprMapper a' diff --git a/src/Language/SystemVerilog/AST/Description.hs b/src/Language/SystemVerilog/AST/Description.hs index 357890d..76e86a3 100644 --- a/src/Language/SystemVerilog/AST/Description.hs +++ b/src/Language/SystemVerilog/AST/Description.hs @@ -57,6 +57,7 @@ data PackageItem | Function (Maybe Lifetime) Type Identifier [Decl] [Stmt] | Task (Maybe Lifetime) Identifier [Decl] [Stmt] | Import Identifier (Maybe Identifier) + | Export (Maybe (Identifier, Maybe Identifier)) | Decl Decl | Comment String deriving Eq @@ -72,6 +73,8 @@ instance Show PackageItem where (showLifetime ml) x (indent $ show i) (indent $ unlines' $ map show b) show (Import x y) = printf "import %s::%s;" x (fromMaybe "*" y) + show (Export Nothing) = "export *::*"; + show (Export (Just (x, y))) = printf "export %s::%s;" x (fromMaybe "*" y) show (Decl decl) = show decl show (Comment c) = if elem '\n' c diff --git a/src/Language/SystemVerilog/Parser/Parse.y b/src/Language/SystemVerilog/Parser/Parse.y index 1d66c15..a8b6c60 100644 --- a/src/Language/SystemVerilog/Parser/Parse.y +++ b/src/Language/SystemVerilog/Parser/Parse.y @@ -578,6 +578,8 @@ NonDeclPackageItem :: { [PackageItem] } | "function" opt(Lifetime) FuncRetAndName TFItems DeclsAndStmts "endfunction" opt(Tag) { [Function $2 (fst $3) (snd $3) (map defaultFuncInput $ (map makeInput $4) ++ fst $5) (snd $5)] } | "task" opt(Lifetime) Identifier TFItems DeclsAndStmts "endtask" opt(Tag) { [Task $2 $3 (map defaultFuncInput $ $4 ++ fst $5) (snd $5)] } | "import" PackageImportItems ";" { map (uncurry Import) $2 } + | "export" PackageImportItems ";" { map (Export . Just) $2 } + | "export" "*" "::" "*" ";" { [Export Nothing] } -- "Nothing" being no restrictions PackageImportItems :: { [(Identifier, Maybe Identifier)] } : PackageImportItem { [$1] } diff --git a/test/basic/package.sv b/test/basic/package.sv index d21201f..f7dc3c4 100644 --- a/test/basic/package.sv +++ b/test/basic/package.sv @@ -17,6 +17,11 @@ package D; endpackage package E; import D::*; + export D::*; +endpackage +package F; + localparam MAGIC = -42; + localparam PIZZAZZ = -5; endpackage module top; import A::FOO; @@ -33,4 +38,28 @@ module top; $display("%d", E::pack(0)); $display("%d", E::pack(1)); end + import F::*; + initial begin + $display("imported MAGIC %d", MAGIC); + $display("imported MAGIC %d", F::MAGIC); + begin + localparam MAGIC = 42; + $display("local MAGIC %d", MAGIC); + $display("imported MAGIC %d", F::MAGIC); + end + $display("imported MAGIC %d", MAGIC); + $display("imported MAGIC %d", F::MAGIC); + end + localparam PIZZAZZ = -6; + initial begin + $display("local PIZZAZZ %d", PIZZAZZ); + $display("imported PIZZAZZ %d", F::PIZZAZZ); + begin + localparam PIZZAZZ = -7; + $display("shadowed local PIZZAZZ %d", PIZZAZZ); + $display("imported PIZZAZZ %d", F::PIZZAZZ); + end + $display("local PIZZAZZ %d", PIZZAZZ); + $display("imported PIZZAZZ %d", F::PIZZAZZ); + end endmodule diff --git a/test/basic/package.v b/test/basic/package.v index 87dfdb5..119d53a 100644 --- a/test/basic/package.v +++ b/test/basic/package.v @@ -25,4 +25,20 @@ module top; $display("%d", E_pack(0)); $display("%d", E_pack(1)); end + initial begin + $display("imported MAGIC %d", -42); + $display("imported MAGIC %d", -42); + $display("local MAGIC %d", +42); + $display("imported MAGIC %d", -42); + $display("imported MAGIC %d", -42); + $display("imported MAGIC %d", -42); + end + initial begin + $display("local PIZZAZZ %d", -6); + $display("imported PIZZAZZ %d", -5); + $display("shadowed local PIZZAZZ %d", -7); + $display("imported PIZZAZZ %d", -5); + $display("local PIZZAZZ %d", -6); + $display("imported PIZZAZZ %d", -5); + end endmodule