Enum.hs 3.58 KB
Newer Older
1 2 3 4 5
{- sv2v
 - Author: Zachary Snow <zach@zachjs.com>
 -
 - Conversion for `enum`
 -
6 7
 - This conversion replaces references to enum items with their values. The
 - values are explicitly cast to the enum's base type.
8 9 10
 -
 - SystemVerilog allows for enums to have any number of the items' values
 - specified or unspecified. If the first one is unspecified, it is 0. All other
11
 - unspecified values take on the value of the previous item, plus 1.
12 13 14 15
 -
 - It is an error for multiple items of the same enum to take on the same value,
 - whether implicitly or explicitly. We catch try to catch "obvious" instances
 - of conflicts.
16 17 18 19
 -}

module Convert.Enum (convert) where

20
import Control.Monad (zipWithM_, (>=>))
21
import Data.List (elemIndices)
22

23
import Convert.ExprUtils
24
import Convert.Scoper
25 26 27
import Convert.Traverse
import Language.SystemVerilog.AST

28
type SC = Scoper Expr
29

30
convert :: [AST] -> [AST]
31 32
convert = map $ traverseDescriptions $ partScoper
    traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
33

34 35 36 37 38 39 40 41 42 43
traverseDeclM :: Decl -> SC Decl
traverseDeclM decl = do
    case decl of
        Variable _ _ x _ _ -> insertElem x Nil
        Net  _ _ _ _ x _ _ -> insertElem x Nil
        Param    _ _ x   _ -> insertElem x Nil
        ParamType  _ x   _ -> insertElem x Nil
        CommentDecl{} -> return ()
    traverseDeclTypesM traverseTypeM decl >>=
        traverseDeclExprsM traverseExprM
44

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
traverseModuleItemM :: ModuleItem -> SC ModuleItem
traverseModuleItemM (Genvar x) =
    insertElem x Nil >> return (Genvar x)
traverseModuleItemM item =
    traverseNodesM traverseExprM return traverseTypeM traverseLHSM return item
    where traverseLHSM = traverseLHSExprsM traverseExprM

traverseGenItemM :: GenItem -> SC GenItem
traverseGenItemM = traverseGenItemExprsM traverseExprM

traverseStmtM :: Stmt -> SC Stmt
traverseStmtM = traverseStmtExprsM traverseExprM

traverseTypeM :: Type -> SC Type
traverseTypeM =
    traverseSinglyNestedTypesM traverseTypeM >=>
    traverseTypeExprsM traverseExprM >=>
    replaceEnum

traverseExprM :: Expr -> SC Expr
traverseExprM (Ident x) = do
    details <- lookupElemM x
    return $ case details of
        Just (_, _, Nil) -> Ident x
        Just (_, _, e) -> e
        Nothing -> Ident x
traverseExprM expr =
    traverseSinglyNestedExprsM traverseExprM expr
        >>= traverseExprTypesM traverseTypeM
74

75 76 77 78 79 80
-- replace enum types and insert enum items
replaceEnum :: Type -> SC Type
replaceEnum t@(Enum Alias{} v _) = -- not ready
    mapM_ (flip insertElem Nil . fst) v >> return t
replaceEnum (Enum (Implicit sg rl) v rs) =
    replaceEnum $ Enum t' v rs
81 82 83 84
    where
        -- default to a 32 bit logic
        t' = IntegerVector TLogic sg rl'
        rl' = if null rl
85
            then [(RawNum 31, RawNum 0)]
86
            else rl
87 88 89 90
replaceEnum (Enum t v rs) =
    insertEnumItems t v >> return (tf $ rl ++ rs)
    where (tf, rl) = typeRanges t
replaceEnum other = return other
91

92 93
insertEnumItems :: Type -> [(Identifier, Expr)] -> SC ()
insertEnumItems itemType items =
94 95
    -- check for obviously duplicate values
    if noDuplicates
96
        then zipWithM_ insertEnumItem keys vals
97 98
        else error $ "enum conversion has duplicate vals: "
                ++ show (zip keys vals)
99
    where
100 101 102 103
        insertEnumItem :: Identifier -> Expr -> SC ()
        insertEnumItem x = scopeExpr . Cast (Left itemType) >=> insertElem x
        (keys, valsRaw) = unzip items
        vals = tail $ scanl step (UniOp UniSub $ RawNum 1) valsRaw
104
        noDuplicates = all (null . tail . flip elemIndices vals) vals
Zachary Snow committed
105
        step :: Expr -> Expr -> Expr
106
        step expr Nil = simplify $ BinOp Add expr (RawNum 1)
Zachary Snow committed
107
        step _ expr = expr