mirror of https://github.com/zachjs/sv2v.git
support complex modport expressions
- modports can use complex expressions - update interface_infer test for consistency across simulators - fix interface inlining of implicitly typed data declarations
This commit is contained in:
parent
8ae925d92e
commit
8d37db30e5
|
|
@ -101,8 +101,8 @@ Other:
|
|||
## Supported Features
|
||||
|
||||
sv2v supports most synthesizable SystemVerilog features. Current notable
|
||||
exceptions include `export` and complex (non-identifier) `modport` expressions.
|
||||
Assertions are also supported, but are simply dropped during conversion.
|
||||
exceptions include `export` and interface arrays. Assertions are also supported,
|
||||
but are simply dropped during conversion.
|
||||
|
||||
If you find a bug or have a feature request, please create an issue. Preference
|
||||
will be given to issues which include examples or test cases.
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ convert =
|
|||
-- we can only collect/map non-extern interfaces
|
||||
collectDesc :: Description -> Writer (Interfaces, Modules) ()
|
||||
collectDesc (orig @ (Part _ False kw _ name ports items)) = do
|
||||
if kw == Interface
|
||||
then tell (Map.singleton name (ports, items), Map.empty)
|
||||
if kw == Interface then
|
||||
if all fullyResolved items
|
||||
then tell (Map.singleton name (ports, items), Map.empty)
|
||||
else return ()
|
||||
else tell (Map.empty, Map.singleton name (params, decls))
|
||||
where
|
||||
params = map fst $ parameters items
|
||||
|
|
@ -51,8 +53,19 @@ convert =
|
|||
collectDecl _ = return ()
|
||||
collectDesc _ = return ()
|
||||
isInterface :: Description -> Bool
|
||||
isInterface (Part _ False Interface _ _ _ _) = True
|
||||
isInterface (Part _ False Interface _ _ _ items) =
|
||||
all fullyResolved items
|
||||
isInterface _ = False
|
||||
-- returns whether a ModuleItem still contains TypeOf
|
||||
fullyResolved :: ModuleItem -> Bool
|
||||
fullyResolved =
|
||||
not . any isTypeOf . execWriter .
|
||||
collectNestedModuleItemsM (collectTypesM collectType)
|
||||
where
|
||||
collectType :: Type -> Writer [Type] ()
|
||||
collectType t = tell [t]
|
||||
isTypeOf TypeOf{} = True
|
||||
isTypeOf _ = False
|
||||
|
||||
convertDescription :: Interfaces -> Modules -> Description -> Description
|
||||
convertDescription interfaces modules (Part attrs extern Module lifetime name ports items) =
|
||||
|
|
@ -72,7 +85,9 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
|
|||
collectInterface (MIPackageItem (Decl (Variable _ t ident _ _))) =
|
||||
case t of
|
||||
InterfaceT interfaceName (Just modportName) [] ->
|
||||
tell (Map.empty, Map.singleton ident (interfaceName, modportDecls))
|
||||
if Map.member interfaceName interfaces
|
||||
then tell (Map.empty, Map.singleton ident (interfaceName, modportDecls))
|
||||
else return ()
|
||||
where Just modportDecls = lookupModport interfaceName modportName
|
||||
Alias Nothing interfaceName [] ->
|
||||
case impliedModport interfaceName of
|
||||
|
|
@ -92,7 +107,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
|
|||
-- expand instantiation of a modport
|
||||
case Map.lookup ident modports of
|
||||
Just (_, modportDecls) -> Generate $ map GenModuleItem $
|
||||
filter shouldKeep interfaceItems ++ map makePortDecl modportDecls
|
||||
filter shouldKeep interfaceItems ++ map makePortDecl
|
||||
(prefixModportDecls ident modportDecls)
|
||||
Nothing -> orig
|
||||
where
|
||||
interfaceName = case t of
|
||||
|
|
@ -108,10 +124,10 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
|
|||
shouldKeep (MIPackageItem Function{}) = True
|
||||
shouldKeep _ = False
|
||||
makePortDecl :: ModportDecl -> ModuleItem
|
||||
makePortDecl (dir, port, expr) =
|
||||
makePortDecl (dir, port, typ, _) =
|
||||
MIPackageItem $ Decl $
|
||||
Variable dir mpt (ident ++ "_" ++ port) mprs Nil
|
||||
where (mpt, mprs) = lookupType interfaceItems ident expr
|
||||
where (mpt, mprs) = (typ, [])
|
||||
mapInterface (Instance part params ident [] instancePorts) =
|
||||
-- expand modport port bindings
|
||||
case Map.lookup part interfaces of
|
||||
|
|
@ -201,7 +217,7 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
|
|||
-- modport directly bound to a modport
|
||||
expandPortBinding' interfaceName portName ident
|
||||
(map redirect modportDecls)
|
||||
where redirect (d, x, _) = (d, x, Ident x)
|
||||
where redirect (d, x, t, _) = (d, x, t, Ident x)
|
||||
expandPortBinding _ other _ = ([], [other])
|
||||
|
||||
expandPortBinding' :: Identifier -> Identifier -> Identifier ->
|
||||
|
|
@ -214,7 +230,7 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
|
|||
interfaceParamNames = map fst $ parameters interfaceItems
|
||||
toParamBinding x = (portName ++ '_' : x, Right $ Ident $ instanceName ++ '_' : x)
|
||||
portBindings = map toPortBinding modportDecls
|
||||
toPortBinding (_, x, e) = (x', e')
|
||||
toPortBinding (_, x, _, e) = (x', e')
|
||||
where
|
||||
x' = portName ++ '_' : x
|
||||
e' = traverseNestedExprs prefixExpr e
|
||||
|
|
@ -247,8 +263,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
|
|||
mapM (collectNestedModuleItemsM collectModportDecls) $
|
||||
interfaceItems
|
||||
collectModportDecls :: ModuleItem -> Writer [ModportDecl] ()
|
||||
collectModportDecls (MIPackageItem (Decl (Variable d _ x _ _))) =
|
||||
tell [(d', x, Ident x)]
|
||||
collectModportDecls (MIPackageItem (Decl (Variable d t x _ _))) =
|
||||
tell [(d', x, t, Ident x)]
|
||||
where d' = if d == Local then Inout else d
|
||||
collectModportDecls _ = return ()
|
||||
|
||||
|
|
@ -268,7 +284,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
|
|||
convertPort ident =
|
||||
case Map.lookup ident modports of
|
||||
Nothing -> [ident]
|
||||
Just (_, decls) -> map (\(_, x, _) -> ident ++ "_" ++ x) decls
|
||||
Just (_, decls) -> map (\(_, x, _, _) ->
|
||||
ident ++ "_" ++ x) decls
|
||||
|
||||
convertDescription _ _ other = other
|
||||
|
||||
|
|
@ -324,20 +341,23 @@ collectIdentsM item = collectDeclsM collectDecl item
|
|||
collectDecl (ParamType _ x _) = tell $ Set.singleton x
|
||||
collectDecl (CommentDecl _) = return ()
|
||||
|
||||
lookupType :: [ModuleItem] -> Identifier -> Expr -> (Type, [Range])
|
||||
lookupType items prefix (Ident ident) =
|
||||
case mapMaybe findType items of
|
||||
[] -> error $ "unable to locate type of " ++ ident
|
||||
ts -> head ts
|
||||
-- add a prefix to the expressions in a modport definition
|
||||
prefixModportDecls :: Identifier -> [ModportDecl] -> [ModportDecl]
|
||||
prefixModportDecls name modportDecls =
|
||||
map mapper modportDecls
|
||||
where
|
||||
findType :: ModuleItem -> Maybe (Type, [Range])
|
||||
findType (MIPackageItem (Decl (Variable _ t x rs _))) =
|
||||
if x == prefix ++ "_" ++ ident then Just (t, rs) else Nothing
|
||||
findType _ = Nothing
|
||||
lookupType _ _ expr =
|
||||
-- TODO: Add support for non-Ident modport expressions.
|
||||
error $ "interface conversion does not support modport expressions that "
|
||||
++ " are not identifiers: " ++ show expr
|
||||
mapper :: ModportDecl -> ModportDecl
|
||||
mapper (d, x, t, e) = (d, x, t', e')
|
||||
where
|
||||
exprMapper = traverseNestedExprs prefixExpr
|
||||
t' = traverseNestedTypes (traverseTypeExprs exprMapper) t
|
||||
e' = exprMapper e
|
||||
prefix :: Identifier -> Identifier
|
||||
prefix = (++) $ name ++ "_"
|
||||
prefixExpr :: Expr -> Expr
|
||||
prefixExpr (Ident ('$' : x)) = Ident $ '$' : x
|
||||
prefixExpr (Ident x) = Ident (prefix x)
|
||||
prefixExpr other = other
|
||||
|
||||
-- convert an interface instantiation into a series of equivalent module items
|
||||
inlineInterface :: Interface -> (Identifier, [ParamBinding], [PortBinding]) -> [ModuleItem]
|
||||
|
|
@ -367,7 +387,11 @@ inlineInterface (ports, items) (instanceName, instanceParams, instancePorts) =
|
|||
|
||||
removeDeclDir :: ModuleItem -> ModuleItem
|
||||
removeDeclDir (MIPackageItem (Decl (Variable _ t x a e))) =
|
||||
MIPackageItem $ Decl $ Variable Local t x a e
|
||||
MIPackageItem $ Decl $ Variable Local t' x a e
|
||||
where t' = case t of
|
||||
Implicit Unspecified rs ->
|
||||
IntegerVector TLogic Unspecified rs
|
||||
_ -> t
|
||||
removeDeclDir other = other
|
||||
removeModport :: ModuleItem -> ModuleItem
|
||||
removeModport (Modport x _) =
|
||||
|
|
|
|||
|
|
@ -56,10 +56,11 @@ convert =
|
|||
portName ++ " in module " ++ name
|
||||
collectPortsM _ = return ()
|
||||
collectDeclDirsM :: ModuleItem -> Writer [(Identifier, Direction)] ()
|
||||
collectDeclDirsM (MIPackageItem (Decl (Variable dir _ ident _ _))) =
|
||||
if dir == Local
|
||||
then return ()
|
||||
else tell [(ident, dir)]
|
||||
collectDeclDirsM (MIPackageItem (Decl (Variable dir t ident _ _))) =
|
||||
case (dir, t) of
|
||||
(_, InterfaceT{}) -> tell [(ident, Local)]
|
||||
(Local, _) -> return ()
|
||||
_ -> tell [(ident, dir)]
|
||||
collectDeclDirsM _ = return ()
|
||||
|
||||
convertDescription :: Ports -> Description -> Description
|
||||
|
|
|
|||
|
|
@ -648,9 +648,10 @@ traverseExprsM' strat exprMapper = moduleItemMapper
|
|||
return $ GenCase e' cases'
|
||||
genItemMapper other = return other
|
||||
|
||||
modportDeclMapper (dir, ident, e) = do
|
||||
modportDeclMapper (dir, ident, t, e) = do
|
||||
t' <- typeMapper t
|
||||
e' <- exprMapper e
|
||||
return (dir, ident, e')
|
||||
return (dir, ident, t', e')
|
||||
|
||||
traverseExprs' :: TFStrategy -> Mapper Expr -> Mapper ModuleItem
|
||||
traverseExprs' strat = unmonad $ traverseExprsM' strat
|
||||
|
|
@ -933,6 +934,11 @@ traverseTypesM' strategy mapper item =
|
|||
then fullMapper t >>= \t' -> return (i, Left t')
|
||||
else return (i, Left t)
|
||||
mapParam (i, Right e) = return $ (i, Right e)
|
||||
miMapper (Modport name decls) =
|
||||
mapM mapModportDecl decls >>= return . Modport name
|
||||
where
|
||||
mapModportDecl (d, x, t, e) =
|
||||
fullMapper t >>= \t' -> return (d, x, t', e)
|
||||
miMapper other = return other
|
||||
|
||||
traverseTypes' :: TypeStrategy -> Mapper Type -> Mapper ModuleItem
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import Language.SystemVerilog.AST.Expr (Expr(Ident, Nil), Range, TypeOrExpr, sho
|
|||
import Language.SystemVerilog.AST.GenItem (GenItem)
|
||||
import Language.SystemVerilog.AST.LHS (LHS)
|
||||
import Language.SystemVerilog.AST.Stmt (Stmt, AssertionItem, Timing(Delay))
|
||||
import Language.SystemVerilog.AST.Type (Identifier, DriveStrength)
|
||||
import Language.SystemVerilog.AST.Type (Type, Identifier, DriveStrength)
|
||||
|
||||
data ModuleItem
|
||||
= MIAttr Attr ModuleItem
|
||||
|
|
@ -99,16 +99,16 @@ showParam (i, arg) =
|
|||
where fmt = if i == "" then "%s%s" else ".%s(%s)"
|
||||
|
||||
showModportDecl :: ModportDecl -> String
|
||||
showModportDecl (dir, ident, e) =
|
||||
showModportDecl (dir, ident, t, e) =
|
||||
if e == Ident ident
|
||||
then printf "%s %s" (show dir) ident
|
||||
else printf "%s .%s(%s)" (show dir) ident (show e)
|
||||
else printf "%s .%s(/* type: %s */ %s)" (show dir) ident (show t) (show e)
|
||||
|
||||
type PortBinding = (Identifier, Expr)
|
||||
|
||||
type ParamBinding = (Identifier, TypeOrExpr)
|
||||
|
||||
type ModportDecl = (Direction, Identifier, Expr)
|
||||
type ModportDecl = (Direction, Identifier, Type, Expr)
|
||||
|
||||
data AlwaysKW
|
||||
= Always
|
||||
|
|
|
|||
|
|
@ -588,7 +588,7 @@ ModportPortsDeclarations :: { [ModportDecl] }
|
|||
ModportPortsDeclaration(delim) :: { [ModportDecl] }
|
||||
: ModportSimplePortsDeclaration(delim) { $1 }
|
||||
ModportSimplePortsDeclaration(delim) :: { [ModportDecl] }
|
||||
: Direction ModportSimplePorts delim { map (\(a, b) -> ($1, a, b)) $2 }
|
||||
: Direction ModportSimplePorts delim { map (\(a, b) -> ($1, a, TypeOf b, b)) $2 }
|
||||
ModportSimplePorts :: { [(Identifier, Expr)] }
|
||||
: ModportSimplePort { [$1] }
|
||||
| ModportSimplePorts "," ModportSimplePort { $1 ++ [$3] }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
localparam SOME_VAL = 3;
|
||||
interface Interface;
|
||||
logic x;
|
||||
logic x = 0;
|
||||
modport Modport(
|
||||
input x
|
||||
);
|
||||
|
|
@ -15,11 +15,11 @@ module Module(Interface.Modport foo);
|
|||
initial $display("Module %d", foo.x);
|
||||
endmodule
|
||||
module top;
|
||||
Interface i();
|
||||
Module m(i);
|
||||
generate
|
||||
for (genvar g = 0; g < 5; ++g) begin
|
||||
initial $display(g);
|
||||
end
|
||||
endgenerate
|
||||
Interface i();
|
||||
Module m(i);
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ module Module(input wire x);
|
|||
initial $display("Module %d", x);
|
||||
endmodule
|
||||
module top;
|
||||
wire i_x;
|
||||
wire i_x = 0;
|
||||
localparam SOME_VAL = 3;
|
||||
initial $display("Interface %d %d", i_x, SOME_VAL);
|
||||
Module m(.x(i_x));
|
||||
generate
|
||||
genvar g;
|
||||
for (g = 0; g < 5; g = g + 1) begin
|
||||
for (g = 10; g < 15; g = g + 1) begin
|
||||
initial $display(g);
|
||||
end
|
||||
for (g = 10; g < 15; g = g + 1) begin
|
||||
for (g = 0; g < 5; g = g + 1) begin
|
||||
initial $display(g);
|
||||
end
|
||||
endgenerate
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
interface Interface #(parameter WIDTH = 4) (
|
||||
input clock,
|
||||
output [$clog2(WIDTH) - 1:0] indices [2]
|
||||
);
|
||||
logic [2*WIDTH-1:0] x;
|
||||
modport ModportA(
|
||||
input clock,
|
||||
output indices,
|
||||
input .x(x[2*WIDTH-1:WIDTH]), .y(x[WIDTH-1:0])
|
||||
);
|
||||
modport ModportB(
|
||||
input clock,
|
||||
output .x(x)
|
||||
);
|
||||
endinterface
|
||||
|
||||
module ModuleA(Interface.ModportA m);
|
||||
assign m.indices[0] = $clog2(m.x);
|
||||
assign m.indices[1] = $clog2(m.y);
|
||||
endmodule
|
||||
|
||||
module ModuleB(Interface.ModportB m);
|
||||
initial m.x = 1;
|
||||
localparam WIDTH = 2 * m.WIDTH;
|
||||
always @(posedge m.clock) begin
|
||||
logic temp;
|
||||
temp = m.x[WIDTH-1];
|
||||
for (integer i = WIDTH-1; i > 0; --i) begin
|
||||
m.x[i] = m.x[i-1];
|
||||
end
|
||||
m.x[0] = temp;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module ModuleBWrapper(Interface.ModportB m);
|
||||
ModuleB b(m);
|
||||
endmodule
|
||||
|
||||
module ModuleAWrapper(Interface.ModportA m);
|
||||
ModuleA a(m);
|
||||
endmodule
|
||||
|
||||
module Tester(input clock);
|
||||
parameter WIDTH = 1;
|
||||
logic [WIDTH-1:0] idx1, idx2;
|
||||
Interface #(2 ** WIDTH) i(clock, '{idx1, idx2});
|
||||
ModuleAWrapper a(i);
|
||||
ModuleBWrapper b(i);
|
||||
always @(negedge clock)
|
||||
$display("%d %0d %2d %2d %b", $time, WIDTH, idx1, idx2, i.x);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
module Tester(input clock);
|
||||
parameter WIDTH = 1;
|
||||
|
||||
localparam DATA_WIDTH = 2 ** WIDTH;
|
||||
|
||||
reg [2*DATA_WIDTH-1:0] x;
|
||||
initial x = 1;
|
||||
|
||||
wire [WIDTH-1:0] idx1, idx2;
|
||||
assign idx1 = $clog2(x[2*DATA_WIDTH-1:DATA_WIDTH]);
|
||||
assign idx2 = $clog2(x[DATA_WIDTH-1:0]);
|
||||
|
||||
always @(posedge clock) begin : block
|
||||
localparam SIZE = 2 * DATA_WIDTH;
|
||||
integer i;
|
||||
reg temp;
|
||||
temp = x[SIZE-1];
|
||||
for (i = SIZE-1; i > 0; i = i - 1) begin
|
||||
x[i] = x[i-1];
|
||||
end
|
||||
x[0] = temp;
|
||||
end
|
||||
|
||||
always @(negedge clock)
|
||||
$display("%d %0d %2d %2d %b", $time, WIDTH, idx1, idx2, x);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
module top;
|
||||
reg clock;
|
||||
initial begin
|
||||
clock = 1;
|
||||
forever #5 clock = ~clock;
|
||||
end
|
||||
|
||||
initial begin
|
||||
repeat(30)
|
||||
@(posedge clock);
|
||||
$finish;
|
||||
end
|
||||
|
||||
Tester #(1) t1(clock);
|
||||
Tester #(2) t2(clock);
|
||||
Tester #(3) t3(clock);
|
||||
Tester #(4) t4(clock);
|
||||
endmodule
|
||||
Loading…
Reference in New Issue