{- sv2v - Author: Zachary Snow <zach@zachjs.com> - - Conversion for `inside` expressions and cases - - The expressions are compared to each candidate using `==?`, the wildcard - comparison. As required by the specification, the result of each comparison - is combined using an OR reduction. - - `case ... inside` statements are converted to an equivalent if-else cascade. - - TODO: Add support for array value ranges. - TODO: This conversion may cause an expression with side effects to be - evaluated more than once. -} module Convert.Inside (convert) where import Convert.Traverse import Language.SystemVerilog.AST import Data.Maybe (fromMaybe) convert :: [AST] -> [AST] convert = map $ traverseDescriptions $ traverseModuleItems convertModuleItem convertModuleItem :: ModuleItem -> ModuleItem convertModuleItem item = traverseExprs (traverseNestedExprs convertExpr) $ traverseStmts convertStmt $ item convertExpr :: Expr -> Expr convertExpr (Inside Nil valueRanges) = Inside Nil valueRanges convertExpr (Inside expr valueRanges) = if length checks == 1 then head checks else UniOp RedOr $ Concat checks where checks = map toCheck valueRanges toCheck :: ExprOrRange -> Expr toCheck (Left pattern) = BinOp WEq expr pattern toCheck (Right (lo, hi)) = BinOp LogAnd (BinOp Le lo expr) (BinOp Ge hi expr) convertExpr other = other convertStmt :: Stmt -> Stmt convertStmt (Case u kw expr items) = if not $ any isSpecialInside exprs then Case u kw expr items else if kw /= CaseN then error $ "cannot use inside with " ++ show kw else foldr ($) defaultStmt $ map (uncurry $ If NoCheck) $ zip comps stmts where exprs = map fst items itemsNonDefault = filter (not . null . fst) items isSpecialInside :: [Expr] -> Bool isSpecialInside [Inside Nil _] = True isSpecialInside _ = False makeComp :: [Expr] -> Expr makeComp [Inside Nil ovr] = Inside expr ovr makeComp _ = error "internal invariant violated" comps = map (makeComp . fst) itemsNonDefault stmts = map snd itemsNonDefault defaultStmt = fromMaybe Null (lookup [] items) convertStmt other = other