Commit ba94920e by Zachary Snow

assign a unique identifier to every genvar

parent a209335c
......@@ -13,6 +13,8 @@
### Bug Fixes
* Fixed an issue that prevented parsing tasks and functions with `inout` ports
* Fixed conflicting genvar names when inlining interfaces and modules that use
them; all genvars are now given a design-wide unique name
* Fixed errant constant folding of shadowed non-trivial localparams
* Fixed certain non-ANSI style port declarations being incorrectly reported as
incompatible
......
......@@ -27,6 +27,7 @@ import qualified Convert.ForAsgn
import qualified Convert.Foreach
import qualified Convert.FuncRet
import qualified Convert.FuncRoutine
import qualified Convert.GenvarName
import qualified Convert.HierConst
import qualified Convert.ImplicitNet
import qualified Convert.Inside
......@@ -114,6 +115,7 @@ initialPhases tops selectExclude =
, Convert.DoWhile.convert
, Convert.Foreach.convert
, Convert.FuncRoutine.convert
, Convert.GenvarName.convert
, selectExclude Job.Assert Convert.Assertion.convert
, selectExclude Job.Always Convert.AlwaysKW.convert
, Convert.Interface.disambiguate
......
{-# LANGUAGE TupleSections #-}
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Assign unique names to `genvar`s to avoid conflicts within explicitly-scoped
- variables when inlining interface arrays.
-}
module Convert.GenvarName (convert) where
import Control.Monad.State.Strict
import Control.Monad.Writer.Strict
import Data.Functor ((<&>))
import Data.List (isPrefixOf)
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Convert.Scoper (replaceInExpr)
import Convert.Traverse
import Language.SystemVerilog.AST
convert :: [AST] -> [AST]
convert files = evalState
(mapM (traverseDescriptionsM traverseDescription) files)
(collectFiles files, mempty)
type IdentSet = Set.Set Identifier
type IdentMap = Map.Map Identifier Identifier
type SC = State (IdentSet, IdentMap)
-- get all of the seemingly sv2v-generated genvar names already present anywhere
-- in the sources so we can avoid generating new ones that conflict with them
collectFiles :: [AST] -> IdentSet
collectFiles = execWriter . mapM (collectDescriptionsM collectDescription)
collectDescription :: Description -> Writer IdentSet ()
collectDescription = collectModuleItemsM collectModuleItem
collectModuleItem :: ModuleItem -> Writer IdentSet ()
collectModuleItem (Genvar ident) =
when (isGeneratedName ident) $ tell (Set.singleton ident)
collectModuleItem _ = return ()
traverseDescription :: Description -> SC Description
traverseDescription (Part att ext kw lif name ports items) =
mapM traverseModuleItem items <&> Part att ext kw lif name ports
traverseDescription description = return description
traverseModuleItem :: ModuleItem -> SC ModuleItem
traverseModuleItem (Genvar ident) =
renameGenvar ident <&> Genvar
traverseModuleItem (Generate genItems) =
mapM traverseGenItem genItems <&> Generate
traverseModuleItem (MIAttr attr item) =
traverseModuleItem item <&> MIAttr attr
traverseModuleItem item = return item
traverseGenItem :: GenItem -> SC GenItem
traverseGenItem (GenFor start@(index, _) cond incr item)
| not (isGeneratedName index) = do
index' <- gets $ (Map.! index) . snd
item' <- traverseGenItem item
return $ if index == index'
then GenFor start cond incr item'
else renameInLoop start cond incr index' item'
traverseGenItem (GenBlock blk items) = do
priorMapping <- gets snd
items' <- mapM traverseGenItem items
-- keep all assigned names, but prefer names from the outer scope
modify' $ (, priorMapping) . fst
return $ GenBlock blk items'
traverseGenItem (GenModuleItem item) =
traverseModuleItem item <&> GenModuleItem
traverseGenItem item =
traverseSinglyNestedGenItemsM traverseGenItem item
-- rename all usages of the genvar in the initialization, guard, and
-- incrementation of a generate for loop
renameInLoop :: (Identifier, Expr) -> Expr -> (Identifier, AsgnOp, Expr)
-> Identifier -> GenItem -> GenItem
renameInLoop (index, start) cond (dest, op, next) index' =
GenFor (index', start') cond' (dest', op, next') . prependGenItem decl
where
expr = Ident index'
replacements = Map.singleton index expr
start' = replaceInExpr replacements start
cond' = replaceInExpr replacements cond
next' = replaceInExpr replacements next
dest' = if dest == index then index' else dest
decl = GenModuleItem $ MIPackageItem $ Decl $
Param Localparam UnknownType index expr
-- add an item to the beginning of the given generate block
prependGenItem :: GenItem -> GenItem -> GenItem
prependGenItem item block = GenBlock blk $ item : items
where GenBlock blk items = block
prefixIntf :: Identifier
prefixIntf = "_arr_"
prefixUniq :: Identifier
prefixUniq = "_gv_"
isGeneratedName :: Identifier -> Bool
isGeneratedName ident =
isPrefixOf prefixIntf ident ||
isPrefixOf prefixUniq ident
-- generate and record a unique name for the given genvar
renameGenvar :: Identifier -> SC Identifier
renameGenvar ident | isGeneratedName ident = return ident
renameGenvar ident = do
idents <- gets fst
let ident' = uniqueGenvarName idents prefix 1
modify' $ (<>) (Set.singleton ident', Map.singleton ident ident')
return ident'
where prefix = prefixUniq ++ ident ++ "_"
-- increment the counter until it produces a unique identifier
uniqueGenvarName :: IdentSet -> Identifier -> Int -> Identifier
uniqueGenvarName idents prefix = step
where
step :: Int -> Identifier
step counter =
if Set.member candidate idents
then step $ counter + 1
else candidate
where candidate = prefix ++ show counter
......@@ -79,6 +79,7 @@ executable sv2v
Convert.Foreach
Convert.FuncRet
Convert.FuncRoutine
Convert.GenvarName
Convert.HierConst
Convert.ImplicitNet
Convert.Inside
......
interface intf;
parameter P;
logic [P - 1:0] x;
assign x = P;
initial $display("intf %b", x);
endinterface
module mod(intf intf[4]);
genvar i;
for (i = 0; i < 4; i++) begin : blk
for (genvar i = 0; i < 2; i++) begin : blk
initial $display("foo %0d", i);
end
initial $display("mod [%0d] %b", i, intf[i].x);
initial begin
localparam intf = "shadowed_intf";
$display("mod %s %0d %b", intf, i, mod.intf[i].x);
end
end
for (i = 0; i < 2; i++) begin
initial $display("bar %0d", i);
end
endmodule
module top;
for (genvar i = 1; i <= 8; i *= 2) begin : blk
intf #(i) intf[4]();
mod mod(intf);
end
endmodule
module top;
genvar i, j, k;
generate
for (i = 1; i <= 8; i = i * 2) begin : blk
for (j = 0; j < 4; j = j + 1) begin : blk
wire [i - 1:0] x;
assign x = i;
initial $display("intf %b", x);
end
for (j = 0; j < 4; j = j + 1) begin : alt
for (k = 0; k < 2; k = k + 1)
initial $display("foo %0d", k);
initial $display("mod [%0d] %b", j, top.blk[i].blk[j].x);
initial $display("mod shadowed_intf %0d %b", j, top.blk[i].blk[j].x);
end
for (k = 0; k < 2; k = k + 1)
initial $display("bar %0d", k);
end
endgenerate
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