HierConst.hs 4.31 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
{- 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

22
import Control.Monad (when)
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
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
40 41 42
        (items', mapping) = runScoper $ scopeModuleItems scoper name items
        scoper = scopeModuleItem
            traverseDeclM
43 44 45 46 47 48 49 50 51
            (traverseExprsM traverseExprM)
            (traverseGenItemExprsM traverseExprM)
            (traverseStmtExprsM traverseExprM)
        shadowedParams = Map.keys $ Map.filter (fromLeft False) $
            extractMapping mapping
        expand = traverseNestedModuleItems $ expandParam shadowedParams
convertDescription description = description

expandParam :: [Identifier] -> ModuleItem -> ModuleItem
52
expandParam shadowed (MIPackageItem (Decl param@(Param Parameter _ x _))) =
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    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
75 76 77 78
            where t = IntegerVector TBit sg rs
        Param Localparam (IntegerVector _ sg rs) x e ->
            scopeExpr (Cast (Left t) e) >>= insertElem x . Right
            where t = IntegerVector TBit sg rs
79 80 81 82 83 84 85
        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
86
traverseExprM expr@(Dot _ x) = do
87 88 89 90 91 92
    expr' <- traverseSinglyNestedExprsM traverseExprM expr
    detailsE <- lookupElemM expr'
    detailsX <- lookupElemM x
    case (detailsE, detailsX) of
        (Just ([_, _], _, Left{}), Just ([_, _], _, Left{})) ->
            return $ Ident x
93
        (Just (accesses@[Access _ Nil, _], _, Left False), _) -> do
94 95 96
            details <- lookupElemM $ prefix x
            when (details == Nothing) $
                insertElem accesses (Left True)
97 98 99 100 101 102 103 104 105 106 107 108 109
            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