mirror of https://github.com/zachjs/sv2v.git
assign a unique identifier to every genvar
This commit is contained in:
parent
a209335c30
commit
ba94920ee0
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
{-# 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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
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
|
||||
Loading…
Reference in New Issue