Commit 911243da by Zachary Snow

add --top for filtering uninstantiated modules

parent 3b2a55a6
......@@ -5,6 +5,7 @@
* Added `-y`/`--libdir` for specifying library directories from which to
automatically load modules and interfaces used in the design that are not
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
* Added support for passing through `sequence` and `property` declarations
......
......@@ -107,6 +107,8 @@ Conversion:
-w --write=MODE/FILE How to write output; default is 'stdout'; use
'adjacent' to create a .v file next to each input;
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:
--oversized-numbers Disable standard-imposed 32-bit limit on unsized
number literals (e.g., 'h1_ffff_ffff, 4294967296)
......
......@@ -75,8 +75,8 @@ finalPhases _ =
, Convert.StringType.convert
]
mainPhases :: Selector -> [Phase]
mainPhases selectExclude =
mainPhases :: [String] -> Selector -> [Phase]
mainPhases tops selectExclude =
[ Convert.BlockDecl.convert
, selectExclude Job.Logic Convert.Logic.convert
, Convert.ImplicitNet.convert
......@@ -85,7 +85,7 @@ mainPhases selectExclude =
, Convert.MultiplePacked.convert
, selectExclude Job.UnbasedUnsized Convert.UnbasedUnsized.convert
, Convert.Cast.convert
, Convert.ParamType.convert
, Convert.ParamType.convert tops
, Convert.HierConst.convert
, Convert.TypeOf.convert
, Convert.DimensionQuery.convert
......@@ -98,12 +98,12 @@ mainPhases selectExclude =
, Convert.Wildcard.convert
, Convert.Enum.convert
, Convert.StringParam.convert
, selectExclude Job.Interface Convert.Interface.convert
, selectExclude Job.Interface $ Convert.Interface.convert tops
, selectExclude Job.Succinct Convert.RemoveComments.convert
]
initialPhases :: Selector -> [Phase]
initialPhases selectExclude =
initialPhases :: [String] -> Selector -> [Phase]
initialPhases tops selectExclude =
[ Convert.ForAsgn.convert
, Convert.Jump.convert
, Convert.ExprAsgn.convert
......@@ -119,21 +119,21 @@ initialPhases selectExclude =
, Convert.Package.convert
, Convert.StructConst.convert
, Convert.PortDecl.convert
, Convert.ParamNoDefault.convert
, Convert.ParamNoDefault.convert tops
, Convert.ResolveBindings.convert
, Convert.UnnamedGenBlock.convert
]
convert :: FilePath -> [Job.Exclude] -> IOPhase
convert dumpPrefix excludes =
convert :: [String] -> FilePath -> [Job.Exclude] -> IOPhase
convert tops dumpPrefix excludes =
step "parse" id >=>
step "initial" initial >=>
loop 1 "main" main >=>
step "final" final
where
final = combine $ finalPhases selectExclude
main = combine $ mainPhases selectExclude
initial = combine $ initialPhases selectExclude
main = combine $ mainPhases tops selectExclude
initial = combine $ initialPhases tops selectExclude
combine = foldr1 (.)
selectExclude :: Selector
......
......@@ -29,13 +29,13 @@ type ModportInstances = [(Identifier, (Identifier, Identifier))]
type ModportBinding = (Identifier, (Substitutions, Expr))
type Substitutions = [(Expr, Expr)]
convert :: [AST] -> [AST]
convert files =
convert :: [Identifier] -> [AST] -> [AST]
convert tops files =
if needsFlattening
then files
else traverseFiles
(collectDescriptionsM collectPart)
(map . convertDescription)
(map . convertDescription tops)
files
where
-- we can only collect/map non-extern interfaces and modules
......@@ -55,12 +55,22 @@ convert files =
checkItem (Instance _ _ _ rs _) = when (length rs > 1) $ tell $ Any True
checkItem _ = return ()
convertDescription :: PartInfos -> Description -> Description
convertDescription _ (Part _ _ Interface _ name _ _) =
PackageItem $ Decl $ CommentDecl $ "removed interface: " ++ name
convertDescription parts (Part attrs extern Module lifetime name ports items) =
topInterfaceError :: String -> String -> a
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
convertDescription tops parts (Part att ext Module lif name ports items) =
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
PackageItem $ Decl $ CommentDecl $
"removed module with interface ports: " ++ name
......@@ -324,7 +334,7 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
Nothing -> False
Just info -> pKind info == Interface
convertDescription _ other = other
convertDescription _ _ other = other
isDecl :: ModuleItem -> Bool
isDecl (MIPackageItem Decl{}) = True
......
......@@ -23,21 +23,32 @@ import Language.SystemVerilog.AST
type Parts = Map.Map Identifier [(Identifier, Bool)]
convert :: [AST] -> [AST]
convert files =
convert :: [Identifier] -> [AST] -> [AST]
convert tops files =
flip (foldr $ ensureTopExists parts) tops $
map convertFile files'
where
(files', parts) = runWriter $
mapM (traverseDescriptionsM traverseDescriptionM) files
mapM (traverseDescriptionsM $ traverseDescriptionM tops) files
convertFile = traverseDescriptions $ traverseModuleItems $
traverseModuleItem parts
traverseDescriptionM :: Description -> Writer Parts Description
traverseDescriptionM (Part attrs extern kw lifetime name ports items) = do
ensureTopExists :: Parts -> Identifier -> a -> a
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
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'
traverseDescriptionM other = return other
traverseDescriptionM _ other = return other
traverseModuleItemM :: ModuleItem -> Writer [(Identifier, Bool)] ModuleItem
traverseModuleItemM (MIAttr attr item) =
......
......@@ -26,8 +26,8 @@ type IdentSet = Set.Set Identifier
type DeclMap = Map.Map Identifier Decl
type UsageMap = [(Identifier, Set.Set Identifier)]
convert :: [AST] -> [AST]
convert files =
convert :: [Identifier] -> [AST] -> [AST]
convert tops files =
files'''
where
modules = execWriter $
......@@ -74,10 +74,11 @@ convert files =
keepDescription :: Description -> Bool
keepDescription (Part _ _ _ _ name _ _) =
isNewModule
|| isntTyped
|| isntTyped && (isTopOrNoTop || isInstantiated)
|| isUsedAsUntyped
|| isUsedAsTyped && isInstantiatedViaNonTyped
|| allTypesHaveDefaults && notInstantiated && isntTemplateTagged
&& isTopOrNoTop
where
maybeTypeMap = Map.lookup name modules
Just typeMap = maybeTypeMap
......@@ -88,7 +89,9 @@ convert files =
isInstantiatedViaNonTyped = untypedUsageSearch $ Set.singleton name
allTypesHaveDefaults = all (/= UnknownType) (Map.elems typeMap)
notInstantiated = lookup name instances == Nothing
isInstantiated = not notInstantiated
isntTemplateTagged = not $ isTemplateTagged name
isTopOrNoTop = null tops || elem name tops
keepDescription _ = True
-- instantiate the type parameters if this is a used default instance
......
......@@ -45,6 +45,7 @@ data Job = Job
, verbose :: Bool
, write :: Write
, writeRaw :: String
, top :: [String]
, oversizedNumbers :: Bool
, dumpPrefix :: FilePath
} deriving (Typeable, Data)
......@@ -78,6 +79,9 @@ defaultJob = Job
&= 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"
++ " 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"
&= help ("Disable standard-imposed 32-bit limit on unsized number"
++ " literals (e.g., 'h1_ffff_ffff, 4294967296)")
......
......@@ -84,9 +84,12 @@ main = do
Right inputs -> do
let (inPaths, asts) = unzip inputs
-- convert the files if requested
asts' <- if passThrough job
then return asts
else convert (dumpPrefix job) (exclude job) asts
let converter = convert (top job) (dumpPrefix job) (exclude job)
asts' <-
if passThrough job then
return asts
else
converter asts
emptyWarnings (concat asts) (concat asts')
-- write the converted files out
writeOutput (write job) inPaths asts'
......
......@@ -75,6 +75,7 @@ Many of these suites test a particular feature of the sv2v CLI.
* `number` generates and tests short number literals
* `search` tests `-y`/`--libdir`
* `siloed` tests `--siloed` and default compilation unit behavior
* `top` tests `--top`
* `truncate` tests number literal truncation and `--oversized-numbers`
* `warning` tests conversion warnings
* `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