added input port default conversion

This commit is contained in:
Zachary Snow 2025-02-23 18:08:18 -05:00
parent 8cc828c77f
commit 5d5723f65d
8 changed files with 187 additions and 11 deletions

View File

@ -2,6 +2,7 @@
### New Features
* Added support for module and interface input ports with default values
* Added conversion of severity system tasks and elaboration system tasks (e.g.,
`$info`) into `$display` tasks that include source file and scope information;
pass `-E SeverityTask` to disable this new conversion

View File

@ -43,6 +43,7 @@ import qualified Convert.Package
import qualified Convert.ParamNoDefault
import qualified Convert.ParamType
import qualified Convert.PortDecl
import qualified Convert.PortDefault
import qualified Convert.RemoveComments
import qualified Convert.ResolveBindings
import qualified Convert.SeverityTask
@ -75,6 +76,7 @@ finalPhases _ =
, Convert.FuncRet.convert
, Convert.TFBlock.convert
, Convert.Unsigned.convert
, Convert.PortDefault.convert
, Convert.StringType.convert
]

View File

@ -631,10 +631,14 @@ inlineInstance global ranges modportBindings items partName
removeDeclDir :: Decl -> Decl
removeDeclDir (Variable _ t x a e) =
Variable Local t' x a e
where t' = case t of
Variable Local t' x a e'
where
t' = case t of
Implicit sg rs -> IntegerVector TLogic sg rs
_ -> t
e' = if isNothing (lookup x instancePorts)
then e
else Nil
removeDeclDir decl@Net{} =
traverseNetAsVar removeDeclDir decl
removeDeclDir other = other

View File

