Commit 9d7f9176 by Zachary Snow

handle naming and scoping of unnamed generate blocks

parent 6e852451
......@@ -47,6 +47,7 @@ import qualified Convert.Typedef
import qualified Convert.TypeOf
import qualified Convert.UnbasedUnsized
import qualified Convert.Unique
import qualified Convert.UnnamedGenBlock
import qualified Convert.UnpackedArray
import qualified Convert.Unsigned
import qualified Convert.Wildcard
......@@ -105,6 +106,7 @@ initialPhases selectExclude =
, Convert.Package.convert
, Convert.ParamNoDefault.convert
, Convert.ResolveBindings.convert
, Convert.UnnamedGenBlock.convert
]
convert :: [Job.Exclude] -> Phase
......
......@@ -341,7 +341,7 @@ inlineInstance global ranges modportBindings items partName
comment :
map (MIPackageItem . Decl) bindingBaseParams ++
map (MIPackageItem . Decl) parameterBinds ++
(wrapInstance $ GenBlock instanceName $ map GenModuleItem items')
wrapInstance instanceName items'
: portBindings
where
items' = evalScoper
......@@ -367,11 +367,20 @@ inlineInstance global ranges modportBindings items partName
comment = MIPackageItem $ Decl $ CommentDecl $
"expanded " ++ inlineKind ++ " instance: " ++ instanceName
portBindings = mapMaybe portBindingItem $
portBindings =
wrapPortBindings $
map portBindingItem $
filter ((/= Nil) . snd) $
filter notSubstituted instancePorts
notSubstituted :: PortBinding -> Bool
notSubstituted (portName, _) =
lookup portName modportBindings == Nothing
wrapPortBindings :: [ModuleItem] -> [ModuleItem]
wrapPortBindings =
if isArray
then (\x -> [x]) . wrapInstance blockName
else id
where blockName = instanceName ++ "_port_bindings"
rewriteItem :: ModuleItem -> ModuleItem
rewriteItem =
......@@ -573,10 +582,8 @@ inlineInstance global ranges modportBindings items partName
++ " expected type, found expr: " ++ show e'
overrideParam other = other
portBindingItem :: PortBinding -> Maybe ModuleItem
portBindingItem (_, Nil) = Nothing
portBindingItem :: PortBinding -> ModuleItem
portBindingItem (ident, expr) =
Just $ wrapInstance $ GenModuleItem $
if findDeclDir ident == Input
then bind (LHSDot (inj LHSBit LHSIdent) ident) expr
else bind (toLHS expr) (Dot (inj Bit Ident) ident)
......@@ -614,8 +621,8 @@ inlineInstance global ranges modportBindings items partName
[arrayRange @ (arrayLeft, arrayRight)] = ranges
-- wrap the given item in a generate loop if necessary
wrapInstance :: GenItem -> ModuleItem
wrapInstance item =
wrapInstance :: Identifier -> [ModuleItem] -> ModuleItem
wrapInstance blockName moduleItems =
Generate $
if not isArray then
[item]
......@@ -624,6 +631,7 @@ inlineInstance global ranges modportBindings items partName
, GenFor inits cond incr item
]
where
item = GenBlock blockName $ map GenModuleItem moduleItems
inits = (loopVar, arrayLeft)
cond = endianCondExpr arrayRange
(BinOp Ge (Ident loopVar) arrayRight)
......
......@@ -512,8 +512,6 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
fullModuleItemMapper item >>= return . MIAttr attr
fullModuleItemMapper item = moduleItemMapper item
-- TODO: This doesn't yet support implicit naming of generate blocks as
-- blocks as described in Section 27.6.
fullGenItemMapper :: GenItem -> ScoperT a m GenItem
fullGenItemMapper genItem = do
genItem' <- genItemMapper genItem
......@@ -524,7 +522,7 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
injected' <- mapM fullModuleItemMapper injected
genItem'' <- scopeGenItemMapper genItem'
let genItems = map GenModuleItem injected' ++ [genItem'']
return $ GenBlock "" genItems
return $ GenBlock "" genItems -- flattened during traversal
scopeGenItemMapper :: GenItem -> ScoperT a m GenItem
scopeGenItemMapper (GenFor (index, a) b c genItem) = do
genItem' <- scopeGenItemBranchMapper index genItem
......
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Labels any unnamed generate blocks, per IEEE 1800-2017 Section 27.6
-
- This transformation is performed before any others, and is only performed
- once. The AST traversal utilities are not used here to avoid the automatic
- elaboration they perform.
-}
module Convert.UnnamedGenBlock (convert) where
import Control.Monad.State.Strict
import Data.List (isPrefixOf)
import Language.SystemVerilog.AST
convert :: [AST] -> [AST]
convert = map $ map traverseDescription
traverseDescription :: Description -> Description
traverseDescription (Part attrs extern kw lifetime name ports items) =
Part attrs extern kw lifetime name ports $
evalState (mapM traverseModuleItemM items) initialState
traverseDescription other = other
type S = State Info
type Info = ([Identifier], Int)
initialState :: Info
initialState = ([], 1)
traverseModuleItemM :: ModuleItem -> S ModuleItem
traverseModuleItemM (item @ (Genvar x)) = declaration x item
traverseModuleItemM (item @ (NInputGate _ _ x _ _)) = declaration x item
traverseModuleItemM (item @ (NOutputGate _ _ x _ _)) = declaration x item
traverseModuleItemM (item @ (Instance _ _ x _ _)) = declaration x item
traverseModuleItemM (MIPackageItem (Decl decl)) =
traverseDeclM decl >>= return . MIPackageItem . Decl
traverseModuleItemM (MIAttr attr item) =
traverseModuleItemM item >>= return . MIAttr attr
traverseModuleItemM (Generate items) =
mapM traverseGenItemM items >>= return . Generate
traverseModuleItemM item = return item
-- add a declaration to the conflict list
traverseDeclM :: Decl -> S Decl
traverseDeclM decl =
case decl of
Variable _ _ x _ _ -> declaration x decl
Param _ _ x _ -> declaration x decl
ParamType _ x _ -> declaration x decl
CommentDecl{} -> return decl
-- label the generate blocks within an individual generate item which is already
-- in a list of generate items (top level or generate block)
traverseGenItemM :: GenItem -> S GenItem
traverseGenItemM (item @ GenIf{}) = do
item' <- labelGenElse item
incrCount >> return item'
traverseGenItemM (item @ GenBlock{}) = do
item' <- labelBlock item
incrCount >> return item'
traverseGenItemM (GenFor a b c item) = do
item' <- labelBlock item
incrCount >> return (GenFor a b c item')
traverseGenItemM (GenCase expr cases) = do
let (exprs, items) = unzip cases
items' <- mapM labelBlock items
let cases' = zip exprs items'
incrCount >> return (GenCase expr cases')
traverseGenItemM (GenModuleItem item) =
traverseModuleItemM item >>= return . GenModuleItem
traverseGenItemM GenNull = return GenNull
-- increment the counter each time a generate construct is encountered
incrCount :: S ()
incrCount = modify' $ \(idents, count) -> (idents, count + 1)
genblk :: Identifier
genblk = "genblk"
-- adds the given identifier to the list of possible identifier conflicts, if
-- necessary, and then returns the second argument as a shorthand courtesy
declaration :: Identifier -> a -> S a
declaration x a = do
when (genblk `isPrefixOf` x) $ do
let ident = drop (length genblk) x
modify' $ \(idents, count) -> (ident : idents, count)
return a
-- generate a locally unique gen block name
makeBlockName :: S Identifier
makeBlockName = do
(idents, count) <- get
let uniqueSuffix = prependZeroes idents (show count)
return $ genblk ++ uniqueSuffix
-- prepend zeroes until the string isn't in the list
prependZeroes :: [String] -> String -> String
prependZeroes xs x | notElem x xs = x
prependZeroes xs x = prependZeroes xs ('0' : x)
-- if the item is a generate conditional item, give its `then` block and any
-- direct `else if` blocks the same name
labelGenElse :: GenItem -> S GenItem
labelGenElse (GenIf cond thenItem elseItem) = do
thenItem' <- labelBlock thenItem
elseItem' <- labelGenElse elseItem
return $ GenIf cond thenItem' elseItem'
labelGenElse other = labelBlock other
-- transform the given item into a named generate block
labelBlock :: GenItem -> S GenItem
labelBlock (GenBlock "" items) =
makeBlockName >>= labelBlock . flip GenBlock items
labelBlock (GenBlock x items) =
return $ GenBlock x $
evalState (mapM traverseGenItemM items) initialState
labelBlock GenNull = return GenNull
labelBlock item = labelBlock $ GenBlock "" [item]
......@@ -1352,6 +1352,7 @@ GenItems :: { [GenItem] }
GenItem :: { GenItem }
: GenBlock { uncurry GenBlock $1 }
| NonGenerateModuleItem { genItemsToGenItem $ map GenModuleItem $1 }
| "generate" GenItems "endgenerate" { genItemsToGenItem $2 }
| ConditionalGenerateConstruct { $1 }
| LoopGenerateConstruct { $1 }
ConditionalGenerateConstruct :: { GenItem }
......@@ -1375,7 +1376,7 @@ GenCase :: { GenCase }
| "default" opt(":") GenItemOrNull { ([], $3) }
GenvarInitialization :: { Expr -> (Identifier, AsgnOp, Expr) -> GenItem -> GenItem }
: "genvar" Identifier "=" Expr { \a b c -> GenBlock "" [GenModuleItem (Genvar $2), GenFor ($2, $4) a b c] }
: "genvar" Identifier "=" Expr { \a b c -> genItemsToGenItem [GenModuleItem (Genvar $2), GenFor ($2, $4) a b c] }
| Identifier "=" Expr { GenFor ($1, $3) }
GenvarIteration :: { (Identifier, AsgnOp, Expr) }
......@@ -1480,7 +1481,7 @@ parseError a = case a of
genItemsToGenItem :: [GenItem] -> GenItem
genItemsToGenItem [x] = x
genItemsToGenItem xs = GenBlock "" xs
genItemsToGenItem xs = GenModuleItem $ Generate xs
combineDeclsAndStmts :: ([Decl], [Stmt]) -> ([Decl], [Stmt]) ->
ParseState ([Decl], [Stmt])
......
......@@ -99,6 +99,7 @@ executable sv2v
Convert.TypeOf
Convert.UnbasedUnsized
Convert.Unique
Convert.UnnamedGenBlock
Convert.UnpackedArray
Convert.Unsigned
Convert.Wildcard
......
module top;
if (1) begin
// should not be visible in a top-level VCD
wire x;
assign x = 1;
end
endmodule
// This test was adapted from Section 27.6 of IEEE 1800-2017
module mod;
initial $dumpvars(0, mod);
// needed because of steveicarus/iverilog#528
`ifdef __ICARUS__
`define BEGIN(name) begin : name
`define END end
`else
`define BEGIN(name)
`define END
`endif
parameter genblk2 = 0;
genvar i;
// The following generate block is implicitly named genblk1
if (genblk2) `BEGIN(genblk1) logic a; `END // mod.genblk1.a
else `BEGIN(genblk1) logic b; `END // mod.genblk1.b
// The following generate block is implicitly named genblk02
// as genblk2 is already a declared identifier
if (genblk2) `BEGIN(genblk02) logic a; `END // mod.genblk02.a
else `BEGIN(genblk02) logic b; `END // mod.genblk02.b
// The following generate block would have been named genblk3
// but is explicitly named g1
for (i = 0; i < 1; i = i + 1) begin : g1 // block name
// The following generate block is implicitly named genblk1
// as the first nested scope inside g1
if (1) `BEGIN(genblk1) logic a; `END // mod.g1[0].genblk1.a
end
// The following generate block is implicitly named genblk4 since
// it belongs to the fourth generate construct in scope "mod".
// The previous generate block would have been
// named genblk3 if it had not been explicitly named g1
for (i = 0; i < 1; i = i + 1) `BEGIN(genblk4)
// The following generate block is implicitly named genblk1
// as the first nested generate block in genblk4
if (1) `BEGIN(genblk1) logic a; `END // mod.genblk4[0].genblk1.a
`END
// The following generate block is implicitly named genblk5
if (1) `BEGIN(genblk5) logic a; `END // mod.genblk5.a
endmodule
module top;
mod #(0) m0();
mod #(1) m1();
endmodule
module example;
parameter P = 0;
// needed because of steveicarus/iverilog#528
`ifdef __ICARUS__
`define BEGIN begin : `BLK
`define END end
`else
`define BEGIN
`define END
`endif
`define BLK genblk1
if (P == 1) `BEGIN integer w = 1; `END
else if (P == 2) `BEGIN integer x = 2; `END
else if (P == 3) `BEGIN integer y = 3; `END
else `BEGIN integer z = 9; `END
`undef BLK
`define BLK genblk2
case (P)
1 : `BEGIN integer w = 1; `END
2 : `BEGIN integer x = 2; `END
3 : `BEGIN integer y = 3; `END
default: `BEGIN integer z = 9; `END
endcase
`undef BLK
`define BLK genblk3
if (1) `BEGIN wire a = 1; `END
endmodule
module top;
`define TEST(i, v) \
example #(i) e``i(); \
initial #i begin \
$display(`"e``i.genblk1.v: %0d`", e``i.genblk1.v); \
$display(`"e``i.genblk2.v: %0d`", e``i.genblk2.v); \
$display(`"e``i.genblk3.a: %0d`", e``i.genblk3.a); \
end
`TEST(1, w)
`TEST(2, x)
`TEST(3, y)
`TEST(4, z)
endmodule
module example;
initial $display("example");
endmodule
module top;
wire genblk1;
wire genblk33;
(* foo = 1 *) wire genblk01;
genvar genblk001;
example genblk0001();
wire x, y;
wire o1, o2, o3;
and genblk00001(o1, x, y);
not genblk000001(o2, o3, o1);
parameter genblk0000001 = 1;
`ifndef REF
typedef logic genblk00000001;
`endif
`define BLK genblk000000001
if (1) begin
`ifdef REF
: `BLK
reg
`else
genblk00000001
`endif
x = genblk0000001;
end
initial begin
`BLK.x = 1;
$display("%b", `BLK.x);
end
endmodule
`define REF
`include "unnamed_genblk_zeroes.sv"
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