mirror of https://github.com/zachjs/sv2v.git
108 lines
3.6 KiB
Haskell
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
|