mirror of https://github.com/zachjs/sv2v.git
support for common non-ANSI style port declarations
Specifically, support has been added for non-ANSI style port declarations where the port declaration is separate from the corresponding net or variable declaration.
This commit is contained in:
parent
407ba59042
commit
95c2bc996c
|
|
@ -24,6 +24,8 @@
|
|||
explicitly providing a leading `parameter` or `localparam` marker
|
||||
* Use UTF-8 on all platforms and tolerate transcoding failures, enabling reading
|
||||
files encoding using Latin-1 with special characters in comments
|
||||
* Support for non-ANSI style port declarations where the port declaration is
|
||||
separate from the corresponding net or variable declaration
|
||||
|
||||
## v0.0.8
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import qualified Convert.NamedBlock
|
|||
import qualified Convert.Package
|
||||
import qualified Convert.ParamNoDefault
|
||||
import qualified Convert.ParamType
|
||||
import qualified Convert.PortDecl
|
||||
import qualified Convert.RemoveComments
|
||||
import qualified Convert.ResolveBindings
|
||||
import qualified Convert.Simplify
|
||||
|
|
@ -107,6 +108,7 @@ initialPhases selectExclude =
|
|||
, selectExclude Job.Assert Convert.Assertion.convert
|
||||
, selectExclude Job.Always Convert.AlwaysKW.convert
|
||||
, Convert.Package.convert
|
||||
, Convert.PortDecl.convert
|
||||
, Convert.ParamNoDefault.convert
|
||||
, Convert.ResolveBindings.convert
|
||||
, Convert.UnnamedGenBlock.convert
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Conversion for checking and standardizing port declarations
|
||||
-
|
||||
- Non-ANSI style port declarations can be split into two separate declarations.
|
||||
- Section 23.2.2.1 of IEEE 1800-2017 defines rules for determining the
|
||||
- resulting details of such declarations. This conversion is part of the
|
||||
- initial phases to avoid requiring that downstream conversions handle these
|
||||
- unusual otherwise conflicting declarations.
|
||||
-
|
||||
- To avoid creating spurious conflicts for redeclared ports, this conversion is
|
||||
- also responsible for defaulting variable ports to `logic`.
|
||||
-}
|
||||
|
||||
module Convert.PortDecl (convert) where
|
||||
|
||||
import Data.List (intercalate, (\\))
|
||||
import Data.Maybe (mapMaybe)
|
||||
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert = map $ traverseDescriptions traverseDescription
|
||||
|
||||
traverseDescription :: Description -> Description
|
||||
traverseDescription (Part attrs extern kw liftetime name ports items) =
|
||||
Part attrs extern kw liftetime name ports items'
|
||||
where items' = convertPorts name ports items
|
||||
traverseDescription other = other
|
||||
|
||||
convertPorts :: Identifier -> [Identifier] -> [ModuleItem] -> [ModuleItem]
|
||||
convertPorts name ports items
|
||||
| not (null extraPorts) =
|
||||
error $ "declared ports " ++ intercalate ", " extraPorts
|
||||
++ " are not in the port list of " ++ name
|
||||
| otherwise =
|
||||
map traverseItem items
|
||||
where
|
||||
portDecls = mapMaybe (findDecl True ) items
|
||||
dataDecls = mapMaybe (findDecl False) items
|
||||
extraPorts = map fst portDecls \\ ports
|
||||
|
||||
-- rewrite a declaration if necessary
|
||||
traverseItem :: ModuleItem -> ModuleItem
|
||||
traverseItem (MIPackageItem (Decl decl))
|
||||
| Variable d _ x _ e <- decl = rewrite decl (combineIdent x) d x e
|
||||
| Net d _ _ _ x _ e <- decl = rewrite decl (combineIdent x) d x e
|
||||
| otherwise = MIPackageItem $ Decl decl
|
||||
traverseItem other = other
|
||||
|
||||
-- produce the combined declaration for a port, if it has one
|
||||
combineIdent :: Identifier -> Maybe Decl
|
||||
combineIdent x = do
|
||||
portDecl <- lookup x portDecls
|
||||
dataDecl <- lookup x dataDecls
|
||||
Just $ combineDecls portDecl dataDecl
|
||||
|
||||
-- given helpfully extracted information, update the given declaration
|
||||
rewrite :: Decl -> Maybe Decl -> Direction -> Identifier -> Expr -> ModuleItem
|
||||
-- implicitly-typed ports default to `logic` in SystemVerilog
|
||||
rewrite (Variable d (Implicit sg rs) x a e) Nothing _ _ _ =
|
||||
MIPackageItem $ Decl $ Variable d (IntegerVector TLogic sg rs) x a e
|
||||
-- not a relevant port declaration
|
||||
rewrite decl Nothing _ _ _ =
|
||||
MIPackageItem $ Decl decl
|
||||
-- turn the non-ANSI style port and data declarations into fully-specified ports
|
||||
-- and optional continuous assignments, respectively
|
||||
rewrite _ (Just combined) d x e
|
||||
| d /= Local =
|
||||
MIPackageItem $ Decl combined
|
||||
| e /= Nil =
|
||||
Assign AssignOptionNone (LHSIdent x) e
|
||||
| otherwise =
|
||||
MIPackageItem $ Decl $ CommentDecl $ "combined with " ++ x
|
||||
|
||||
-- combine the two declarations defining a non-ANSI style port
|
||||
combineDecls :: Decl -> Decl -> Decl
|
||||
combineDecls portDecl dataDecl
|
||||
| eP /= Nil =
|
||||
mismatch "invalid initialization at port declaration"
|
||||
| aP /= aD =
|
||||
mismatch "different unpacked dimensions"
|
||||
| rsP /= rsD =
|
||||
mismatch "different packed dimensions"
|
||||
| otherwise =
|
||||
base (tf rsD) ident aD Nil
|
||||
where
|
||||
|
||||
-- signed if *either* declaration is marked signed
|
||||
sg = if sgP == Signed || sgD == Signed
|
||||
then Signed
|
||||
else Unspecified
|
||||
|
||||
-- the port cannot have a variable or net type
|
||||
Implicit sgP rsP = case tP of
|
||||
Implicit{} -> tP
|
||||
_ -> mismatch "redeclaration"
|
||||
|
||||
-- pull out the base type, signedness, and packed dimensions
|
||||
(tf, sgD, rsD) = case tD of
|
||||
Implicit s r -> (IntegerVector TLogic sg, s, r )
|
||||
IntegerVector k s r -> (IntegerVector k sg, s, r )
|
||||
IntegerAtom k s -> (\[] -> IntegerAtom k s , s, [])
|
||||
-- TODO: other basic types may be worth supporting here
|
||||
_ -> mismatch "non-ANSI port declaration with unsupported data type"
|
||||
|
||||
-- extract the core components of each declaration
|
||||
Variable dir tP ident aP eP = portDecl
|
||||
(base, tD, aD) = case dataDecl of
|
||||
Variable Local t _ a _ -> (Variable dir, t, a)
|
||||
Net Local n s t _ a _ -> (Net dir n s, t, a)
|
||||
_ -> undefined -- not possible given findDecl
|
||||
|
||||
-- helpful error message utility
|
||||
mismatch :: String -> a
|
||||
mismatch msg = error $ "declarations `" ++ p portDecl ++ "` and `"
|
||||
++ p dataDecl ++ "` are incompatible due to " ++ msg
|
||||
where p = init . show
|
||||
|
||||
-- used to build independent lists of port and data declarations
|
||||
findDecl :: Bool -> ModuleItem -> Maybe (Identifier, Decl)
|
||||
findDecl isPort (MIPackageItem (Decl decl))
|
||||
| Variable d _ x _ _ <- decl, (d /= Local) == isPort = Just (x, decl)
|
||||
| Net d _ _ _ x _ _ <- decl, (d /= Local) == isPort = Just (x, decl)
|
||||
findDecl _ _ = Nothing
|
||||
|
|
@ -381,9 +381,7 @@ parseDTsAsDecls backupDir mode l0 =
|
|||
(rs , l6) = takeRanges l5
|
||||
(tps, l7) = takeTrips l6 initReason
|
||||
base = von dir t
|
||||
t = case (dir, tf rs) of
|
||||
(Output, Implicit sg _) -> IntegerVector TLogic sg rs
|
||||
(_, typ) -> typ
|
||||
t = tf rs
|
||||
decls =
|
||||
traceComment l0 :
|
||||
map (\(x, a, e) -> base x a e) tps
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ executable sv2v
|
|||
Convert.Package
|
||||
Convert.ParamNoDefault
|
||||
Convert.ParamType
|
||||
Convert.PortDecl
|
||||
Convert.RemoveComments
|
||||
Convert.ResolveBindings
|
||||
Convert.Scoper
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
`define TEST_SG(port_sg, data_sg, exp_u, exp_s) \
|
||||
`TEST_RAW(o_``port_sg``_``data_sg``_one, port_sg , data_sg , [ 0:0], exp_u) \
|
||||
`TEST_RAW(o_``port_sg``_``data_sg``_two, port_sg [1:0], data_sg [1:0] , [ 1:0], exp_u) \
|
||||
`TEST_RAW(o_``port_sg``_``data_sg``_int, port_sg , integer data_sg, [31:0], exp_s)
|
||||
|
||||
`define TEST \
|
||||
`TEST_SG( , , 0, 1) \
|
||||
`TEST_SG( , signed, 1, 1) \
|
||||
`TEST_SG( , unsigned, 0, 0) \
|
||||
`TEST_SG( signed, , 1, 1) \
|
||||
`TEST_SG( signed, signed, 1, 1) \
|
||||
`TEST_SG( signed, unsigned, 1, 0) \
|
||||
`TEST_SG(unsigned, , 0, 1) \
|
||||
`TEST_SG(unsigned, signed, 1, 1) \
|
||||
`TEST_SG(unsigned, unsigned, 0, 0)
|
||||
|
||||
`define TEST_RAW(name, a, b, c, d) name,
|
||||
|
||||
module top(
|
||||
`TEST
|
||||
foo
|
||||
);
|
||||
output wire foo;
|
||||
assign foo = 1;
|
||||
|
||||
`undef TEST_RAW
|
||||
`define TEST_RAW(name, port, data, range, exp) \
|
||||
`ifdef REF \
|
||||
output wire range name; \
|
||||
initial #1 $display(`"name %b %b`", name, 1'b``exp); \
|
||||
`else \
|
||||
output port name; \
|
||||
wire data name; \
|
||||
initial #1 $display(`"name %b %b`", name, name < 0); \
|
||||
`endif \
|
||||
assign name = 1'sb1; \
|
||||
|
||||
`TEST
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
`define REF
|
||||
`include "non_ansi_port_decl.sv"
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
module mod(a, b, c, d);
|
||||
input a;
|
||||
wire a;
|
||||
output b;
|
||||
reg b;
|
||||
always @*
|
||||
b = ~a;
|
||||
input [7:0] c;
|
||||
wire integer d = 10 + c;
|
||||
logic [7:0] c;
|
||||
output d;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
module mod(a, b, c, d);
|
||||
input wire a;
|
||||
output reg b;
|
||||
always @*
|
||||
b = ~a;
|
||||
input wire [7:0] c;
|
||||
output wire [31:0] d;
|
||||
assign d = 10 + c;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
module top;
|
||||
reg a;
|
||||
wire b;
|
||||
reg [7:0] c;
|
||||
wire [31:0] d;
|
||||
mod m(a, b, c, d);
|
||||
initial begin
|
||||
$monitor("%2d %b %b %b %b", $time, a, b, c, d);
|
||||
#1 a = 0;
|
||||
#1 a = 1;
|
||||
for (c = 0; c < 10; c = c + 1)
|
||||
#1;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// pattern: declarations `output a = 1` and `logic a` are incompatible due to invalid initialization at port declaration
|
||||
module top(a);
|
||||
output a = 1;
|
||||
logic a;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// pattern: declared ports w, z are not in the port list of top
|
||||
module top(x, y);
|
||||
output w, x, y, z;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// pattern: declarations `output \[1:0\] x` and `wire x` are incompatible due to different packed dimensions
|
||||
module top(x);
|
||||
output [1:0] x;
|
||||
wire x;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// pattern: declarations `output x` and `wire \[1:0\] x` are incompatible due to different packed dimensions
|
||||
module top(x);
|
||||
output x;
|
||||
wire [1:0] x;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// pattern: declarations `output logic a` and `logic a` are incompatible due to redeclaration
|
||||
module top(a);
|
||||
output logic a;
|
||||
logic a;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// pattern: declarations `output x \[1:0\]` and `wire x` are incompatible due to different unpacked dimensions
|
||||
module top(x);
|
||||
output x [1:0];
|
||||
wire x;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// pattern: declarations `output x` and `wire x \[1:0\]` are incompatible due to different unpacked dimensions
|
||||
module top(x);
|
||||
output x;
|
||||
wire x [1:0];
|
||||
endmodule
|
||||
Loading…
Reference in New Issue