Wildcard.hs 3.54 KB
Newer Older
1 2 3 4 5 6
{- sv2v
 - Author: Zachary Snow <zach@zachjs.com>
 -
 - Conversion for `==?` and `!=?`
 -
 - `a ==? b` is defined as the bitwise comparison of `a` and `b`, where X and Z
7 8 9 10 11 12 13 14 15
 - values in `b` (but not those in `a`) are used as wildcards. This conversion
 - relies on the fact that works because any value xor'ed with X or Z becomes X.
 -
 - Procedure for `A ==? B`:
 - 1. If there is any bit in A that doesn't match a non-wildcarded bit in B,
 -    then the result is always `1'b0`.
 - 2. If there is any X or Z in A that is not wildcarded in B, then the result
 -    is `1'bx`.
 - 3. Otherwise, the result is `1'b1`.
16 17
 -
 - `!=?` is simply converted as the logical negation of `==?`, which is
18 19 20 21 22 23
 -
 - The conversion for `inside` produces wildcard equality comparisons as per the
 - SystemVerilog specification. However, many usages of `inside` don't depend on
 - the wildcard behavior. To avoid generating needlessly complex output, this
 - conversion use the standard equality operator if the pattern obviously
 - contains no wildcard bits.
24 25 26 27
 -}

module Convert.Wildcard (convert) where

28
import Control.Monad (when)
29
import Data.Bits ((.|.))
30

31
import Convert.Scoper
32 33 34 35
import Convert.Traverse
import Language.SystemVerilog.AST

convert :: [AST] -> [AST]
36 37 38 39
convert = map $ traverseDescriptions convertDescription

convertDescription :: Description -> Description
convertDescription =
40
    partScoper traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
41

42
traverseDeclM :: Decl -> Scoper Number Decl
43 44
traverseDeclM decl = do
    case decl of
45
        Param Localparam _ x (Number n) -> insertElem x n
46 47
        Param Parameter  _ x (Number n) ->
            when (numberToInteger n /= Nothing) $ insertElem x n
48 49 50 51 52 53
        _ -> return ()
    let mi = MIPackageItem $ Decl decl
    mi' <- traverseModuleItemM mi
    let MIPackageItem (Decl decl') = mi'
    return decl'

54
traverseModuleItemM :: ModuleItem -> Scoper Number ModuleItem
55 56
traverseModuleItemM = traverseExprsM traverseExprM

57 58 59 60
traverseGenItemM :: GenItem -> Scoper Number GenItem
traverseGenItemM = traverseGenItemExprsM traverseExprM

traverseStmtM :: Stmt -> Scoper Number Stmt
61 62
traverseStmtM = traverseStmtExprsM traverseExprM

63 64
traverseExprM :: Expr -> Scoper Number Expr
traverseExprM = traverseNestedExprsM $ embedScopes convertExpr
65

66 67 68
lookupPattern :: Scopes Number -> Expr -> Maybe Number
lookupPattern _ (Number n) = Just n
lookupPattern scopes e =
69
    case lookupElem scopes e of
70 71
        Nothing -> Nothing
        Just (_, _, n) -> Just n
72

73 74 75 76 77 78 79 80 81 82
convertExpr :: Scopes Number -> Expr -> Expr
convertExpr scopes (BinOp WEq l r) =
    if maybePattern == Nothing then
        BinOp BitAnd couldMatch $
        BinOp BitOr  noExtraXZs $
        Number (Based 1 False Binary 0 1)
    else if numberToInteger pattern /= Nothing then
        BinOp Eq l r
    else
        BinOp Eq (BinOp BitOr l mask) pattern'
83 84 85 86
    where
        lxl = BinOp BitXor l l
        rxr = BinOp BitXor r r
        -- Step #1: definitive mismatch
87
        couldMatch = BinOp TEq rxlxl lxrxr
88 89 90
        rxlxl = BinOp BitXor r lxl
        lxrxr = BinOp BitXor l rxr
        -- Step #2: extra X or Z
91
        noExtraXZs = BinOp TEq lxlxrxr rxr
92
        lxlxrxr = BinOp BitXor lxl rxr
93 94 95 96 97 98 99
        -- For wildcard patterns we can find, use masking
        maybePattern = lookupPattern scopes r
        Just pattern = maybePattern
        Based size signed base vals knds = pattern
        mask = Number $ Based size signed base knds 0
        pattern' = Number $ Based size signed base (vals .|. knds) 0
convertExpr scopes (BinOp WNe l r) =
100
    UniOp LogNot $
101
    convertExpr scopes $
102
    BinOp WEq l r
103
convertExpr _ other = other