sv2v/src/Convert/Enum.hs

108 lines
3.6 KiB
Haskell

{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for `enum`
-
- This conversion replaces references to enum items with their values. The
- values are explicitly cast to the enum's base type.
-
- 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
- unspecified values take on the value of the previous item, plus 1.
-
- 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.
-}
module Convert.Enum (convert) where
import Control.Monad (zipWithM_, (>=>))
import Data.List (elemIndices)
import Convert.ExprUtils
import Convert.Scoper
import Convert.Traverse
import Language.SystemVerilog.AST
type SC = Scoper Expr
convert :: [AST] -> [AST]
convert = map $ traverseDescriptions $ partScoper
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
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
traverseModuleItemM :: ModuleItem -> SC ModuleItem
traverseModuleItemM (Genvar x) =
insertElem x Nil >> return (Genvar x)
traverseModuleItemM item =
traverseNodesM traverseExprM return traverseTypeM traverseLHSM return item
where traverseLHSM = traverseNestedLHSsM $ 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
-- 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
where
-- default to a 32 bit logic
t' = IntegerVector TLogic sg rl'
rl' = if null rl
then [(RawNum 31, RawNum 0)]
else rl
replaceEnum (Enum t v rs) =
insertEnumItems t v >> return (tf $ rl ++ rs)
where (tf, rl) = typeRanges t
replaceEnum other = return other
insertEnumItems :: Type -> [(Identifier, Expr)] -> SC ()
insertEnumItems itemType items =
-- check for obviously duplicate values
if noDuplicates
then zipWithM_ insertEnumItem keys vals
else scopedErrorM $ "enum conversion has duplicate vals: "
++ show (zip keys vals)
where
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
noDuplicates = all (null . tail . flip elemIndices vals) vals
step :: Expr -> Expr -> Expr
step expr Nil = simplify $ BinOp Add expr (RawNum 1)
step _ expr = expr