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: ...@@ -101,8 +101,8 @@ Other:
## Supported Features ## Supported Features
sv2v supports most synthesizable SystemVerilog features. Current notable sv2v supports most synthesizable SystemVerilog features. Current notable
exceptions include `export` and complex (non-identifier) `modport` expressions. exceptions include `export` and interface arrays. Assertions are also supported,
Assertions are also supported, but are simply dropped during conversion. but are simply dropped during conversion.
If you find a bug or have a feature request, please create an issue. Preference 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. will be given to issues which include examples or test cases.
......
...@@ -38,8 +38,10 @@ convert = ...@@ -38,8 +38,10 @@ convert =
-- we can only collect/map non-extern interfaces -- we can only collect/map non-extern interfaces
collectDesc :: Description -> Writer (Interfaces, Modules) () collectDesc :: Description -> Writer (Interfaces, Modules) ()
collectDesc (orig @ (Part _ False kw _ name ports items)) = do collectDesc (orig @ (Part _ False kw _ name ports items)) = do
if kw == Interface if kw == Interface then
if all fullyResolved items
then tell (Map.singleton name (ports, items), Map.empty) then tell (Map.singleton name (ports, items), Map.empty)
else return ()
else tell (Map.empty, Map.singleton name (params, decls)) else tell (Map.empty, Map.singleton name (params, decls))
where where
params = map fst $ parameters items params = map fst $ parameters items
...@@ -51,8 +53,19 @@ convert = ...@@ -51,8 +53,19 @@ convert =
collectDecl _ = return () collectDecl _ = return ()
collectDesc _ = return () collectDesc _ = return ()
isInterface :: Description -> Bool isInterface :: Description -> Bool
isInterface (Part _ False Interface _ _ _ _) = True isInterface (Part _ False Interface _ _ _ items) =
all fullyResolved items
isInterface _ = False 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 -> Description -> Description
convertDescription interfaces modules (Part attrs extern Module lifetime name ports items) = 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 ...@@ -72,7 +85,9 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
collectInterface (MIPackageItem (Decl (Variable _ t ident _ _))) = collectInterface (MIPackageItem (Decl (Variable _ t ident _ _))) =
case t of case t of
InterfaceT interfaceName (Just modportName) [] -> 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 where Just modportDecls = lookupModport interfaceName modportName
Alias Nothing interfaceName [] -> Alias Nothing interfaceName [] ->
case impliedModport interfaceName of case impliedModport interfaceName of
...@@ -92,7 +107,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po ...@@ -92,7 +107,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
-- expand instantiation of a modport -- expand instantiation of a modport
case Map.lookup ident modports of case Map.lookup ident modports of
Just (_, modportDecls) -> Generate $ map GenModuleItem $ Just (_, modportDecls) -> Generate $ map GenModuleItem $
filter shouldKeep interfaceItems ++ map makePortDecl modportDecls filter shouldKeep interfaceItems ++ map makePortDecl
(prefixModportDecls ident modportDecls)
Nothing -> orig Nothing -> orig
where where
interfaceName = case t of interfaceName = case t of
...@@ -108,10 +124,10 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po ...@@ -108,10 +124,10 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
shouldKeep (MIPackageItem Function{}) = True shouldKeep (MIPackageItem Function{}) = True
shouldKeep _ = False shouldKeep _ = False
makePortDecl :: ModportDecl -> ModuleItem makePortDecl :: ModportDecl -> ModuleItem
makePortDecl (dir, port, expr) = makePortDecl (dir, port, typ, _) =
MIPackageItem $ Decl $ MIPackageItem $ Decl $
Variable dir mpt (ident ++ "_" ++ port) mprs Nil Variable dir mpt (ident ++ "_" ++ port) mprs Nil
where (mpt, mprs) = lookupType interfaceItems ident expr where (mpt, mprs) = (typ, [])
mapInterface (Instance part params ident [] instancePorts) = mapInterface (Instance part params ident [] instancePorts) =
-- expand modport port bindings -- expand modport port bindings
case Map.lookup part interfaces of case Map.lookup part interfaces of
...@@ -201,7 +217,7 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po ...@@ -201,7 +217,7 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
-- modport directly bound to a modport -- modport directly bound to a modport
expandPortBinding' interfaceName portName ident expandPortBinding' interfaceName portName ident
(map redirect modportDecls) (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 _ other _ = ([], [other])
expandPortBinding' :: Identifier -> Identifier -> Identifier -> expandPortBinding' :: Identifier -> Identifier -> Identifier ->
...@@ -214,7 +230,7 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po ...@@ -214,7 +230,7 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
interfaceParamNames = map fst $ parameters interfaceItems interfaceParamNames = map fst $ parameters interfaceItems
toParamBinding x = (portName ++ '_' : x, Right $ Ident $ instanceName ++ '_' : x) toParamBinding x = (portName ++ '_' : x, Right $ Ident $ instanceName ++ '_' : x)
portBindings = map toPortBinding modportDecls portBindings = map toPortBinding modportDecls
toPortBinding (_, x, e) = (x', e') toPortBinding (_, x, _, e) = (x', e')
where where
x' = portName ++ '_' : x x' = portName ++ '_' : x
e' = traverseNestedExprs prefixExpr e e' = traverseNestedExprs prefixExpr e
...@@ -247,8 +263,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po ...@@ -247,8 +263,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
mapM (collectNestedModuleItemsM collectModportDecls) $ mapM (collectNestedModuleItemsM collectModportDecls) $
interfaceItems interfaceItems
collectModportDecls :: ModuleItem -> Writer [ModportDecl] () collectModportDecls :: ModuleItem -> Writer [ModportDecl] ()
collectModportDecls (MIPackageItem (Decl (Variable d _ x _ _))) = collectModportDecls (MIPackageItem (Decl (Variable d t x _ _))) =
tell [(d', x, Ident x)] tell [(d', x, t, Ident x)]
where d' = if d == Local then Inout else d where d' = if d == Local then Inout else d
collectModportDecls _ = return () collectModportDecls _ = return ()
...@@ -268,7 +284,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po ...@@ -268,7 +284,8 @@ convertDescription interfaces modules (Part attrs extern Module lifetime name po
convertPort ident = convertPort ident =
case Map.lookup ident modports of case Map.lookup ident modports of
Nothing -> [ident] Nothing -> [ident]
Just (_, decls) -> map (\(_, x, _) -> ident ++ "_" ++ x) decls Just (_, decls) -> map (\(_, x, _, _) ->
ident ++ "_" ++ x) decls
convertDescription _ _ other = other convertDescription _ _ other = other
...@@ -324,20 +341,23 @@ collectIdentsM item = collectDeclsM collectDecl item ...@@ -324,20 +341,23 @@ collectIdentsM item = collectDeclsM collectDecl item
collectDecl (ParamType _ x _) = tell $ Set.singleton x collectDecl (ParamType _ x _) = tell $ Set.singleton x
collectDecl (CommentDecl _) = return () collectDecl (CommentDecl _) = return ()
lookupType :: [ModuleItem] -> Identifier -> Expr -> (Type, [Range]) -- add a prefix to the expressions in a modport definition
lookupType items prefix (Ident ident) = prefixModportDecls :: Identifier -> [ModportDecl] -> [ModportDecl]
case mapMaybe findType items of prefixModportDecls name modportDecls =
[] -> error $ "unable to locate type of " ++ ident map mapper modportDecls
ts -> head ts
where where
findType :: ModuleItem -> Maybe (Type, [Range]) mapper :: ModportDecl -> ModportDecl
findType (MIPackageItem (Decl (Variable _ t x rs _))) = mapper (d, x, t, e) = (d, x, t', e')
if x == prefix ++ "_" ++ ident then Just (t, rs) else Nothing where
findType _ = Nothing exprMapper = traverseNestedExprs prefixExpr
lookupType _ _ expr = t' = traverseNestedTypes (traverseTypeExprs exprMapper) t
-- TODO: Add support for non-Ident modport expressions. e' = exprMapper e
error $ "interface conversion does not support modport expressions that " prefix :: Identifier -> Identifier
++ " are not identifiers: " ++ show expr 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 -- convert an interface instantiation into a series of equivalent module items
inlineInterface :: Interface -> (Identifier, [ParamBinding], [PortBinding]) -> [ModuleItem] inlineInterface :: Interface -> (Identifier, [ParamBinding], [PortBinding]) -> [ModuleItem]
...@@ -367,7 +387,11 @@ inlineInterface (ports, items) (instanceName, instanceParams, instancePorts) = ...@@ -367,7 +387,11 @@ inlineInterface (ports, items) (instanceName, instanceParams, instancePorts) =
removeDeclDir :: ModuleItem -> ModuleItem removeDeclDir :: ModuleItem -> ModuleItem
removeDeclDir (MIPackageItem (Decl (Variable _ t x a e))) = 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 removeDeclDir other = other
removeModport :: ModuleItem -> ModuleItem removeModport :: ModuleItem -> ModuleItem
removeModport (Modport x _) = removeModport (Modport x _) =
......
...@@ -56,10 +56,11 @@ convert = ...@@ -56,10 +56,11 @@ convert =
portName ++ " in module " ++ name portName ++ " in module " ++ name
collectPortsM _ = return () collectPortsM _ = return ()
collectDeclDirsM :: ModuleItem -> Writer [(Identifier, Direction)] () collectDeclDirsM :: ModuleItem -> Writer [(Identifier, Direction)] ()
collectDeclDirsM (MIPackageItem (Decl (Variable dir _ ident _ _))) = collectDeclDirsM (MIPackageItem (Decl (Variable dir t ident _ _))) =
if dir == Local case (dir, t) of
then return () (_, InterfaceT{}) -> tell [(ident, Local)]
else tell [(ident, dir)] (Local, _) -> return ()
_ -> tell [(ident, dir)]
collectDeclDirsM _ = return () collectDeclDirsM _ = return ()
convertDescription :: Ports -> Description -> Description convertDescription :: Ports -> Description -> Description
......
...@@ -648,9 +648,10 @@ traverseExprsM' strat exprMapper = moduleItemMapper ...@@ -648,9 +648,10 @@ traverseExprsM' strat exprMapper = moduleItemMapper
return $ GenCase e' cases' return $ GenCase e' cases'
genItemMapper other = return other genItemMapper other = return other
modportDeclMapper (dir, ident, e) = do modportDeclMapper (dir, ident, t, e) = do
t' <- typeMapper t
e' <- exprMapper e e' <- exprMapper e
return (dir, ident, e') return (dir, ident, t', e')
traverseExprs' :: TFStrategy -> Mapper Expr -> Mapper ModuleItem traverseExprs' :: TFStrategy -> Mapper Expr -> Mapper ModuleItem
traverseExprs' strat = unmonad $ traverseExprsM' strat traverseExprs' strat = unmonad $ traverseExprsM' strat
...@@ -933,6 +934,11 @@ traverseTypesM' strategy mapper item = ...@@ -933,6 +934,11 @@ traverseTypesM' strategy mapper item =
then fullMapper t >>= \t' -> return (i, Left t') then fullMapper t >>= \t' -> return (i, Left t')
else return (i, Left t) else return (i, Left t)
mapParam (i, Right e) = return $ (i, Right e) 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 miMapper other = return other
traverseTypes' :: TypeStrategy -> Mapper Type -> Mapper ModuleItem traverseTypes' :: TypeStrategy -> Mapper Type -> Mapper ModuleItem
......
...@@ -28,7 +28,7 @@ import Language.SystemVerilog.AST.Expr (Expr(Ident, Nil), Range, TypeOrExpr, sho ...@@ -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.GenItem (GenItem)
import Language.SystemVerilog.AST.LHS (LHS) import Language.SystemVerilog.AST.LHS (LHS)
import Language.SystemVerilog.AST.Stmt (Stmt, AssertionItem, Timing(Delay)) 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 data ModuleItem
= MIAttr Attr ModuleItem = MIAttr Attr ModuleItem
...@@ -99,16 +99,16 @@ showParam (i, arg) = ...@@ -99,16 +99,16 @@ showParam (i, arg) =
where fmt = if i == "" then "%s%s" else ".%s(%s)" where fmt = if i == "" then "%s%s" else ".%s(%s)"
showModportDecl :: ModportDecl -> String showModportDecl :: ModportDecl -> String
showModportDecl (dir, ident, e) = showModportDecl (dir, ident, t, e) =
if e == Ident ident if e == Ident ident
then printf "%s %s" (show dir) 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 PortBinding = (Identifier, Expr)
type ParamBinding = (Identifier, TypeOrExpr) type ParamBinding = (Identifier, TypeOrExpr)
type ModportDecl = (Direction, Identifier, Expr) type ModportDecl = (Direction, Identifier, Type, Expr)
data AlwaysKW data AlwaysKW
= Always = Always
......
...@@ -588,7 +588,7 @@ ModportPortsDeclarations :: { [ModportDecl] } ...@@ -588,7 +588,7 @@ ModportPortsDeclarations :: { [ModportDecl] }
ModportPortsDeclaration(delim) :: { [ModportDecl] } ModportPortsDeclaration(delim) :: { [ModportDecl] }
: ModportSimplePortsDeclaration(delim) { $1 } : ModportSimplePortsDeclaration(delim) { $1 }
ModportSimplePortsDeclaration(delim) :: { [ModportDecl] } 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)] } ModportSimplePorts :: { [(Identifier, Expr)] }
: ModportSimplePort { [$1] } : ModportSimplePort { [$1] }
| ModportSimplePorts "," ModportSimplePort { $1 ++ [$3] } | ModportSimplePorts "," ModportSimplePort { $1 ++ [$3] }
......
localparam SOME_VAL = 3; localparam SOME_VAL = 3;
interface Interface; interface Interface;
logic x; logic x = 0;
modport Modport( modport Modport(
input x input x
); );
...@@ -15,11 +15,11 @@ module Module(Interface.Modport foo); ...@@ -15,11 +15,11 @@ module Module(Interface.Modport foo);
initial $display("Module %d", foo.x); initial $display("Module %d", foo.x);
endmodule endmodule
module top; module top;
Interface i();
Module m(i);
generate generate
for (genvar g = 0; g < 5; ++g) begin for (genvar g = 0; g < 5; ++g) begin
initial $display(g); initial $display(g);
end end
endgenerate endgenerate
Interface i();
Module m(i);
endmodule endmodule
...@@ -2,16 +2,16 @@ module Module(input wire x); ...@@ -2,16 +2,16 @@ module Module(input wire x);
initial $display("Module %d", x); initial $display("Module %d", x);
endmodule endmodule
module top; module top;
wire i_x; wire i_x = 0;
localparam SOME_VAL = 3; localparam SOME_VAL = 3;
initial $display("Interface %d %d", i_x, SOME_VAL); initial $display("Interface %d %d", i_x, SOME_VAL);
Module m(.x(i_x)); Module m(.x(i_x));
generate generate
genvar g; genvar g;
for (g = 0; g < 5; g = g + 1) begin for (g = 10; g < 15; g = g + 1) begin
initial $display(g); initial $display(g);
end end
for (g = 10; g < 15; g = g + 1) begin for (g = 0; g < 5; g = g + 1) begin
initial $display(g); initial $display(g);
end end
endgenerate 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