sv2v/src/Convert/HierConst.hs

103 lines
4.0 KiB
Haskell

{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Elaborate hierarchical references to constants
-
- [System]Verilog does not allow hierarchical identifiers as constant
- primaries. However, the resolution of type information across scopes can
- create such hierarchical references. This conversion performs substitution
- for any hierarchical references to parameters or localparams, regardless of
- whether or not they occur within what should be a constant expression.
-
- If an identifier refers to a parameter which has been shadowed locally, the
- conversion creates a localparam alias of the parameter at the top level scope
- and refers to the parameter using that alias instead.
-
- TODO: Support resolution of hierarchical references to constant functions
- TODO: Some other conversions still blindly substitute type information
-}
module Convert.HierConst (convert) where
import Data.Either (fromLeft)
import qualified Data.Map.Strict as Map
import Convert.Scoper
import Convert.Traverse
import Language.SystemVerilog.AST
convert :: [AST] -> [AST]
convert = map $ traverseDescriptions convertDescription
convertDescription :: Description -> Description
convertDescription (Part attrs extern kw lifetime name ports items) =
Part attrs extern kw lifetime name ports $
if null shadowedParams
then items'
else map expand items'
where
(items', mapping) = runScoper traverseDeclM
(traverseExprsM traverseExprM)
(traverseGenItemExprsM traverseExprM)
(traverseStmtExprsM traverseExprM)
name items
shadowedParams = Map.keys $ Map.filter (fromLeft False) $
extractMapping mapping
expand = traverseNestedModuleItems $ expandParam shadowedParams
convertDescription description = description
expandParam :: [Identifier] -> ModuleItem -> ModuleItem
expandParam shadowed (MIPackageItem (Decl (param @ (Param Parameter _ x _)))) =
if elem x shadowed
then Generate $ map (GenModuleItem . wrap) [param, extra]
else wrap param
where
wrap = MIPackageItem . Decl
extra = Param Localparam UnknownType (prefix x) (Ident x)
expandParam _ item = item
prefix :: Identifier -> Identifier
prefix = (++) "_sv2v_disambiguate_"
type ST = Scoper (Either Bool Expr)
traverseDeclM :: Decl -> ST Decl
traverseDeclM decl = do
case decl of
Param Parameter _ x _ ->
insertElem x (Left False)
Param Localparam UnknownType x e ->
scopeExpr e >>= insertElem x . Right
Param Localparam (Implicit sg rs) x e ->
scopeExpr (Cast (Left t) e) >>= insertElem x . Right
where t = IntegerVector TLogic sg rs
Param Localparam t x e ->
scopeExpr (Cast (Left t) e) >>= insertElem x . Right
_ -> return ()
traverseDeclExprsM traverseExprM decl
-- substitute hierarchical references to constants
traverseExprM :: Expr -> ST Expr
traverseExprM (expr @ (Dot _ x)) = do
expr' <- traverseSinglyNestedExprsM traverseExprM expr
detailsE <- lookupElemM expr'
detailsX <- lookupElemM x
case (detailsE, detailsX) of
(Just ([_, _], _, Left{}), Just ([_, _], _, Left{})) ->
return $ Ident x
(Just (accesses @ [Access _ Nil, _], _, Left False), _) -> do
insertElem accesses (Left True)
return $ Ident $ prefix x
(Just ([Access _ Nil, _], _, Left True), _) ->
return $ Ident $ prefix x
(Just (aE, replacements, Right value), Just (aX, _, _)) ->
if aE == aX && Map.null replacements
then return $ Ident x
else traverseSinglyNestedExprsM traverseExprM $
replaceInExpr replacements value
(Just (_, replacements, Right value), Nothing) ->
traverseSinglyNestedExprsM traverseExprM $
replaceInExpr replacements value
_ -> traverseSinglyNestedExprsM traverseExprM expr
traverseExprM expr = traverseSinglyNestedExprsM traverseExprM expr