From 5cc4dce01f19433e9434a19967f358d01e6bb6fb Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Fri, 30 Apr 2021 13:42:36 -0400 Subject: [PATCH] refactor positional binding checking and resolution --- src/Convert.hs | 4 +- src/Convert/Interface.hs | 18 +------- src/Convert/Package.hs | 3 +- src/Convert/ParamNoDefault.hs | 3 +- src/Convert/ResolveBindings.hs | 67 ++++++++++++++++++++++++++++ src/Convert/StarPort.hs | 42 ----------------- src/Convert/Traverse.hs | 2 +- src/Language/SystemVerilog/AST.hs | 19 ++++---- sv2v.cabal | 2 +- test/error/binding_overflow_class.sv | 10 +++++ test/error/binding_overflow_param.sv | 8 ++++ test/error/binding_overflow_port.sv | 8 ++++ 12 files changed, 111 insertions(+), 75 deletions(-) create mode 100644 src/Convert/ResolveBindings.hs delete mode 100644 src/Convert/StarPort.hs create mode 100644 test/error/binding_overflow_class.sv create mode 100644 test/error/binding_overflow_param.sv create mode 100644 test/error/binding_overflow_port.sv diff --git a/src/Convert.hs b/src/Convert.hs index ca4cf78..3ae7d92 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -37,8 +37,8 @@ import qualified Convert.Package import qualified Convert.ParamNoDefault import qualified Convert.ParamType import qualified Convert.RemoveComments +import qualified Convert.ResolveBindings import qualified Convert.Simplify -import qualified Convert.StarPort import qualified Convert.Stream import qualified Convert.StringParam import qualified Convert.Struct @@ -100,11 +100,11 @@ initialPhases selectExclude = , Convert.Unique.convert , Convert.LogOp.convert , Convert.Foreach.convert - , Convert.StarPort.convert , selectExclude Job.Assert Convert.Assertion.convert , selectExclude Job.Always Convert.AlwaysKW.convert , Convert.Package.convert , Convert.ParamNoDefault.convert + , Convert.ResolveBindings.convert ] convert :: [Job.Exclude] -> Phase diff --git a/src/Convert/Interface.hs b/src/Convert/Interface.hs index 68d1afb..be0b504 100644 --- a/src/Convert/Interface.hs +++ b/src/Convert/Interface.hs @@ -96,15 +96,11 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) = inlineInstance rs modportBindings partItems part instanceName paramBindings portBindings where - Instance part rawParamBindings instanceName rs rawPortBindings = + Instance part paramBindings instanceName rs portBindings = instanceItem maybePartInfo = Map.lookup part parts Just partInfo = maybePartInfo - PartInfo partKind partPorts partItems = partInfo - - partParams = parameterNames partItems - paramBindings = resolveBindings partParams rawParamBindings - portBindings = resolveBindings partPorts rawPortBindings + PartInfo partKind _ partItems = partInfo modportInstances = extractModportInstances partInfo getModportBindings modports = mapMaybe @@ -583,16 +579,6 @@ pattern InstArrKey expr = Dot (Bit expr (RawNum 0)) InstArrName pattern InstArrEncoded :: Expr -> Expr -> ModuleItem pattern InstArrEncoded l r = Modport InstArrName (InstArrVal l r) --- given a list of module items, produces the parameter names in order -parameterNames :: [ModuleItem] -> [Identifier] -parameterNames = - execWriter . mapM (collectNestedModuleItemsM $ collectDeclsM collectDeclM) - where - collectDeclM :: Decl -> Writer [Identifier] () - collectDeclM (Param Parameter _ x _) = tell [x] - collectDeclM (ParamType Parameter x _) = tell [x] - collectDeclM _ = return () - -- determines the lower bound for the given slice sliceLo :: PartSelectMode -> Range -> Expr sliceLo NonIndexed (l, r) = endianCondExpr (l, r) r l diff --git a/src/Convert/Package.hs b/src/Convert/Package.hs index 53ac738..dde27e2 100644 --- a/src/Convert/Package.hs +++ b/src/Convert/Package.hs @@ -450,8 +450,9 @@ resolveCSIdent className paramBindings scopeKeys itemName = do "could not find class " ++ show className let Just (classParams, classItems) = maybeClass -- resolve the provided parameters + let resolveMsg = "parameters in class specialization of " ++ show className let paramNames = mapMaybe extractParameterName classParams - let paramBindings' = resolveBindings paramNames paramBindings + let paramBindings' = resolveBindings resolveMsg paramNames paramBindings -- generate a unique name for this synthetic package let packageName = className ++ '_' : shortHash (scopeKeys, paramBindings') -- process the synthetic package and inject the given parameters diff --git a/src/Convert/ParamNoDefault.hs b/src/Convert/ParamNoDefault.hs index 3c121da..4437c01 100644 --- a/src/Convert/ParamNoDefault.hs +++ b/src/Convert/ParamNoDefault.hs @@ -74,9 +74,8 @@ traverseModuleItem parts (orig @ (Instance part params name _ _)) = where maybePartInfo = Map.lookup part parts Just partInfo = maybePartInfo - paramsResolved = resolveBindings (map fst partInfo) params paramsWithNoDefault = map fst $ filter snd partInfo - missingParams = filter (needsDefault paramsResolved) paramsWithNoDefault + missingParams = filter (needsDefault params) paramsWithNoDefault traverseModuleItem _ other = other -- whether a given parameter is unspecified in the given parameter bindings diff --git a/src/Convert/ResolveBindings.hs b/src/Convert/ResolveBindings.hs new file mode 100644 index 0000000..6498640 --- /dev/null +++ b/src/Convert/ResolveBindings.hs @@ -0,0 +1,67 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion for `.*` and unnamed bindings + - + - While positional bindings need not be converted, resolving them here + - simplifies downstream conversions. + -} + +module Convert.ResolveBindings (convert) where + +import Control.Monad.Writer.Strict +import qualified Data.Map.Strict as Map + +import Convert.Traverse +import Language.SystemVerilog.AST + +type Ports = Map.Map Identifier ([Identifier], [Identifier]) + +convert :: [AST] -> [AST] +convert = + traverseFiles + (collectDescriptionsM collectPortsM) + (traverseDescriptions . traverseModuleItems . mapInstance) + +collectPortsM :: Description -> Writer Ports () +collectPortsM (Part _ _ _ _ name ports items) = + tell $ Map.singleton name (params, ports) + where params = parameterNames items +collectPortsM _ = return () + +-- given a list of module items, produces the parameter names in order +parameterNames :: [ModuleItem] -> [Identifier] +parameterNames = + execWriter . mapM (collectNestedModuleItemsM $ collectDeclsM collectDeclM) + where + collectDeclM :: Decl -> Writer [Identifier] () + collectDeclM (Param Parameter _ x _) = tell [x] + collectDeclM (ParamType Parameter x _) = tell [x] + collectDeclM _ = return () + +mapInstance :: Ports -> ModuleItem -> ModuleItem +mapInstance modulePorts (Instance m paramBindings x rs portBindings) = + -- if we can't find it, just skip :( + if maybeModuleInfo == Nothing + then Instance m paramBindings x rs portBindings + else Instance m paramBindings' x rs portBindings' + where + maybeModuleInfo = Map.lookup m modulePorts + Just (paramNames, portNames) = maybeModuleInfo + + msg :: String -> String + msg = flip (++) $ " in instance " ++ show x ++ " of " ++ show m + + paramBindings' = resolveBindings (msg "parameter overrides") paramNames + paramBindings + portBindings' = resolveBindings (msg "port connections") portNames + $ concatMap expandStar portBindings + + expandStar :: PortBinding -> [PortBinding] + expandStar ("*", Nil) = + map (\port -> (port, Ident port)) $ + filter (flip notElem alreadyBound) portNames + where alreadyBound = map fst portBindings + expandStar other = [other] + +mapInstance _ other = other diff --git a/src/Convert/StarPort.hs b/src/Convert/StarPort.hs deleted file mode 100644 index 8b7a40b..0000000 --- a/src/Convert/StarPort.hs +++ /dev/null @@ -1,42 +0,0 @@ -{- sv2v - - Author: Zachary Snow - - - - Conversion for `.*` in module instantiation - -} - -module Convert.StarPort (convert) where - -import Control.Monad.Writer.Strict -import qualified Data.Map.Strict as Map - -import Convert.Traverse -import Language.SystemVerilog.AST - -type Ports = Map.Map Identifier [Identifier] - -convert :: [AST] -> [AST] -convert = - traverseFiles - (collectDescriptionsM collectPortsM) - (traverseDescriptions . traverseModuleItems . mapInstance) - -collectPortsM :: Description -> Writer Ports () -collectPortsM (Part _ _ _ _ name ports _) = tell $ Map.singleton name ports -collectPortsM _ = return () - -mapInstance :: Ports -> ModuleItem -> ModuleItem -mapInstance modulePorts (Instance m p x rs bindings) = - Instance m p x rs $ concatMap expandBinding bindings - where - alreadyBound :: [Identifier] - alreadyBound = map fst bindings - expandBinding :: PortBinding -> [PortBinding] - expandBinding ("*", Nil) = - case Map.lookup m modulePorts of - Just l -> - map (\port -> (port, Ident port)) $ - filter (\s -> not $ elem s alreadyBound) $ l - -- if we can't find it, just skip :( - Nothing -> [("*", Nil)] - expandBinding other = [other] -mapInstance _ other = other diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index b5c4979..3edc5ed 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -1109,7 +1109,7 @@ traverseNestedModuleItemsM mapper = fullMapper Nothing -> return $ GenIf (Number n) s1 s2 Just 0 -> genItemMapper s2 Just _ -> genItemMapper s1 - genItemMapper (GenBlock "" [item]) = return item + genItemMapper (GenBlock "" [item]) = genItemMapper item genItemMapper (GenBlock _ []) = return GenNull genItemMapper other = return other diff --git a/src/Language/SystemVerilog/AST.hs b/src/Language/SystemVerilog/AST.hs index 43813c1..fdef780 100644 --- a/src/Language/SystemVerilog/AST.hs +++ b/src/Language/SystemVerilog/AST.hs @@ -88,13 +88,12 @@ shortHash x = type Binding t = (Identifier, t) -- give a set of bindings explicit names -resolveBindings :: Show t => [Identifier] -> [Binding t] -> [Binding t] -resolveBindings available bindings = - zipWith resolveBinding bindings [0..] - where - resolveBinding ("", e) idx = - if idx < length available - then (available !! idx, e) - else error $ "binding " ++ show e ++ " is out of range " - ++ show available - resolveBinding other _ = other +resolveBindings :: String -> [Identifier] -> [Binding t] -> [Binding t] +resolveBindings _ _ [] = [] +resolveBindings location available bindings = + if length available < length bindings then + error $ "too many bindings specified for " ++ location + else if null $ fst $ head bindings then + zip available $ map snd bindings + else + bindings diff --git a/sv2v.cabal b/sv2v.cabal index 1b49f7e..7c49dbb 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -87,9 +87,9 @@ executable sv2v Convert.ParamNoDefault Convert.ParamType Convert.RemoveComments + Convert.ResolveBindings Convert.Scoper Convert.Simplify - Convert.StarPort Convert.Stream Convert.StringParam Convert.Struct diff --git a/test/error/binding_overflow_class.sv b/test/error/binding_overflow_class.sv new file mode 100644 index 0000000..3357544 --- /dev/null +++ b/test/error/binding_overflow_class.sv @@ -0,0 +1,10 @@ +// pattern: too many bindings specified for parameters in class specialization of "example" +class example #( + parameter P = 1, + parameter Q = 1 +); + typedef logic [P * Q:0] T; +endclass +module top; + example#(1, 2, 3)::T x; +endmodule diff --git a/test/error/binding_overflow_param.sv b/test/error/binding_overflow_param.sv new file mode 100644 index 0000000..4279e2e --- /dev/null +++ b/test/error/binding_overflow_param.sv @@ -0,0 +1,8 @@ +// pattern: too many bindings specified for parameter overrides in instance "e" of "example" +module example; + parameter P = 1; + parameter Q = 1; +endmodule +module top; + example #(1, 2, 3) e(); +endmodule diff --git a/test/error/binding_overflow_port.sv b/test/error/binding_overflow_port.sv new file mode 100644 index 0000000..68d24d8 --- /dev/null +++ b/test/error/binding_overflow_port.sv @@ -0,0 +1,8 @@ +// pattern: too many bindings specified for port connections in instance "e" of "example" +module example( + input x, y +); +endmodule +module top; + example e(1'b1, 1'b0, 1'b0); +endmodule