mirror of https://github.com/zachjs/sv2v.git
handle naming and scoping of unnamed generate blocks
This commit is contained in:
parent
6e85245118
commit
9d7f917608
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
{- 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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
module top;
|
||||
if (1) begin
|
||||
// should not be visible in a top-level VCD
|
||||
wire x;
|
||||
assign x = 1;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// 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
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
`define REF
|
||||
`include "unnamed_genblk_zeroes.sv"
|
||||
Loading…
Reference in New Issue