mirror of https://github.com/zachjs/sv2v.git
add --top for filtering uninstantiated modules
This commit is contained in:
parent
3b2a55a69c
commit
911243dac4
|
|
@ -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 _ _) =
|
||||
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 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
|
||||
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`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
#!/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
|
||||
Loading…
Reference in New Issue