Commit 8d37db30 by Zachary Snow

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
parent 8ae925d9
......@@ -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] }
......
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
......
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
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
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
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