Commit b2fe865e by Zachary Snow

fix interface modport substitution strategy

The interface conversion no longer substitutes parameters immediately,
instead fully scoping modports and allowing hierarchical constants to be
resolved separately. This fixes an issue where struct parameters could
lose their type information during substitution. The conversion also now
handles renaming references to the module or interface top-level scope.
parent 67c0d22a
......@@ -7,7 +7,6 @@
module Convert.Interface (convert) where
import Data.List (isPrefixOf)
import Data.Maybe (isNothing, mapMaybe)
import Control.Monad.Writer.Strict
import qualified Data.Map.Strict as Map
......@@ -272,16 +271,7 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
toPortBinding (_, x, e) = (x', e')
where
x' = Dot baseE x
e' = prefixExpr e
prefixExpr :: Expr -> Expr
prefixExpr (Ident x) =
case Map.lookup x replacements of
Just replacement -> replacement
Nothing ->
if "_param_" `isPrefixOf` x
then Ident x
else Dot instanceE x
prefixExpr other = traverseSinglyNestedExprs prefixExpr other
e' = replaceInExpr replacements e
-- association list of modport instances in the given module body
extractModportInstances :: PartInfo -> ModportInstances
......@@ -348,9 +338,9 @@ inlineInstance global ranges modportBindings items partName
wrapInstance instanceName items'
: portBindings
where
items' = evalScoper
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM ""
$ map (traverseNestedModuleItems rewriteItem) $
items' = evalScoper traverseDeclM traverseModuleItemM traverseGenItemM
traverseStmtM partName $
map (traverseNestedModuleItems rewriteItem) $
if null modportBindings
then items ++ [typeModport, dimensionModport, bundleModport]
else items
......@@ -393,28 +383,27 @@ inlineInstance global ranges modportBindings items partName
removeDeclDir .
overrideParam
traverseDeclM :: Decl -> Scoper Expr Decl
traverseDeclM :: Decl -> Scoper () Decl
traverseDeclM decl = do
decl' <- traverseDeclExprsM substituteExprM decl
case decl' of
Variable _ _ x _ _ -> insertElem x Nil
Net _ _ _ _ x _ _ -> insertElem x Nil
Param _ _ x e -> insertElem x e
ParamType _ x _ -> insertElem x Nil
case decl of
Variable _ _ x _ _ -> insertElem x ()
Net _ _ _ _ x _ _ -> insertElem x ()
Param _ _ x _ -> insertElem x ()
ParamType _ x _ -> insertElem x ()
CommentDecl{} -> return ()
return decl'
return decl
traverseModuleItemM :: ModuleItem -> Scoper Expr ModuleItem
traverseModuleItemM :: ModuleItem -> Scoper () ModuleItem
traverseModuleItemM (item @ Modport{}) =
traverseExprsM substituteExprM item
traverseExprsM (scopeExpr >=> traverseExprM) item
traverseModuleItemM item =
traverseExprsM traverseExprM item >>=
traverseLHSsM traverseLHSM
traverseGenItemM :: GenItem -> Scoper Expr GenItem
traverseGenItemM :: GenItem -> Scoper () GenItem
traverseGenItemM = traverseGenItemExprsM traverseExprM
traverseStmtM :: Stmt -> Scoper Expr Stmt
traverseStmtM :: Stmt -> Scoper () Stmt
traverseStmtM =
traverseStmtExprsM traverseExprM >=>
traverseStmtLHSsM traverseLHSM
......@@ -424,16 +413,22 @@ inlineInstance global ranges modportBindings items partName
lhsReplacements = map (\(x, y) -> (toLHS x, toLHS y)) exprReplacements
exprReplacements = filter ((/= Nil) . snd) modportSubstitutions
-- LHSs are replaced using simple substitutions
traverseLHSM :: LHS -> Scoper Expr LHS
traverseLHSM :: LHS -> Scoper () LHS
traverseLHSM =
embedScopes tagLHS >=>
embedScopes replaceLHS
tagLHS :: Scopes Expr -> LHS -> LHS
tagLHS :: Scopes () -> LHS -> LHS
tagLHS scopes lhs =
if lookupElem scopes lhs /= Nothing
then LHSDot lhs "@"
then LHSDot (renamePartLHS lhs) "@"
else traverseSinglyNestedLHSs (tagLHS scopes) lhs
replaceLHS :: Scopes Expr -> LHS -> LHS
renamePartLHS :: LHS -> LHS
renamePartLHS (LHSDot (LHSIdent x) y) =
if x == partName
then LHSDot scopedInstanceLHS y
else LHSDot (LHSIdent x) y
renamePartLHS lhs = traverseSinglyNestedLHSs renamePartLHS lhs
replaceLHS :: Scopes () -> LHS -> LHS
replaceLHS _ (LHSDot lhs "@") = lhs
replaceLHS local (LHSDot (LHSBit lhs elt) field) =
case lookup (LHSDot (LHSBit lhs Tag) field) lhsReplacements of
......@@ -448,24 +443,22 @@ inlineInstance global ranges modportBindings items partName
replaceLHSArrTag =
traverseNestedLHSs . (traverseLHSExprs . replaceArrTag)
-- top-level expressions may be modports bound to other modports
traverseExprM :: Expr -> Scoper Expr Expr
traverseExprM :: Expr -> Scoper () Expr
traverseExprM =
embedScopes (tagExpr False) >=>
embedScopes tagExpr >=>
embedScopes replaceExpr
substituteExprM :: Expr -> Scoper Expr Expr
substituteExprM =
embedScopes (tagExpr True) >=>
embedScopes replaceExpr
tagExpr :: Bool -> Scopes Expr -> Expr -> Expr
tagExpr substitute scopes expr =
case lookupElem scopes expr of
Just (_, _, expr') ->
if substitute && expr' /= Nil
then Dot expr' "@"
else Dot expr "@"
Nothing ->
traverseSinglyNestedExprs (tagExpr substitute scopes) expr
replaceExpr :: Scopes Expr -> Expr -> Expr
tagExpr :: Scopes () -> Expr -> Expr
tagExpr scopes expr =
if lookupElem scopes expr /= Nothing
then Dot (renamePartExpr expr) "@"
else traverseSinglyNestedExprs (tagExpr scopes) expr
renamePartExpr :: Expr -> Expr
renamePartExpr (Dot (Ident x) y) =
if x == partName
then Dot scopedInstanceExpr y
else Dot (Ident x) y
renamePartExpr expr = traverseSinglyNestedExprs renamePartExpr expr
replaceExpr :: Scopes () -> Expr -> Expr
replaceExpr _ (Dot expr "@") = expr
replaceExpr local (Ident x) =
case lookup x modportBindings of
......@@ -473,7 +466,7 @@ inlineInstance global ranges modportBindings items partName
Nothing -> checkExprResolution local (Ident x) (Ident x)
replaceExpr local expr =
replaceExpr' local expr
replaceExpr' :: Scopes Expr -> Expr -> Expr
replaceExpr' :: Scopes () -> Expr -> Expr
replaceExpr' _ (Dot expr "@") = expr
replaceExpr' local (Dot (Bit expr elt) field) =
case lookup (Dot (Bit expr Tag) field) exprReplacements of
......@@ -491,7 +484,7 @@ inlineInstance global ranges modportBindings items partName
replaceExpr' local (Ident x) =
checkExprResolution local (Ident x) (Ident x)
replaceExpr' local expr = replaceExprAny local expr
replaceExprAny :: Scopes Expr -> Expr -> Expr
replaceExprAny :: Scopes () -> Expr -> Expr
replaceExprAny local expr =
case lookup expr exprReplacements of
Just expr' -> expr'
......@@ -502,7 +495,7 @@ inlineInstance global ranges modportBindings items partName
replaceArrTag replacement expr =
traverseSinglyNestedExprs (replaceArrTag replacement) expr
checkExprResolution :: Scopes Expr -> Expr -> a -> a
checkExprResolution :: Scopes () -> Expr -> a -> a
checkExprResolution local expr =
case (lookupElem local expr, lookupElem global expr) of
(Nothing, Just (_, _, DeclVal)) ->
......@@ -513,6 +506,14 @@ inlineInstance global ranges modportBindings items partName
++ "\" resolvable when it wasn't previously"
_ -> id
-- unambiguous reference to the current instance
scopedInstanceRaw = accessesToExpr $ localAccesses global instanceName
scopedInstanceExpr =
if isArray
then Bit scopedInstanceRaw (Ident loopVar)
else scopedInstanceRaw
Just scopedInstanceLHS = exprToLHS scopedInstanceExpr
removeModportInstance :: Decl -> Decl
removeModportInstance (Variable d t x a e) =
if maybeModportBinding == Nothing then
......
typedef struct packed {
byte x;
shortint y;
} T;
interface intf;
parameter T P = 0;
wire [P.x-1:0] z = '1;
initial begin
$display("intf.P.x %0d", P.x);
$display("intf.P.y %0d", P.y);
end
if (P.x) begin : blk
wire [31:0] z;
end
wire [31:0] z = P.y;
if (P.x) begin : blk2
integer z;
assign intf.blk.z = intf.z;
end
modport X (
input .x(P),
input .y(intf.blk.z)
);
endinterface
module mod(
intf.X f
);
integer i;
initial begin
$display("mod.f.x %b", f.x);
$display("mod.f.y %b", f.y);
end
endmodule
module top;
localparam T Q = '{ x: 1, y: 2 };
localparam T R = '{ x: 4, y: 6 };
intf #(Q) i();
intf #(R) is [1:0] ();
mod m(i);
mod ms(is[0]);
endmodule
module top;
initial begin
$display("intf.P.x %0d", 1);
$display("intf.P.y %0d", 2);
$display("intf.P.x %0d", 4);
$display("intf.P.y %0d", 6);
$display("intf.P.x %0d", 4);
$display("intf.P.y %0d", 6);
$display("mod.f.x %b", {8'd1, 16'd2});
$display("mod.f.y %b", 32'h1);
$display("mod.f.x %b", {8'd4, 16'd6});
$display("mod.f.y %b", 32'hF);
end
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