mirror of https://github.com/zachjs/sv2v.git
support for parameters without defaults
This commit is contained in:
parent
e94c0346e8
commit
ea56f51d03
|
|
@ -33,6 +33,7 @@ import qualified Convert.MultiplePacked
|
|||
import qualified Convert.NamedBlock
|
||||
import qualified Convert.NestPI
|
||||
import qualified Convert.Package
|
||||
import qualified Convert.ParamNoDefault
|
||||
import qualified Convert.ParamType
|
||||
import qualified Convert.RemoveComments
|
||||
import qualified Convert.SignCast
|
||||
|
|
@ -109,7 +110,9 @@ run excludes = foldr (.) id $ phases excludes
|
|||
|
||||
convert :: [Job.Exclude] -> Phase
|
||||
convert excludes =
|
||||
convert' . Convert.NestPI.reorder
|
||||
convert'
|
||||
. Convert.NestPI.reorder
|
||||
. Convert.ParamNoDefault.convert
|
||||
where
|
||||
convert' :: Phase
|
||||
convert' descriptions =
|
||||
|
|
|
|||
|
|
@ -588,19 +588,6 @@ pattern InstArrKey expr = Dot (Bit expr (RawNum 0)) InstArrName
|
|||
pattern InstArrEncoded :: Expr -> Expr -> ModuleItem
|
||||
pattern InstArrEncoded l r = Modport InstArrName (InstArrVal l r)
|
||||
|
||||
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
|
||||
|
||||
-- given a list of module items, produces the parameter names in order
|
||||
parameterNames :: [ModuleItem] -> [Identifier]
|
||||
parameterNames =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Conversion for parameters without default values
|
||||
-
|
||||
- This conversion ensures that any parameters which don't have a default value
|
||||
- are always given an explicit value wherever that module or interface is used.
|
||||
-
|
||||
- Parameters are given a fake default value if they do not have one so that the
|
||||
- given source for that module can be consumed by downstream tools. This is not
|
||||
- done for type parameters, as those modules are rewritten by a separate
|
||||
- conversion. Localparams without defaults are expressly caught and forbidden.
|
||||
-}
|
||||
|
||||
module Convert.ParamNoDefault (convert) where
|
||||
|
||||
import Control.Monad.Writer.Strict
|
||||
import Data.List (intercalate)
|
||||
import qualified Data.Map.Strict as Map
|
||||
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
type Parts = Map.Map Identifier [(Identifier, Bool)]
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert files =
|
||||
map convertFile files'
|
||||
where
|
||||
(files', parts) = runWriter $
|
||||
mapM (traverseDescriptionsM traverseDescriptionM) files
|
||||
convertFile = traverseDescriptions $ traverseModuleItems $
|
||||
traverseModuleItem parts
|
||||
|
||||
traverseDescriptionM :: Description -> Writer Parts Description
|
||||
traverseDescriptionM (Part attrs extern kw lifetime name ports items) = do
|
||||
let (items', params) = runWriter $ mapM traverseModuleItemM items
|
||||
tell $ Map.singleton name params
|
||||
return $ Part attrs extern kw lifetime name ports items'
|
||||
traverseDescriptionM other = return other
|
||||
|
||||
traverseModuleItemM :: ModuleItem -> Writer [(Identifier, Bool)] ModuleItem
|
||||
traverseModuleItemM (MIAttr attr item) =
|
||||
traverseModuleItemM item >>= return . MIAttr attr
|
||||
traverseModuleItemM (MIPackageItem (Decl decl)) =
|
||||
traverseDeclM decl >>= return . MIPackageItem . Decl
|
||||
traverseModuleItemM other = return other
|
||||
|
||||
-- writes down the parameters for a part
|
||||
traverseDeclM :: Decl -> Writer [(Identifier, Bool)] Decl
|
||||
traverseDeclM (Param Localparam _ x Nil) =
|
||||
error $ "localparam " ++ show x ++ " has no default value"
|
||||
traverseDeclM (Param Parameter t x e) = do
|
||||
tell [(x, e == Nil)]
|
||||
return $ if e == Nil
|
||||
then Param Parameter t x $ RawNum 0
|
||||
else Param Parameter t x e
|
||||
traverseDeclM (ParamType Localparam x Nothing) =
|
||||
error $ "localparam type " ++ show x ++ " has no default value"
|
||||
traverseDeclM (ParamType Parameter x mt) = do
|
||||
-- parameter types are rewritten separately, so no fake default here
|
||||
tell [(x, mt == Nothing)]
|
||||
return $ ParamType Parameter x mt
|
||||
traverseDeclM other = return other
|
||||
|
||||
-- check for instances missing values for parameters without defaults
|
||||
traverseModuleItem :: Parts -> ModuleItem -> ModuleItem
|
||||
traverseModuleItem parts (orig @ (Instance part params name _ _)) =
|
||||
if maybePartInfo == Nothing || null missingParams
|
||||
then orig
|
||||
else error $ "instance " ++ show name ++ " of " ++ show part
|
||||
++ " is missing values for parameters without defaults: "
|
||||
++ (intercalate " " $ map show missingParams)
|
||||
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
|
||||
traverseModuleItem _ other = other
|
||||
|
||||
-- whether a given parameter is unspecified in the given parameter bindings
|
||||
needsDefault :: [(Identifier, TypeOrExpr)] -> Identifier -> Bool
|
||||
needsDefault instanceParams param =
|
||||
case lookup param instanceParams of
|
||||
Nothing -> True
|
||||
Just (Right Nil) -> True
|
||||
Just _ -> False
|
||||
|
|
@ -29,6 +29,7 @@ module Language.SystemVerilog.AST
|
|||
, exprToLHS
|
||||
, lhsToExpr
|
||||
, shortHash
|
||||
, resolveBindings
|
||||
) where
|
||||
|
||||
import Text.Printf (printf)
|
||||
|
|
@ -84,3 +85,16 @@ shortHash :: (Show a) => a -> String
|
|||
shortHash x =
|
||||
take 5 $ printf "%05X" val
|
||||
where val = hash $ show 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
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ data Decl
|
|||
|
||||
instance Show Decl where
|
||||
showList l _ = unlines' $ map show l
|
||||
show (Param s t x e) = printf "%s %s%s = %s;" (show s) (showPad t) x (show e)
|
||||
show (Param s t x e) = printf "%s %s%s%s;" (show s) (showPad t) x (showAssignment e)
|
||||
show (ParamType s x mt) = printf "%s type %s%s;" (show s) x tStr
|
||||
where tStr = maybe "" ((" = " ++) . show) mt
|
||||
show (Variable d t x a e) = printf "%s%s%s%s%s;" (showPad d) (showPad t) x (showRanges a) (showAssignment e)
|
||||
|
|
|
|||
|
|
@ -921,8 +921,10 @@ DeclAsgns :: { [(Identifier, Expr, [Range])] }
|
|||
: DeclAsgn { [$1] }
|
||||
| DeclAsgns "," DeclAsgn { $1 ++ [$3] }
|
||||
DeclAsgn :: { (Identifier, Expr, [Range]) }
|
||||
: Identifier "=" Expr { ($1, $3, []) }
|
||||
| Identifier DimensionsNonEmpty "=" Expr { ($1, $4, $2) }
|
||||
: Identifier "=" Expr { ($1, $3, []) }
|
||||
| Identifier DimensionsNonEmpty "=" Expr { ($1, $4, $2) }
|
||||
| Identifier { ($1, Nil, []) }
|
||||
| Identifier DimensionsNonEmpty { ($1, Nil, $2) }
|
||||
|
||||
Range :: { Range }
|
||||
: "[" Expr ":" Expr "]" { ($2, $4) }
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ executable sv2v
|
|||
Convert.NamedBlock
|
||||
Convert.NestPI
|
||||
Convert.Package
|
||||
Convert.ParamNoDefault
|
||||
Convert.ParamType
|
||||
Convert.RemoveComments
|
||||
Convert.Scoper
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
`define DUMP(name) initial $display(`"name W=%b $bits(X)=%0d Y=%b $bits(Z)=%0d", W, $bits(X), Y, $bits(Z));
|
||||
|
||||
interface InterfaceA #(
|
||||
parameter W,
|
||||
parameter type X,
|
||||
parameter byte Y,
|
||||
parameter type Z
|
||||
);
|
||||
`DUMP(InterfaceA)
|
||||
endinterface
|
||||
|
||||
interface InterfaceB;
|
||||
parameter W;
|
||||
parameter type X;
|
||||
parameter byte Y;
|
||||
parameter type Z;
|
||||
`DUMP(InterfaceB)
|
||||
endinterface
|
||||
|
||||
module ModuleA #(
|
||||
parameter W,
|
||||
parameter type X,
|
||||
parameter byte Y,
|
||||
parameter type Z
|
||||
);
|
||||
`DUMP(ModuleA)
|
||||
endmodule
|
||||
|
||||
module ModuleB;
|
||||
parameter W;
|
||||
parameter type X;
|
||||
parameter byte Y;
|
||||
parameter type Z;
|
||||
`DUMP(ModuleB)
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
`define PARAMS_A #(.Y(6), .X(logic [4:0]), .Z(logic [6:0]), .W(4))
|
||||
`define PARAMS_B #(0, logic, 2, logic [2:0])
|
||||
InterfaceA `PARAMS_A ia1();
|
||||
InterfaceA `PARAMS_B ia2();
|
||||
InterfaceB `PARAMS_A ib1();
|
||||
InterfaceB `PARAMS_B ib2();
|
||||
ModuleA `PARAMS_A ma1();
|
||||
ModuleA `PARAMS_B ma2();
|
||||
ModuleB `PARAMS_A mb1();
|
||||
ModuleB `PARAMS_B mb2();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
`define DUMP(name) initial $display(`"name W=%b $bits(X)=%0d Y=%b $bits(Z)=%0d`", W, X, Y, Z);
|
||||
|
||||
module InterfaceA #(
|
||||
parameter W = 9,
|
||||
parameter X = 9,
|
||||
parameter [7:0] Y = 9,
|
||||
parameter Z = 9
|
||||
);
|
||||
`DUMP(InterfaceA)
|
||||
endmodule
|
||||
|
||||
module InterfaceB;
|
||||
parameter W = 9;
|
||||
parameter X = 9;
|
||||
parameter [7:0] Y = 9;
|
||||
parameter Z = 9;
|
||||
`DUMP(InterfaceB)
|
||||
endmodule
|
||||
|
||||
module ModuleA #(
|
||||
parameter W = 9,
|
||||
parameter X = 9,
|
||||
parameter [7:0] Y = 9,
|
||||
parameter Z = 9
|
||||
);
|
||||
`DUMP(ModuleA)
|
||||
endmodule
|
||||
|
||||
module ModuleB;
|
||||
parameter W = 9;
|
||||
parameter X = 9;
|
||||
parameter [7:0] Y = 9;
|
||||
parameter Z = 9;
|
||||
`DUMP(ModuleB)
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
`define PARAMS_A #(.Y(6), .X(5), .Z(7), .W(4))
|
||||
`define PARAMS_B #(0, 1, 2, 3)
|
||||
InterfaceA `PARAMS_A ia1();
|
||||
InterfaceA `PARAMS_B ia2();
|
||||
InterfaceB `PARAMS_A ib1();
|
||||
InterfaceB `PARAMS_B ib2();
|
||||
ModuleA `PARAMS_A ma1();
|
||||
ModuleA `PARAMS_B ma2();
|
||||
ModuleB `PARAMS_A mb1();
|
||||
ModuleB `PARAMS_B mb2();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// pattern: localparam "X" has no default value
|
||||
module top;
|
||||
localparam X;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// pattern: localparam type "X" has no default value
|
||||
module top;
|
||||
localparam type X;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// pattern: instance "e" of "Example" is missing values for parameters without defaults: "X"
|
||||
module Example;
|
||||
parameter type X;
|
||||
endmodule
|
||||
module top;
|
||||
Example e();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// pattern: instance "bad" of "Example" is missing values for parameters without defaults: "Y"
|
||||
module Example;
|
||||
parameter X = 1;
|
||||
parameter Y;
|
||||
endmodule
|
||||
module top;
|
||||
Example #(.Y(1)) good();
|
||||
Example #(1) bad();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// pattern: instance "bad" of "Example" is missing values for parameters without defaults: "Y"
|
||||
interface Example;
|
||||
parameter X = 1;
|
||||
parameter Y;
|
||||
endinterface
|
||||
module top;
|
||||
Example #(.Y(1)) good();
|
||||
Example #(.Y()) bad();
|
||||
endmodule
|
||||
Loading…
Reference in New Issue