Commit 911243da by Zachary Snow

add --top for filtering uninstantiated modules

parent 3b2a55a6
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Added `-y`/`--libdir` for specifying library directories from which to * Added `-y`/`--libdir` for specifying library directories from which to
automatically load modules and interfaces used in the design that are not automatically load modules and interfaces used in the design that are not
found in the provided input files found in the provided input files
* Added `--top` for pruning unneeded modules during conversion
* The `string` data type is now dropped from parameters and localparams * The `string` data type is now dropped from parameters and localparams
* Added support for passing through `sequence` and `property` declarations * Added support for passing through `sequence` and `property` declarations
......
...@@ -107,6 +107,8 @@ Conversion: ...@@ -107,6 +107,8 @@ Conversion:
-w --write=MODE/FILE How to write output; default is 'stdout'; use -w --write=MODE/FILE How to write output; default is 'stdout'; use
'adjacent' to create a .v file next to each input; 'adjacent' to create a .v file next to each input;
use a path ending in .v to write to a file use a path ending in .v to write to a file
--top=NAME Remove uninstantiated modules except the given
top module; can be used multiple times
Other: Other:
--oversized-numbers Disable standard-imposed 32-bit limit on unsized --oversized-numbers Disable standard-imposed 32-bit limit on unsized
number literals (e.g., 'h1_ffff_ffff, 4294967296) number literals (e.g., 'h1_ffff_ffff, 4294967296)
......
...@@ -75,8 +75,8 @@ finalPhases _ = ...@@ -75,8 +75,8 @@ finalPhases _ =
, Convert.StringType.convert , Convert.StringType.convert
] ]
mainPhases :: Selector -> [Phase] mainPhases :: [String] -> Selector -> [Phase]
mainPhases selectExclude = mainPhases tops selectExclude =
[ Convert.BlockDecl.convert [ Convert.BlockDecl.convert
, selectExclude Job.Logic Convert.Logic.convert , selectExclude Job.Logic Convert.Logic.convert
, Convert.ImplicitNet.convert , Convert.ImplicitNet.convert
...@@ -85,7 +85,7 @@ mainPhases selectExclude = ...@@ -85,7 +85,7 @@ mainPhases selectExclude =
, Convert.MultiplePacked.convert , Convert.MultiplePacked.convert
, selectExclude Job.UnbasedUnsized Convert.UnbasedUnsized.convert , selectExclude Job.UnbasedUnsized Convert.UnbasedUnsized.convert
, Convert.Cast.convert , Convert.Cast.convert
, Convert.ParamType.convert , Convert.ParamType.convert tops
, Convert.HierConst.convert , Convert.HierConst.convert
, Convert.TypeOf.convert , Convert.TypeOf.convert
, Convert.DimensionQuery.convert , Convert.DimensionQuery.convert
...@@ -98,12 +98,12 @@ mainPhases selectExclude = ...@@ -98,12 +98,12 @@ mainPhases selectExclude =
, Convert.Wildcard.convert , Convert.Wildcard.convert
, Convert.Enum.convert , Convert.Enum.convert
, Convert.StringParam.convert , Convert.StringParam.convert
, selectExclude Job.Interface Convert.Interface.convert , selectExclude Job.Interface $ Convert.Interface.convert tops
, selectExclude Job.Succinct Convert.RemoveComments.convert , selectExclude Job.Succinct Convert.RemoveComments.convert
] ]
initialPhases :: Selector -> [Phase] initialPhases :: [String] -> Selector -> [Phase]
initialPhases selectExclude = initialPhases tops selectExclude =
[ Convert.ForAsgn.convert [ Convert.ForAsgn.convert
, Convert.Jump.convert , Convert.Jump.convert
, Convert.ExprAsgn.convert , Convert.ExprAsgn.convert
...@@ -119,21 +119,21 @@ initialPhases selectExclude = ...@@ -119,21 +119,21 @@ initialPhases selectExclude =
, Convert.Package.convert , Convert.Package.convert
, Convert.StructConst.convert , Convert.StructConst.convert
, Convert.PortDecl.convert , Convert.PortDecl.convert
, Convert.ParamNoDefault.convert , Convert.ParamNoDefault.convert tops
, Convert.ResolveBindings.convert , Convert.ResolveBindings.convert
, Convert.UnnamedGenBlock.convert , Convert.UnnamedGenBlock.convert
] ]
convert :: FilePath -> [Job.Exclude] -> IOPhase convert :: [String] -> FilePath -> [Job.Exclude] -> IOPhase
convert dumpPrefix excludes = convert tops dumpPrefix excludes =
step "parse" id >=> step "parse" id >=>
step "initial" initial >=> step "initial" initial >=>
loop 1 "main" main >=> loop 1 "main" main >=>
step "final" final step "final" final
where where
final = combine $ finalPhases selectExclude final = combine $ finalPhases selectExclude
main = combine $ mainPhases selectExclude main = combine $ mainPhases tops selectExclude
initial = combine $ initialPhases selectExclude initial = combine $ initialPhases tops selectExclude
combine = foldr1 (.) combine = foldr1 (.)
selectExclude :: Selector selectExclude :: Selector
......
...@@ -29,13 +29,13 @@ type ModportInstances = [(Identifier, (Identifier, Identifier))] ...@@ -29,13 +29,13 @@ type ModportInstances = [(Identifier, (Identifier, Identifier))]
type ModportBinding = (Identifier, (Substitutions, Expr)) type ModportBinding = (Identifier, (Substitutions, Expr))
type Substitutions = [(Expr, Expr)] type Substitutions = [(Expr, Expr)]
convert :: [AST] -> [AST] convert :: [Identifier] -> [AST] -> [AST]
convert files = convert tops files =
if needsFlattening if needsFlattening
then files then files
else traverseFiles else traverseFiles
(collectDescriptionsM collectPart) (collectDescriptionsM collectPart)
(map . convertDescription) (map . convertDescription tops)
files files
where where
-- we can only collect/map non-extern interfaces and modules -- we can only collect/map non-extern interfaces and modules
...@@ -55,12 +55,22 @@ convert files = ...@@ -55,12 +55,22 @@ convert files =
checkItem (Instance _ _ _ rs _) = when (length rs > 1) $ tell $ Any True checkItem (Instance _ _ _ rs _) = when (length rs > 1) $ tell $ Any True
checkItem _ = return () checkItem _ = return ()
convertDescription :: PartInfos -> Description -> Description topInterfaceError :: String -> String -> a
convertDescription _ (Part _ _ Interface _ name _ _) = topInterfaceError name issue = error $
"Specified top module " ++ name ++ " " ++ issue ++ ". Please " ++
"instantiate it somewhere and use that as your top module instead."
convertDescription :: [Identifier] -> PartInfos -> Description -> Description
convertDescription tops _ (Part _ _ Interface _ name _ _)
| elem name tops =
topInterfaceError name "is an interface"
| otherwise =
PackageItem $ Decl $ CommentDecl $ "removed interface: " ++ name PackageItem $ Decl $ CommentDecl $ "removed interface: " ++ name
convertDescription parts (Part attrs extern Module lifetime name ports items) = convertDescription tops parts (Part att ext Module lif name ports items) =
if null $ extractModportInstances name $ PartInfo Module ports items then if null $ extractModportInstances name $ PartInfo Module ports items then
Part attrs extern Module lifetime name ports items' Part att ext Module lif name ports items'
else if elem name tops then
topInterfaceError name "has interface ports"
else else
PackageItem $ Decl $ CommentDecl $ PackageItem $ Decl $ CommentDecl $
"removed module with interface ports: " ++ name "removed module with interface ports: " ++ name
...@@ -324,7 +334,7 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) = ...@@ -324,7 +334,7 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
Nothing -> False Nothing -> False
Just info -> pKind info == Interface Just info -> pKind info == Interface
convertDescription _ other = other convertDescription _ _ other = other
isDecl :: ModuleItem -> Bool isDecl :: ModuleItem -> Bool
isDecl (MIPackageItem Decl{}) = True isDecl (MIPackageItem Decl{}) = True
......
...@@ -23,21 +23,32 @@ import Language.SystemVerilog.AST ...@@ -23,21 +23,32 @@ import Language.SystemVerilog.AST
type Parts = Map.Map Identifier [(Identifier, Bool)] type Parts = Map.Map Identifier [(Identifier, Bool)]
convert :: [AST] -> [AST] convert :: [Identifier] -> [AST] -> [AST]
convert files = convert tops files =
flip (foldr $ ensureTopExists parts) tops $
map convertFile files' map convertFile files'
where where
(files', parts) = runWriter $ (files', parts) = runWriter $
mapM (traverseDescriptionsM traverseDescriptionM) files mapM (traverseDescriptionsM $ traverseDescriptionM tops) files
convertFile = traverseDescriptions $ traverseModuleItems $ convertFile = traverseDescriptions $ traverseModuleItems $
traverseModuleItem parts traverseModuleItem parts
traverseDescriptionM :: Description -> Writer Parts Description ensureTopExists :: Parts -> Identifier -> a -> a
traverseDescriptionM (Part attrs extern kw lifetime name ports items) = do ensureTopExists parts top =
if Map.member top parts
then id
else error $ "Could not find top module " ++ top
traverseDescriptionM :: [Identifier] -> Description -> Writer Parts Description
traverseDescriptionM tops (Part attrs extern kw lifetime name ports items) = do
let (items', params) = runWriter $ mapM traverseModuleItemM items let (items', params) = runWriter $ mapM traverseModuleItemM items
tell $ Map.singleton name params tell $ Map.singleton name params
let missing = map fst $ filter snd params
when (not (null tops) && elem name tops && not (null missing)) $
error $ "Specified top module " ++ name ++ " is missing default "
++ "parameter value(s) for " ++ intercalate ", " missing
return $ Part attrs extern kw lifetime name ports items' return $ Part attrs extern kw lifetime name ports items'
traverseDescriptionM other = return other traverseDescriptionM _ other = return other
traverseModuleItemM :: ModuleItem -> Writer [(Identifier, Bool)] ModuleItem traverseModuleItemM :: ModuleItem -> Writer [(Identifier, Bool)] ModuleItem
traverseModuleItemM (MIAttr attr item) = traverseModuleItemM (MIAttr attr item) =
......
...@@ -26,8 +26,8 @@ type IdentSet = Set.Set Identifier ...@@ -26,8 +26,8 @@ type IdentSet = Set.Set Identifier
type DeclMap = Map.Map Identifier Decl type DeclMap = Map.Map Identifier Decl
type UsageMap = [(Identifier, Set.Set Identifier)] type UsageMap = [(Identifier, Set.Set Identifier)]
convert :: [AST] -> [AST] convert :: [Identifier] -> [AST] -> [AST]
convert files = convert tops files =
files''' files'''
where where
modules = execWriter $ modules = execWriter $
...@@ -74,10 +74,11 @@ convert files = ...@@ -74,10 +74,11 @@ convert files =
keepDescription :: Description -> Bool keepDescription :: Description -> Bool
keepDescription (Part _ _ _ _ name _ _) = keepDescription (Part _ _ _ _ name _ _) =
isNewModule isNewModule
|| isntTyped || isntTyped && (isTopOrNoTop || isInstantiated)
|| isUsedAsUntyped || isUsedAsUntyped
|| isUsedAsTyped && isInstantiatedViaNonTyped || isUsedAsTyped && isInstantiatedViaNonTyped
|| allTypesHaveDefaults && notInstantiated && isntTemplateTagged || allTypesHaveDefaults && notInstantiated && isntTemplateTagged
&& isTopOrNoTop
where where
maybeTypeMap = Map.lookup name modules maybeTypeMap = Map.lookup name modules
Just typeMap = maybeTypeMap Just typeMap = maybeTypeMap
...@@ -88,7 +89,9 @@ convert files = ...@@ -88,7 +89,9 @@ convert files =
isInstantiatedViaNonTyped = untypedUsageSearch $ Set.singleton name isInstantiatedViaNonTyped = untypedUsageSearch $ Set.singleton name
allTypesHaveDefaults = all (/= UnknownType) (Map.elems typeMap) allTypesHaveDefaults = all (/= UnknownType) (Map.elems typeMap)
notInstantiated = lookup name instances == Nothing notInstantiated = lookup name instances == Nothing
isInstantiated = not notInstantiated
isntTemplateTagged = not $ isTemplateTagged name isntTemplateTagged = not $ isTemplateTagged name
isTopOrNoTop = null tops || elem name tops
keepDescription _ = True keepDescription _ = True
-- instantiate the type parameters if this is a used default instance -- instantiate the type parameters if this is a used default instance
......
...@@ -45,6 +45,7 @@ data Job = Job ...@@ -45,6 +45,7 @@ data Job = Job
, verbose :: Bool , verbose :: Bool
, write :: Write , write :: Write
, writeRaw :: String , writeRaw :: String
, top :: [String]
, oversizedNumbers :: Bool , oversizedNumbers :: Bool
, dumpPrefix :: FilePath , dumpPrefix :: FilePath
} deriving (Typeable, Data) } deriving (Typeable, Data)
...@@ -78,6 +79,9 @@ defaultJob = Job ...@@ -78,6 +79,9 @@ defaultJob = Job
&= help ("How to write output; default is 'stdout'; use 'adjacent' to" &= help ("How to write output; default is 'stdout'; use 'adjacent' to"
++ " create a .v file next to each input; use a path ending in .v" ++ " create a .v file next to each input; use a path ending in .v"
++ " to write to a file") ++ " to write to a file")
, top = def &= name "top" &= explicit &= typ "NAME"
&= help ("Remove uninstantiated modules except the given top module;"
++ " can be used multiple times")
, oversizedNumbers = nam_ "oversized-numbers" , oversizedNumbers = nam_ "oversized-numbers"
&= help ("Disable standard-imposed 32-bit limit on unsized number" &= help ("Disable standard-imposed 32-bit limit on unsized number"
++ " literals (e.g., 'h1_ffff_ffff, 4294967296)") ++ " literals (e.g., 'h1_ffff_ffff, 4294967296)")
......
...@@ -84,9 +84,12 @@ main = do ...@@ -84,9 +84,12 @@ main = do
Right inputs -> do Right inputs -> do
let (inPaths, asts) = unzip inputs let (inPaths, asts) = unzip inputs
-- convert the files if requested -- convert the files if requested
asts' <- if passThrough job let converter = convert (top job) (dumpPrefix job) (exclude job)
then return asts asts' <-
else convert (dumpPrefix job) (exclude job) asts if passThrough job then
return asts
else
converter asts
emptyWarnings (concat asts) (concat asts') emptyWarnings (concat asts) (concat asts')
-- write the converted files out -- write the converted files out
writeOutput (write job) inPaths asts' writeOutput (write job) inPaths asts'
......
...@@ -75,6 +75,7 @@ Many of these suites test a particular feature of the sv2v CLI. ...@@ -75,6 +75,7 @@ Many of these suites test a particular feature of the sv2v CLI.
* `number` generates and tests short number literals * `number` generates and tests short number literals
* `search` tests `-y`/`--libdir` * `search` tests `-y`/`--libdir`
* `siloed` tests `--siloed` and default compilation unit behavior * `siloed` tests `--siloed` and default compilation unit behavior
* `top` tests `--top`
* `truncate` tests number literal truncation and `--oversized-numbers` * `truncate` tests number literal truncation and `--oversized-numbers`
* `warning` tests conversion warnings * `warning` tests conversion warnings
* `write` tests `-w`/`--write` * `write` tests `-w`/`--write`
......
module top_a;
initial $display("top_a");
mod m();
endmodule
module top_b;
initial $display("top_b");
intf i();
sub s(i);
endmodule
module mod;
initial $display("mod");
endmodule
interface intf;
initial $display("intf");
endinterface
module sub(interface i);
initial $display("sub");
endmodule
module top_c;
parameter type T;
parameter U;
initial if ($bits(T) == 1) $display("top_c");
endmodule
module top_d;
initial $display("top_d");
endmodule
#!/bin/bash
assertHasPrints() {
for module in "$@"; do
assertContains $module "$stdout" "display(\"$module\");"
done
}
assertDoesNotHavePrints() {
for module in "$@"; do
assertNotContains $module "$stdout" "display(\"$module\");"
done
}
convertSuccessful() {
runAndCapture main.sv "$@"
assertTrue "conversion should succeed" $result
assertNotNull "stdout should not be empty" "$stdout"
assertNull "stderr should be empty" "$stderr"
}
test_default() {
convertSuccessful
assertHasPrints top_a top_b top_d mod intf sub
assertDoesNotHavePrints top_c
}
test_tops_a() {
convertSuccessful --top top_a
assertHasPrints top_a mod
assertDoesNotHavePrints top_b top_c top_d intf sub
}
test_tops_b() {
convertSuccessful --top top_b
assertHasPrints top_b intf sub
assertDoesNotHavePrints top_a top_c top_d mod
}
test_tops_mod() {
convertSuccessful --top mod
assertHasPrints mod
assertDoesNotHavePrints top_a top_b top_c top_d intf sub
}
test_tops_a_b() {
convertSuccessful --top top_a --top top_b
assertHasPrints top_a top_b mod intf sub
assertDoesNotHavePrints top_c top_d
}
test_tops_a_d() {
convertSuccessful --top top_a --top top_d
assertHasPrints top_a top_d mod
assertDoesNotHavePrints top_b top_c intf sub
}
test_tops_b_d_mod() {
convertSuccessful --top top_b --top top_d --top mod
assertHasPrints top_b top_d mod intf sub
assertDoesNotHavePrints top_a top_c
}
test_error_no_default() {
runAndCapture main.sv --top top_c
assertFalse "conversion should fail" $result
assertNull "stdout should be empty" "$stdout"
assertContains "$stderr" "Specified top module top_c is missing default parameter value(s) for T, U"
}
test_error_is_an_interface() {
runAndCapture main.sv --top intf
assertFalse "conversion should fail" $result
assertNull "stdout should be empty" "$stdout"
assertContains "$stderr" "Specified top module intf is an interface. Please"
}
test_error_has_interface_ports() {
runAndCapture main.sv --top sub
assertFalse "conversion should fail" $result
assertNull "stdout should be empty" "$stdout"
assertContains "$stderr" "Specified top module sub has interface ports. Please"
}
test_error_not_found() {
runAndCapture main.sv --top fake
assertFalse "conversion should fail" $result
assertNull "stdout should be empty" "$stdout"
assertContains "$stderr" "Could not find top module fake"
}
source ../lib/functions.sh
. shunit2
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