Commit 9d7f9176 by Zachary Snow

handle naming and scoping of unnamed generate blocks

parent 6e852451
...@@ -47,6 +47,7 @@ import qualified Convert.Typedef ...@@ -47,6 +47,7 @@ import qualified Convert.Typedef
import qualified Convert.TypeOf import qualified Convert.TypeOf
import qualified Convert.UnbasedUnsized import qualified Convert.UnbasedUnsized
import qualified Convert.Unique import qualified Convert.Unique
import qualified Convert.UnnamedGenBlock
import qualified Convert.UnpackedArray import qualified Convert.UnpackedArray
import qualified Convert.Unsigned import qualified Convert.Unsigned
import qualified Convert.Wildcard import qualified Convert.Wildcard
...@@ -105,6 +106,7 @@ initialPhases selectExclude = ...@@ -105,6 +106,7 @@ initialPhases selectExclude =
, Convert.Package.convert , Convert.Package.convert
, Convert.ParamNoDefault.convert , Convert.ParamNoDefault.convert
, Convert.ResolveBindings.convert , Convert.ResolveBindings.convert
, Convert.UnnamedGenBlock.convert
] ]
convert :: [Job.Exclude] -> Phase convert :: [Job.Exclude] -> Phase
......
...@@ -341,7 +341,7 @@ inlineInstance global ranges modportBindings items partName ...@@ -341,7 +341,7 @@ inlineInstance global ranges modportBindings items partName
comment : comment :
map (MIPackageItem . Decl) bindingBaseParams ++ map (MIPackageItem . Decl) bindingBaseParams ++
map (MIPackageItem . Decl) parameterBinds ++ map (MIPackageItem . Decl) parameterBinds ++
(wrapInstance $ GenBlock instanceName $ map GenModuleItem items') wrapInstance instanceName items'
: portBindings : portBindings
where where
items' = evalScoper items' = evalScoper
...@@ -367,11 +367,20 @@ inlineInstance global ranges modportBindings items partName ...@@ -367,11 +367,20 @@ inlineInstance global ranges modportBindings items partName
comment = MIPackageItem $ Decl $ CommentDecl $ comment = MIPackageItem $ Decl $ CommentDecl $
"expanded " ++ inlineKind ++ " instance: " ++ instanceName "expanded " ++ inlineKind ++ " instance: " ++ instanceName
portBindings = mapMaybe portBindingItem $ portBindings =
wrapPortBindings $
map portBindingItem $
filter ((/= Nil) . snd) $
filter notSubstituted instancePorts filter notSubstituted instancePorts
notSubstituted :: PortBinding -> Bool notSubstituted :: PortBinding -> Bool
notSubstituted (portName, _) = notSubstituted (portName, _) =
lookup portName modportBindings == Nothing 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 :: ModuleItem -> ModuleItem
rewriteItem = rewriteItem =
...@@ -573,10 +582,8 @@ inlineInstance global ranges modportBindings items partName ...@@ -573,10 +582,8 @@ inlineInstance global ranges modportBindings items partName
++ " expected type, found expr: " ++ show e' ++ " expected type, found expr: " ++ show e'
overrideParam other = other overrideParam other = other
portBindingItem :: PortBinding -> Maybe ModuleItem portBindingItem :: PortBinding -> ModuleItem
portBindingItem (_, Nil) = Nothing
portBindingItem (ident, expr) = portBindingItem (ident, expr) =
Just $ wrapInstance $ GenModuleItem $
if findDeclDir ident == Input if findDeclDir ident == Input
then bind (LHSDot (inj LHSBit LHSIdent) ident) expr then bind (LHSDot (inj LHSBit LHSIdent) ident) expr
else bind (toLHS expr) (Dot (inj Bit Ident) ident) else bind (toLHS expr) (Dot (inj Bit Ident) ident)
...@@ -614,8 +621,8 @@ inlineInstance global ranges modportBindings items partName ...@@ -614,8 +621,8 @@ inlineInstance global ranges modportBindings items partName
[arrayRange @ (arrayLeft, arrayRight)] = ranges [arrayRange @ (arrayLeft, arrayRight)] = ranges
-- wrap the given item in a generate loop if necessary -- wrap the given item in a generate loop if necessary
wrapInstance :: GenItem -> ModuleItem wrapInstance :: Identifier -> [ModuleItem] -> ModuleItem
wrapInstance item = wrapInstance blockName moduleItems =
Generate $ Generate $
if not isArray then if not isArray then
[item] [item]
...@@ -624,6 +631,7 @@ inlineInstance global ranges modportBindings items partName ...@@ -624,6 +631,7 @@ inlineInstance global ranges modportBindings items partName
, GenFor inits cond incr item , GenFor inits cond incr item
] ]
where where
item = GenBlock blockName $ map GenModuleItem moduleItems
inits = (loopVar, arrayLeft) inits = (loopVar, arrayLeft)
cond = endianCondExpr arrayRange cond = endianCondExpr arrayRange
(BinOp Ge (Ident loopVar) arrayRight) (BinOp Ge (Ident loopVar) arrayRight)
......
...@@ -512,8 +512,6 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper = ...@@ -512,8 +512,6 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
fullModuleItemMapper item >>= return . MIAttr attr fullModuleItemMapper item >>= return . MIAttr attr
fullModuleItemMapper item = moduleItemMapper item 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 -> ScoperT a m GenItem
fullGenItemMapper genItem = do fullGenItemMapper genItem = do
genItem' <- genItemMapper genItem genItem' <- genItemMapper genItem
...@@ -524,7 +522,7 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper = ...@@ -524,7 +522,7 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper =
injected' <- mapM fullModuleItemMapper injected injected' <- mapM fullModuleItemMapper injected
genItem'' <- scopeGenItemMapper genItem' genItem'' <- scopeGenItemMapper genItem'
let genItems = map GenModuleItem injected' ++ [genItem''] let genItems = map GenModuleItem injected' ++ [genItem'']
return $ GenBlock "" genItems return $ GenBlock "" genItems -- flattened during traversal
scopeGenItemMapper :: GenItem -> ScoperT a m GenItem scopeGenItemMapper :: GenItem -> ScoperT a m GenItem
scopeGenItemMapper (GenFor (index, a) b c genItem) = do scopeGenItemMapper (GenFor (index, a) b c genItem) = do
genItem' <- scopeGenItemBranchMapper index genItem 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] } ...@@ -1352,6 +1352,7 @@ GenItems :: { [GenItem] }
GenItem :: { GenItem } GenItem :: { GenItem }
: GenBlock { uncurry GenBlock $1 } : GenBlock { uncurry GenBlock $1 }
| NonGenerateModuleItem { genItemsToGenItem $ map GenModuleItem $1 } | NonGenerateModuleItem { genItemsToGenItem $ map GenModuleItem $1 }
| "generate" GenItems "endgenerate" { genItemsToGenItem $2 }
| ConditionalGenerateConstruct { $1 } | ConditionalGenerateConstruct { $1 }
| LoopGenerateConstruct { $1 } | LoopGenerateConstruct { $1 }
ConditionalGenerateConstruct :: { GenItem } ConditionalGenerateConstruct :: { GenItem }
...@@ -1375,7 +1376,7 @@ GenCase :: { GenCase } ...@@ -1375,7 +1376,7 @@ GenCase :: { GenCase }
| "default" opt(":") GenItemOrNull { ([], $3) } | "default" opt(":") GenItemOrNull { ([], $3) }
GenvarInitialization :: { Expr -> (Identifier, AsgnOp, Expr) -> GenItem -> GenItem } 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) } | Identifier "=" Expr { GenFor ($1, $3) }
GenvarIteration :: { (Identifier, AsgnOp, Expr) } GenvarIteration :: { (Identifier, AsgnOp, Expr) }
...@@ -1480,7 +1481,7 @@ parseError a = case a of ...@@ -1480,7 +1481,7 @@ parseError a = case a of
genItemsToGenItem :: [GenItem] -> GenItem genItemsToGenItem :: [GenItem] -> GenItem
genItemsToGenItem [x] = x genItemsToGenItem [x] = x
genItemsToGenItem xs = GenBlock "" xs genItemsToGenItem xs = GenModuleItem $ Generate xs
combineDeclsAndStmts :: ([Decl], [Stmt]) -> ([Decl], [Stmt]) -> combineDeclsAndStmts :: ([Decl], [Stmt]) -> ([Decl], [Stmt]) ->
ParseState ([Decl], [Stmt]) ParseState ([Decl], [Stmt])
......
...@@ -99,6 +99,7 @@ executable sv2v ...@@ -99,6 +99,7 @@ executable sv2v
Convert.TypeOf Convert.TypeOf
Convert.UnbasedUnsized Convert.UnbasedUnsized
Convert.Unique Convert.Unique
Convert.UnnamedGenBlock
Convert.UnpackedArray Convert.UnpackedArray
Convert.Unsigned Convert.Unsigned
Convert.Wildcard 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