@ -0,0 +1,92 @@
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for input ports with default values
-
- The default values are permitted to depend on complex constants declared
- within the instantiated module. The relevant constants are copied into the
- site of the instantiation.
-}
module Convert.PortDefault (convert) where
import Control.Monad.Writer.Strict
import Data.Functor ((<&>))
import qualified Data.Map.Strict as Map
import Data.Maybe (isNothing)
import Convert.Traverse
import Convert.UnbasedUnsized (inlineConstants)
import Language.SystemVerilog.AST
type Part = ([ModuleItem], [PortDefault])
type Parts = Map.Map Identifier Part
type PortDefault = (Identifier, Decl)
convert :: [AST] -> [AST]
convert files =
map (traverseDescriptions convertDescription) files'
where
(files', parts) = runWriter $
mapM (traverseDescriptionsM preparePart) files
convertDescription = traverseModuleItems $ convertModuleItem parts
-- remove and record input ports with defaults
preparePart :: Description -> Writer Parts Description
preparePart description@(Part att ext kw lif name ports items) =
if null portDefaults
then return description
else do
tell $ Map.singleton name (items, portDefaults)
return $ Part att ext kw lif name ports items'
where
(items', portDefaults) = runWriter $
mapM (traverseNestedModuleItemsM prepareModuleItem) items
preparePart other = return other
prepareModuleItem :: ModuleItem -> Writer [PortDefault] ModuleItem
prepareModuleItem (MIPackageItem (Decl decl)) =
prepareDecl decl <&> MIPackageItem . Decl
prepareModuleItem other = return other
prepareDecl :: Decl -> Writer [PortDefault] Decl
prepareDecl (Variable Input t x [] e) | e /= Nil =
preparePortDefault t x e >> return (Variable Input t x [] Nil)
prepareDecl (Net Input n s t x [] e) | e /= Nil =
preparePortDefault t x e >> return (Net Input n s t x [] Nil)
prepareDecl other = return other
preparePortDefault :: Type -> Identifier -> Expr -> Writer [PortDefault] ()
preparePortDefault t x e = tell [(x, decl)]
where
decl = Param Localparam t' x e
t' = case t of
Implicit sg [] -> Implicit sg [(RawNum 0, RawNum 0)]
_ -> t
-- add default port bindings to module instances that need them
convertModuleItem :: Parts -> ModuleItem -> ModuleItem
convertModuleItem parts (Instance moduleName params instanceName ds bindings) =
if isNothing maybePart || null neededDecls
then instanceBase bindings
else Generate $ map GenModuleItem $
stubItems ++ [instanceBase $ neededBindings ++ bindings]
where
instanceBase = Instance moduleName params instanceName ds
maybePart = Map.lookup moduleName parts
Just (moduleItems, portDefaults) = maybePart
-- determine which defaulted ports are unbound
(neededBindings, neededDecls) = unzip
[ ( (port, Ident $ blockName ++ '_' : port)
, MIPackageItem $ Decl decl
)
| (port, decl) <- portDefaults
, isNothing (lookup port bindings)
]
-- inline and prefix the declarations used by the defaults
stubItems = inlineConstants blockName params moduleItems neededDecls
blockName = "sv2v_pd_" ++ instanceName
convertModuleItem _ other = other

View File

@ -14,7 +14,10 @@
- creating hierarchical or generate-scoped references.
-}
module Convert.UnbasedUnsized (convert) where
module Convert.UnbasedUnsized
( convert
, inlineConstants
) where
import Control.Monad.Writer.Strict
import Data.Either (isLeft)
@ -62,7 +65,7 @@ convertModuleItem parts (Instance moduleName params instanceName ds bindings) =
-- checking whether we're ready to inline
hasTypeParams = any (isLeft . snd) params
moduleIsResolved = isEntirelyResolved selectedStubItems
moduleIsResolved = isEntirelyResolved stubItems
-- transform the existing bindings to reference extension declarations
(bindings', extensionDeclLists) = unzip $
@ -71,13 +74,18 @@ convertModuleItem parts (Instance moduleName params instanceName ds bindings) =
-- inline the necessary portions of the module alongside the selected
-- extension declarations
stubItems =
map (traverseDecls overrideParam) $
prefixItems blockName selectedStubItems
selectedStubItems = inject rawStubItems extensionDecls
rawStubItems = createModuleStub moduleItems
stubItems = inlineConstants blockName params moduleItems extensionDecls
blockName = "sv2v_uu_" ++ instanceName
convertModuleItem _ other = convertModuleItem' other
inlineConstants :: Identifier -> [ParamBinding] -> [ModuleItem] -> [ModuleItem]
-> [ModuleItem]
inlineConstants blockName params moduleItems =
map (traverseDecls overrideParam) .
prefixItems blockName .
inject (createModuleStub moduleItems)
where
-- override a parameter value in the stub
overrideParam :: Decl -> Decl
overrideParam (Param Parameter t x e) =
@ -89,8 +97,6 @@ convertModuleItem parts (Instance moduleName params instanceName ds bindings) =
where xOrig = drop (length blockName + 1) x
overrideParam decl = decl
convertModuleItem _ other = convertModuleItem' other
-- convert a port binding and produce a list of needed extension decls
convertBinding :: Identifier -> PortBinding -> (PortBinding, [Decl])
convertBinding blockName (portName, expr) =

View File

@ -95,6 +95,7 @@ executable sv2v
Convert.ParamNoDefault
Convert.ParamType
Convert.PortDecl
Convert.PortDefault
Convert.RemoveComments
Convert.ResolveBindings
Convert.Scoper

51
test/core/port_default.sv Normal file
View File

@ -0,0 +1,51 @@
module M(x, y);
parameter P = 0;
localparam L = 10;
function automatic integer F;
input integer inp;
return inp + L;
endfunction
input wire integer x = F(P); // defining a default here is non-standard
input wire integer y;
initial #1 $display("M %0d %0d", x, y);
endmodule
module N #(
parameter type P,
parameter type Q = integer,
localparam L = 10
) (
input wire P x = $bits(P) + L,
input wire Q y = $bits(Q) + L
);
initial #1 $display("N %b %b", x, y);
endmodule
interface I #(
parameter type P,
parameter type Q = integer,
localparam L = 10
) (
input wire P x = $bits(P) + L,
input wire Q y = $bits(Q) + L
);
initial #2 $display("I %b %b", x, y);
endinterface
module top;
M m0(0, 0);
M m1(.y(1));
M#(1) m2(.y(2));
N#(logic) n0();
N#(logic) n1(1'b0);
N#(logic) n2(.y(2));
N#(byte) n3();
N#(byte, shortint) n4();
I#(logic) i0();
I#(logic) i1(0);
I#(logic) i2(.y(2));
I#(byte) i3();
I#(byte, shortint) i4();
endmodule

19
test/core/port_default.v Normal file
View File

@ -0,0 +1,19 @@
module top;
initial #2 begin
$display("M %0d %0d", 0, 0);
$display("M %0d %0d", 10, 1);
$display("M %0d %0d", 11, 2);
$display("N %b %b", 1'b1, 32'd42);
$display("N %b %b", 1'b0, 32'd42);
$display("N %b %b", 1'b1, 32'd2);
$display("N %b %b", 8'd18, 32'd42);
$display("N %b %b", 8'd18, 16'd26);
$display("I %b %b", 1'b1, 32'd42);
$display("I %b %b", 1'b0, 32'd42);
$display("I %b %b", 1'b1, 32'd2);
$display("I %b %b", 8'd18, 32'd42);
$display("I %b %b", 8'd18, 16'd26);
end
endmodule