Commit ba94920e by Zachary Snow

assign a unique identifier to every genvar

parent a209335c
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
### Bug Fixes ### Bug Fixes
* Fixed an issue that prevented parsing tasks and functions with `inout` ports * 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 errant constant folding of shadowed non-trivial localparams
* Fixed certain non-ANSI style port declarations being incorrectly reported as * Fixed certain non-ANSI style port declarations being incorrectly reported as
incompatible incompatible
......
...@@ -27,6 +27,7 @@ import qualified Convert.ForAsgn ...@@ -27,6 +27,7 @@ import qualified Convert.ForAsgn
import qualified Convert.Foreach import qualified Convert.Foreach
import qualified Convert.FuncRet import qualified Convert.FuncRet
import qualified Convert.FuncRoutine import qualified Convert.FuncRoutine
import qualified Convert.GenvarName
import qualified Convert.HierConst import qualified Convert.HierConst
import qualified Convert.ImplicitNet import qualified Convert.ImplicitNet
import qualified Convert.Inside import qualified Convert.Inside
...@@ -114,6 +115,7 @@ initialPhases tops selectExclude = ...@@ -114,6 +115,7 @@ initialPhases tops selectExclude =
, Convert.DoWhile.convert , Convert.DoWhile.convert
, Convert.Foreach.convert , Convert.Foreach.convert
, Convert.FuncRoutine.convert , Convert.FuncRoutine.convert
, Convert.GenvarName.convert
, selectExclude Job.Assert Convert.Assertion.convert , selectExclude Job.Assert Convert.Assertion.convert
, selectExclude Job.Always Convert.AlwaysKW.convert , selectExclude Job.Always Convert.AlwaysKW.convert
, Convert.Interface.disambiguate , 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 ...@@ -79,6 +79,7 @@ executable sv2v
Convert.Foreach Convert.Foreach
Convert.FuncRet Convert.FuncRet
Convert.FuncRoutine Convert.FuncRoutine
Convert.GenvarName
Convert.HierConst Convert.HierConst
Convert.ImplicitNet Convert.ImplicitNet
Convert.Inside 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