Commit 95c2bc99 by Zachary Snow

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.
parent 407ba590
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
explicitly providing a leading `parameter` or `localparam` marker explicitly providing a leading `parameter` or `localparam` marker
* Use UTF-8 on all platforms and tolerate transcoding failures, enabling reading * Use UTF-8 on all platforms and tolerate transcoding failures, enabling reading
files encoding using Latin-1 with special characters in comments 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 ## v0.0.8
......
...@@ -38,6 +38,7 @@ import qualified Convert.NamedBlock ...@@ -38,6 +38,7 @@ import qualified Convert.NamedBlock
import qualified Convert.Package import qualified Convert.Package
import qualified Convert.ParamNoDefault import qualified Convert.ParamNoDefault
import qualified Convert.ParamType import qualified Convert.ParamType
import qualified Convert.PortDecl
import qualified Convert.RemoveComments import qualified Convert.RemoveComments
import qualified Convert.ResolveBindings import qualified Convert.ResolveBindings
import qualified Convert.Simplify import qualified Convert.Simplify
...@@ -107,6 +108,7 @@ initialPhases selectExclude = ...@@ -107,6 +108,7 @@ initialPhases selectExclude =
, selectExclude Job.Assert Convert.Assertion.convert , selectExclude Job.Assert Convert.Assertion.convert
, selectExclude Job.Always Convert.AlwaysKW.convert , selectExclude Job.Always Convert.AlwaysKW.convert
, Convert.Package.convert , Convert.Package.convert
, Convert.PortDecl.convert
, Convert.ParamNoDefault.convert , Convert.ParamNoDefault.convert
, Convert.ResolveBindings.convert , Convert.ResolveBindings.convert
, Convert.UnnamedGenBlock.convert , Convert.UnnamedGenBlock.convert
......
{- 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 = ...@@ -381,9 +381,7 @@ parseDTsAsDecls backupDir mode l0 =
(rs , l6) = takeRanges l5 (rs , l6) = takeRanges l5
(tps, l7) = takeTrips l6 initReason (tps, l7) = takeTrips l6 initReason
base = von dir t base = von dir t
t = case (dir, tf rs) of t = tf rs
(Output, Implicit sg _) -> IntegerVector TLogic sg rs
(_, typ) -> typ
decls = decls =
traceComment l0 : traceComment l0 :
map (\(x, a, e) -> base x a e) tps map (\(x, a, e) -> base x a e) tps
......
...@@ -90,6 +90,7 @@ executable sv2v ...@@ -90,6 +90,7 @@ executable sv2v
Convert.Package Convert.Package
Convert.ParamNoDefault Convert.ParamNoDefault
Convert.ParamType Convert.ParamType
Convert.PortDecl
Convert.RemoveComments Convert.RemoveComments
Convert.ResolveBindings Convert.ResolveBindings
Convert.Scoper Convert.Scoper
......
`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
`define REF
`include "non_ansi_port_decl.sv"
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
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
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
// 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
// pattern: declared ports w, z are not in the port list of top
module top(x, y);
output w, x, y, z;
endmodule
// 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
// 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
// pattern: declarations `output logic a` and `logic a` are incompatible due to redeclaration
module top(a);
output logic a;
logic a;
endmodule
// 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
// 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment