From d88c516d33c7aef93e3f6b594596adc513329c07 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sun, 12 Jul 2020 15:06:27 -0600 Subject: [PATCH] enhanced handling of number literals - number literals are parsed rather than stored as strings - fix array query functions used on non-trivial number literals - more efficient expression simplification recursion - expanded constant folding scenarios --- src/Convert/DimensionQuery.hs | 50 ++- src/Convert/EmptyArgs.hs | 2 +- src/Convert/Enum.hs | 9 +- src/Convert/ExprUtils.hs | 199 ++++++++++++ src/Convert/ForDecl.hs | 2 +- src/Convert/Foreach.hs | 6 +- src/Convert/Jump.hs | 13 +- src/Convert/Logic.hs | 4 +- src/Convert/MultiplePacked.hs | 11 +- src/Convert/ParamType.hs | 5 +- src/Convert/Simplify.hs | 57 ++-- src/Convert/SizeCast.hs | 50 +-- src/Convert/Stream.hs | 13 +- src/Convert/Struct.hs | 27 +- src/Convert/Traverse.hs | 42 ++- src/Convert/TypeOf.hs | 29 +- src/Convert/UnbasedUnsized.hs | 32 +- src/Convert/Wildcard.hs | 9 +- src/Language/SystemVerilog/AST.hs | 2 + src/Language/SystemVerilog/AST/Expr.hs | 188 +---------- src/Language/SystemVerilog/AST/Number.hs | 298 ++++++++++++++++++ src/Language/SystemVerilog/AST/Type.hs | 8 +- src/Language/SystemVerilog/Parser/Lex.x | 6 +- src/Language/SystemVerilog/Parser/Parse.y | 39 ++- .../SystemVerilog/Parser/ParseDecl.hs | 8 +- src/Language/SystemVerilog/Parser/Tokens.hs | 1 + sv2v.cabal | 2 + test/basic/dimensions.sv | 8 + test/basic/dimensions.v | 8 + test/basic/div.sv | 8 + test/basic/div.v | 1 + test/lex/number.sv | 41 +++ test/lex/number.v | 1 + 33 files changed, 813 insertions(+), 366 deletions(-) create mode 100644 src/Convert/ExprUtils.hs create mode 100644 src/Language/SystemVerilog/AST/Number.hs create mode 100644 test/basic/div.sv create mode 100644 test/basic/div.v create mode 100644 test/lex/number.sv create mode 100644 test/lex/number.v diff --git a/src/Convert/DimensionQuery.hs b/src/Convert/DimensionQuery.hs index f81aee4..885d367 100644 --- a/src/Convert/DimensionQuery.hs +++ b/src/Convert/DimensionQuery.hs @@ -19,8 +19,7 @@ module Convert.DimensionQuery (convert) where -import Data.List (elemIndex) - +import Convert.ExprUtils import Convert.Traverse import Language.SystemVerilog.AST @@ -37,9 +36,9 @@ elaborateType (IntegerAtom t sg) = IntegerVector TLogic sg [(hi, lo)] where size = atomSize t - hi = Number $ show (size - 1) - lo = Number "0" - atomSize :: IntegerAtomType -> Int + hi = RawNum $ size - 1 + lo = RawNum 0 + atomSize :: IntegerAtomType -> Integer atomSize TByte = 8 atomSize TShortint = 16 atomSize TInt = 32 @@ -59,32 +58,32 @@ convertExpr (DimFn fn (Right e) d) = DimFn fn (Left $ TypeOf e) d convertExpr (orig @ (DimsFn FnUnpackedDimensions (Left t))) = case t of - UnpackedType _ rs -> Number $ show $ length rs + UnpackedType _ rs -> RawNum $ fromIntegral $ length rs TypeOf{} -> orig - _ -> Number "0" + _ -> RawNum 0 convertExpr (orig @ (DimsFn FnDimensions (Left t))) = case t of - IntegerAtom{} -> Number "1" + IntegerAtom{} -> RawNum 1 Alias{} -> orig PSAlias{} -> orig CSAlias{} -> orig TypeOf{} -> orig UnpackedType t' rs -> BinOp Add - (Number $ show $ length rs) + (RawNum $ fromIntegral $ length rs) (DimsFn FnDimensions $ Left t') - _ -> Number $ show $ length $ snd $ typeRanges t + _ -> RawNum $ fromIntegral $ length $ snd $ typeRanges t -- conversion for array dimension functions on types -convertExpr (DimFn f (Left t) (Number str)) = - if dm == Nothing || isUnresolved t then - DimFn f (Left t) (Number str) - else if d <= 0 || fromIntegral d > length rs then - Number "'x" +convertExpr (DimFn f (Left t) (Number n)) = + if isUnresolved t then + DimFn f (Left t) (Number n) + else if d <= 0 || d > length rs then + Number $ UnbasedUnsized 'x' else case f of FnLeft -> fst r FnRight -> snd r - FnIncrement -> endianCondExpr r (Number "1") (UniOp UniSub $ Number "1") + FnIncrement -> endianCondExpr r (RawNum 1) (UniOp UniSub $ RawNum 1) FnLow -> endianCondExpr r (snd r) (fst r) FnHigh -> endianCondExpr r (fst r) (snd r) FnSize -> rangeSize r @@ -93,9 +92,10 @@ convertExpr (DimFn f (Left t) (Number str)) = UnpackedType tInner rsOuter -> rsOuter ++ (snd $ typeRanges $ elaborateType tInner) _ -> snd $ typeRanges $ elaborateType t - dm = readNumber str - Just d = dm - r = rs !! (fromIntegral $ d - 1) + d = case numberToInteger n of + Just value -> fromIntegral value + Nothing -> 0 + r = rs !! (d - 1) isUnresolved :: Type -> Bool isUnresolved Alias{} = True isUnresolved PSAlias{} = True @@ -117,7 +117,7 @@ convertBits (Left t) = Struct _ fields rs -> BinOp Mul (dimensionsSize rs) - (foldl (BinOp Add) (Number "0") fieldSizes) + (foldl (BinOp Add) (RawNum 0) fieldSizes) where fieldSizes = map (DimsFn FnBits . Left . fst) fields UnpackedType t' rs -> BinOp Mul @@ -127,17 +127,13 @@ convertBits (Left t) = convertBits (Right e) = case e of Concat exprs -> - foldl (BinOp Add) (Number "0") $ + foldl (BinOp Add) (RawNum 0) $ map (convertBits . Right) $ exprs Stream _ _ exprs -> convertBits $ Right $ Concat exprs - Number n -> - case elemIndex '\'' n of - Nothing -> Number "32" - Just 0 -> Number "32" - Just idx -> Number $ take idx n + Number n -> RawNum $ numberBitLength n Range expr mode range -> - BinOp Mul size $ convertBits $ Right $ Bit expr (Number "0") + BinOp Mul size $ convertBits $ Right $ Bit expr (RawNum 0) where size = case mode of NonIndexed -> rangeSize range diff --git a/src/Convert/EmptyArgs.hs b/src/Convert/EmptyArgs.hs index fc18b71..8166085 100644 --- a/src/Convert/EmptyArgs.hs +++ b/src/Convert/EmptyArgs.hs @@ -49,6 +49,6 @@ convertExpr :: Idents -> Expr -> Expr convertExpr functions (Call (Ident func) (Args [] [])) = Call (Ident func) (Args args []) where args = if Set.member func functions - then [Number "0"] + then [RawNum 0] else [] convertExpr _ other = other diff --git a/src/Convert/Enum.hs b/src/Convert/Enum.hs index f893ba9..5719b19 100644 --- a/src/Convert/Enum.hs +++ b/src/Convert/Enum.hs @@ -23,6 +23,7 @@ import Control.Monad.Writer import Data.List (elemIndices) import qualified Data.Set as Set +import Convert.ExprUtils import Convert.Traverse import Language.SystemVerilog.AST @@ -72,12 +73,12 @@ traverseType (Enum (Implicit sg rl) v rs) = -- default to a 32 bit logic t' = IntegerVector TLogic sg rl' rl' = if null rl - then [(Number "31", Number "0")] + then [(RawNum 31, RawNum 0)] else rl traverseType (Enum t v rs) = do let (tf, rl) = typeRanges t rlParam <- case rl of - [ ] -> return [(Number "0", Number "0")] + [ ] -> return [(RawNum 0, RawNum 0)] [_] -> return rl _ -> error $ "unexpected multi-dim enum type: " ++ show (Enum t v rs) tell $ Set.singleton (tf rlParam, v) -- type of localparams @@ -93,10 +94,10 @@ makeEnumItems (itemType, l) = ++ show (zip keys vals) where keys = map fst l - vals = tail $ scanl step (UniOp UniSub $ Number "1") (map snd l) + vals = tail $ scanl step (UniOp UniSub $ RawNum 1) (map snd l) noDuplicates = all (null . tail . flip elemIndices vals) vals step :: Expr -> Expr -> Expr - step expr Nil = simplify $ BinOp Add expr (Number "1") + step expr Nil = simplify $ BinOp Add expr (RawNum 1) step _ expr = expr toPackageItem :: Identifier -> Expr -> PackageItem toPackageItem x v = diff --git a/src/Convert/ExprUtils.hs b/src/Convert/ExprUtils.hs new file mode 100644 index 0000000..50ed802 --- /dev/null +++ b/src/Convert/ExprUtils.hs @@ -0,0 +1,199 @@ +{-# LANGUAGE PatternSynonyms #-} +{- sv2v + - Author: Zachary Snow + - + - Utilities for expressions and ranges + -} + +module Convert.ExprUtils + ( simplify + , simplifyStep + , rangeSize + , rangeSizeHiLo + , endianCondExpr + , endianCondRange + , dimensionsSize + ) where + +import Data.Bits (shiftL, shiftR) + +import Convert.Traverse +import Language.SystemVerilog.AST + +simplify :: Expr -> Expr +simplify = simplifyStep . traverseSinglyNestedExprs simplify . simplifyStep + +simplifyStep :: Expr -> Expr + +simplifyStep (UniOp LogNot (Number n)) = + case numberToInteger n of + Just 0 -> bool True + Just _ -> bool False + Nothing -> UniOp LogNot $ Number n +simplifyStep (UniOp LogNot (BinOp Eq a b)) = BinOp Ne a b +simplifyStep (UniOp LogNot (BinOp Ne a b)) = BinOp Eq a b + +simplifyStep (UniOp UniSub (UniOp UniSub e)) = e +simplifyStep (UniOp UniSub (BinOp Sub e1 e2)) = BinOp Sub e2 e1 + +simplifyStep (Concat [e]) = e +simplifyStep (Concat es) = Concat $ filter (/= Concat []) es +simplifyStep (Repeat (Dec 0) _) = Concat [] +simplifyStep (Repeat (Dec 1) es) = Concat es +simplifyStep (Mux (Number n) e1 e2) = + case numberToInteger n of + Just 0 -> e2 + Just _ -> e1 + Nothing -> Mux (Number n) e1 e2 + +simplifyStep (Call (Ident "$clog2") (Args [Dec k] [])) = + toDec $ clog2 k + where + clog2Help :: Integer -> Integer -> Integer + clog2Help p n = if p >= n then 0 else 1 + clog2Help (p*2) n + clog2 :: Integer -> Integer + clog2 n = if n < 2 then 0 else clog2Help 1 n + +simplifyStep (BinOp op e1 e2) = simplifyBinOp op e1 e2 +simplifyStep other = other + + +simplifyBinOp :: BinOp -> Expr -> Expr -> Expr + +simplifyBinOp Add (Dec 0) e = e +simplifyBinOp Add e (Dec 0) = e +simplifyBinOp Sub e (Dec 0) = e +simplifyBinOp Sub (Dec 0) e = UniOp UniSub e +simplifyBinOp Mul (Dec 0) _ = toDec 0 +simplifyBinOp Mul (Dec 1) e = e +simplifyBinOp Mul _ (Dec 0) = toDec 0 +simplifyBinOp Mul e (Dec 1) = e + +simplifyBinOp Add e1 (UniOp UniSub e2) = BinOp Sub e1 e2 +simplifyBinOp Add (UniOp UniSub e1) e2 = BinOp Sub e2 e1 +simplifyBinOp Sub e1 (UniOp UniSub e2) = BinOp Add e1 e2 +simplifyBinOp Sub (UniOp UniSub e1) e2 = UniOp UniSub $ BinOp Add e1 e2 + +simplifyBinOp Sub (n1 @ Number{}) (BinOp Sub (n2 @ Number{}) e) = + BinOp Add (BinOp Sub n1 n2) e +simplifyBinOp Sub (n1 @ Number{}) (BinOp Sub e (n2 @ Number{})) = + BinOp Sub (BinOp Add n1 n2) e +simplifyBinOp Sub (BinOp Add e (n1 @ Number{})) (n2 @ Number{}) = + BinOp Add e (BinOp Sub n1 n2) +simplifyBinOp Add (n1 @ Number{}) (BinOp Add (n2 @ Number{}) e) = + BinOp Add (BinOp Add n1 n2) e +simplifyBinOp Add (n1 @ Number{}) (BinOp Sub e (n2 @ Number{})) = + BinOp Add e (BinOp Sub n1 n2) +simplifyBinOp Sub (BinOp Sub e (n1 @ Number{})) (n2 @ Number{}) = + BinOp Sub e (BinOp Add n1 n2) +simplifyBinOp Add (BinOp Sub e (n1 @ Number{})) (n2 @ Number{}) = + BinOp Sub e (BinOp Sub n1 n2) +simplifyBinOp Add (BinOp Sub (n1 @ Number{}) e) (n2 @ Number{}) = + BinOp Sub (BinOp Add n1 n2) e +simplifyBinOp Ge (BinOp Sub e (Dec 1)) (Dec 0) = BinOp Ge e (toDec 1) + +simplifyBinOp ShiftAL (Dec x) (Dec y) = toDec $ shiftL x (fromIntegral y) +simplifyBinOp ShiftAR (Dec x) (Dec y) = toDec $ shiftR x (fromIntegral y) +simplifyBinOp ShiftL (Dec x) (Dec y) = toDec $ shiftL x (fromIntegral y) +simplifyBinOp ShiftR (Dec x) (Dec y) = toDec $ shiftR x (fromIntegral y) + +simplifyBinOp op e1 e2 = + case (e1, e2) of + (Dec x, Dec y) -> constantFold orig op x y + (SizDec x, Dec y) -> constantFold orig op x y + (Dec x, SizDec y) -> constantFold orig op x y + (Bas x, Dec y) -> constantFold orig op x y + (Dec x, Bas y) -> constantFold orig op x y + (Bas x, Bas y) -> constantFold orig op x y + (NegDec x, Dec y) -> constantFold orig op (-x) y + (Dec x, NegDec y) -> constantFold orig op x (-y) + (NegDec x, NegDec y) -> constantFold orig op (-x) (-y) + _ -> orig + where orig = BinOp op e1 e2 + + +-- attempt to constant fold a binary operation on integers +constantFold :: Expr -> BinOp -> Integer -> Integer -> Expr +constantFold _ Add x y = toDec (x + y) +constantFold _ Sub x y = toDec (x - y) +constantFold _ Mul x y = toDec (x * y) +constantFold _ Div _ 0 = Number $ Based (-32) True Hex 0 bits + where bits = 2 ^ (32 :: Integer) - 1 +constantFold _ Div x y = toDec (x `quot` y) +constantFold _ Mod x y = toDec (x `rem` y) +constantFold _ Pow x y = toDec (x ^ y) +constantFold _ Eq x y = bool $ x == y +constantFold _ Ne x y = bool $ x /= y +constantFold _ Gt x y = bool $ x > y +constantFold _ Ge x y = bool $ x >= y +constantFold _ Lt x y = bool $ x < y +constantFold _ Le x y = bool $ x <= y +constantFold fallback _ _ _ = fallback + + +bool :: Bool -> Expr +bool True = Number $ Decimal 1 False 1 +bool False = Number $ Decimal 1 False 0 + +toDec :: Integer -> Expr +toDec n = + if n < 0 then + UniOp UniSub $ toDec (-n) + else if n >= 4294967296 `div` 2 then + let size = fromIntegral $ bits $ n * 2 + in Number $ Decimal (negate size) True n + else + RawNum n + where + bits :: Integer -> Integer + bits 0 = 0 + bits v = 1 + bits (quot v 2) + +pattern Dec :: Integer -> Expr +pattern Dec n <- Number (Decimal (-32) _ n) + +pattern SizDec :: Integer -> Expr +pattern SizDec n <- Number (Decimal 32 _ n) + +pattern NegDec :: Integer -> Expr +pattern NegDec n <- UniOp UniSub (Dec n) + +pattern Bas :: Integer -> Expr +pattern Bas n <- Number (Based _ _ _ n 0) + + +-- returns the size of a range +rangeSize :: Range -> Expr +rangeSize (s, e) = + endianCondExpr (s, e) a b + where + a = rangeSizeHiLo (s, e) + b = rangeSizeHiLo (e, s) + +-- returns the size of a range known to be ordered +rangeSizeHiLo :: Range -> Expr +rangeSizeHiLo (hi, lo) = + simplify $ BinOp Add (BinOp Sub hi lo) (RawNum 1) + +-- chooses one or the other expression based on the endianness of the given +-- range; [hi:lo] chooses the first expression +endianCondExpr :: Range -> Expr -> Expr -> Expr +endianCondExpr r e1 e2 = simplify $ Mux (uncurry (BinOp Ge) r) e1 e2 + +-- chooses one or the other range based on the endianness of the given range, +-- but in such a way that the result is itself also usable as a range even if +-- the endianness cannot be resolved during conversion, i.e. if it's dependent +-- on a parameter value; [hi:lo] chooses the first range +endianCondRange :: Range -> Range -> Range -> Range +endianCondRange r r1 r2 = + ( endianCondExpr r (fst r1) (fst r2) + , endianCondExpr r (snd r1) (snd r2) + ) + +-- returns the total size of a set of dimensions +dimensionsSize :: [Range] -> Expr +dimensionsSize ranges = + simplify $ + foldl (BinOp Mul) (RawNum 1) $ + map rangeSize $ + ranges diff --git a/src/Convert/ForDecl.hs b/src/Convert/ForDecl.hs index df7c563..8a37316 100644 --- a/src/Convert/ForDecl.hs +++ b/src/Convert/ForDecl.hs @@ -23,7 +23,7 @@ convertStmt (For (Left []) cc asgns stmt) = convertStmt $ For (Right []) cc asgns stmt convertStmt (For (Right []) cc asgns stmt) = convertStmt $ For inits cc asgns stmt - where inits = Left [dummyDecl $ Number "0"] + where inits = Left [dummyDecl $ RawNum 0] convertStmt (orig @ (For (Right [_]) _ _ _)) = orig convertStmt (For (Left inits) cc asgns stmt) = diff --git a/src/Convert/Foreach.hs b/src/Convert/Foreach.hs index c261b3c..646f22d 100644 --- a/src/Convert/Foreach.hs +++ b/src/Convert/Foreach.hs @@ -22,16 +22,16 @@ convertStmt :: Stmt -> Stmt convertStmt (Foreach x idxs stmt) = (foldl (.) id $ map toLoop $ zip [1..] idxs) stmt where - toLoop :: (Int, Identifier) -> (Stmt -> Stmt) + toLoop :: (Integer, Identifier) -> (Stmt -> Stmt) toLoop (_, "") = id toLoop (d, i) = For (Left [idxDecl]) cmp [incr] where - queryFn f = DimFn f (Right $ Ident x) (Number $ show d) + queryFn f = DimFn f (Right $ Ident x) (RawNum d) idxDecl = Variable Local (IntegerAtom TInteger Unspecified) i [] (queryFn FnLeft) cmp = - Mux (BinOp Eq (queryFn FnIncrement) (Number "1")) + Mux (BinOp Eq (queryFn FnIncrement) (RawNum 1)) (BinOp Ge (Ident i) (queryFn FnRight)) (BinOp Le (Ident i) (queryFn FnRight)) incr = (LHSIdent i, AsgnOp Sub, queryFn FnIncrement) diff --git a/src/Convert/Jump.hs b/src/Convert/Jump.hs index d76ebfa..1fbec2b 100644 --- a/src/Convert/Jump.hs +++ b/src/Convert/Jump.hs @@ -276,23 +276,26 @@ convertLoop loop comp stmt = do ] jumpStateType :: Type -jumpStateType = IntegerVector TBit Unspecified [(Number "0", Number "1")] +jumpStateType = IntegerVector TBit Unspecified [(RawNum 0, RawNum 1)] jumpState :: String jumpState = "_sv2v_jump" +jsVal :: Integer -> Expr +jsVal n = Number $ Based 2 False Binary n 0 + -- keep running the loop/function normally jsNone :: Expr -jsNone = Number "2'b00" +jsNone = jsVal 0 -- skip to the next iteration of the loop (continue) jsContinue :: Expr -jsContinue = Number "2'b01" +jsContinue = jsVal 1 -- stop running the loop immediately (break) jsBreak :: Expr -jsBreak = Number "2'b10" +jsBreak = jsVal 2 -- stop running the function immediately (return) jsReturn :: Expr -jsReturn = Number "2'b11" +jsReturn = jsVal 3 assertMsg :: Bool -> String -> State Info () diff --git a/src/Convert/Logic.hs b/src/Convert/Logic.hs index b082aef..f9d9a22 100644 --- a/src/Convert/Logic.hs +++ b/src/Convert/Logic.hs @@ -134,7 +134,7 @@ traverseModuleItem ports scopes = tmp = "sv2v_tmp_" ++ instanceName ++ "_" ++ portName tmpExpr = Ident tmp t = Net (NetType TWire) Unspecified - [(DimsFn FnBits $ Right expr, Number "1")] + [(DimsFn FnBits $ Right expr, RawNum 1)] items = [ MIPackageItem $ Decl $ Variable Local t tmp [] Nil , AlwaysC AlwaysComb $ Asgn AsgnOpEq Nothing lhs tmpExpr] @@ -182,7 +182,7 @@ rewriteDeclM (Variable d t x a e) = do return $ Variable d' t' x a e rewriteDeclM (Param s (IntegerVector _ sg []) x e) = return $ Param s (Implicit sg [(zero, zero)]) x e - where zero = Number "0" + where zero = RawNum 0 rewriteDeclM (Param s (IntegerVector _ sg rs) x e) = return $ Param s (Implicit sg rs) x e rewriteDeclM decl = return decl diff --git a/src/Convert/MultiplePacked.hs b/src/Convert/MultiplePacked.hs index 5ad1c4a..92f3cd0 100644 --- a/src/Convert/MultiplePacked.hs +++ b/src/Convert/MultiplePacked.hs @@ -26,6 +26,7 @@ module Convert.MultiplePacked (convert) where +import Convert.ExprUtils import Control.Monad ((>=>)) import Data.Tuple (swap) import Data.Maybe (isJust) @@ -110,7 +111,7 @@ combineRanges r1 r2 = r size2 = rangeSizeHiLo (s2, e2) lower = BinOp Add e2 (BinOp Mul e1 size2) upper = BinOp Add (BinOp Mul size1 size2) - (BinOp Sub lower (Number "1")) + (BinOp Sub lower (RawNum 1)) traverseStmtM :: Stmt -> Scoper TypeInfo Stmt traverseStmtM = @@ -254,7 +255,7 @@ convertExpr scopes = maybeDims = dims expr exprOuter = Bit expr idxInner baseDec = fst rangeOuter - baseInc = BinOp Sub (BinOp Add baseDec len) (Number "1") + baseInc = BinOp Sub (BinOp Add baseDec len) (RawNum 1) base = endianCondExpr rangeOuter baseDec baseInc len = rangeSize rangeOuter range = (base, len) @@ -277,7 +278,7 @@ convertExpr scopes = base = endianCondExpr dimOuter baseDec baseInc len = lenOuter range' = (base, len) - one = Number "1" + one = RawNum 1 rewriteExpr (orig @ (Range expr NonIndexed range)) = if isJust maybeDims && expr == rewriteExpr expr then rewriteExpr $ Range expr IndexedMinus range' @@ -285,7 +286,7 @@ convertExpr scopes = where maybeDims = dims expr baseDec = fst range - baseInc = BinOp Sub (BinOp Add baseDec len) (Number "1") + baseInc = BinOp Sub (BinOp Add baseDec len) (RawNum 1) base = endianCondExpr range baseDec baseInc len = rangeSize range range' = (base, len) @@ -299,7 +300,7 @@ convertExpr scopes = sizeOuter = rangeSize dimOuter offsetOuter = uncurry (endianCondExpr dimOuter) $ swap dimOuter (baseOrig, lenOrig) = range - lenOrigMinusOne = BinOp Sub lenOrig (Number "1") + lenOrigMinusOne = BinOp Sub lenOrig (RawNum 1) baseSwapped = orientIdx dimInner $ case mode of diff --git a/src/Convert/ParamType.hs b/src/Convert/ParamType.hs index af7b0cf..cf60dff 100644 --- a/src/Convert/ParamType.hs +++ b/src/Convert/ParamType.hs @@ -13,6 +13,7 @@ import Data.Maybe (isJust, isNothing, fromJust) import qualified Data.Map.Strict as Map import qualified Data.Set as Set +import Convert.ExprUtils import Convert.Traverse import Language.SystemVerilog.AST @@ -164,7 +165,7 @@ convert files = idents = Set.toList identSet toParam :: Identifier -> Decl toParam ident = - Param Parameter typ name (Number "0") + Param Parameter typ name (RawNum 0) where typ = Alias (addedParamTypeName paramName ident) [] name = addedParamName paramName ident @@ -225,7 +226,7 @@ exprToType (Bit e i) = Just t -> Just $ tf (rs ++ [r]) where (tf, rs) = typeRanges t - r = (simplify $ BinOp Sub i (Number "1"), Number "0") + r = (simplify $ BinOp Sub i (RawNum 1), RawNum 0) exprToType _ = Nothing -- checks where a type is sufficiently resolved to be substituted diff --git a/src/Convert/Simplify.hs b/src/Convert/Simplify.hs index 4ccf63b..6cfd73e 100644 --- a/src/Convert/Simplify.hs +++ b/src/Convert/Simplify.hs @@ -19,6 +19,7 @@ module Convert.Simplify (convert) where import Control.Monad.State import qualified Data.Map.Strict as Map +import Convert.ExprUtils import Convert.Traverse import Language.SystemVerilog.AST @@ -66,44 +67,56 @@ traverseStmtM :: Stmt -> State Info Stmt traverseStmtM stmt = traverseStmtExprsM traverseExprM stmt traverseExprM :: Expr -> State Info Expr -traverseExprM = traverseNestedExprsM $ stately convertExpr +traverseExprM = stately convertExpr substituteExprM :: Expr -> State Info Expr -substituteExprM = traverseNestedExprsM $ stately substitute +substituteExprM = stately substitute convertExpr :: Info -> Expr -> Expr convertExpr info (Cast (Right c) e) = - Cast (Right c') e + Cast (Right c') e' where - c' = simplify $ substitute info c + c' = convertExpr info $ substitute info c + e' = convertExpr info e convertExpr info (DimFn f v e) = DimFn f v e' - where - e' = simplify $ substitute info e + where e' = convertExpr info $ substitute info e convertExpr info (Call (Ident "$clog2") (Args [e] [])) = - if clog2' == clog2 - then clog2 - else clog2' + if val' == val + then val + else val' where - e' = simplify $ substitute info e - clog2 = Call (Ident "$clog2") (Args [e'] []) - clog2' = simplify clog2 + e' = convertExpr info $ substitute info e + val = Call (Ident "$clog2") (Args [e'] []) + val' = simplifyStep val convertExpr info (Mux cc aa bb) = if before == after - then simplify $ Mux cc aa bb - else simplify $ Mux after aa bb + then simplifyStep $ Mux cc' aa' bb' + else simplifyStep $ Mux after aa' bb' where - before = substitute info cc - after = simplify before -convertExpr _ (other @ Repeat{}) = traverseNestedExprs simplify other -convertExpr _ (other @ Concat{}) = simplify other -convertExpr _ (other @ BinOp{}) = simplify other -convertExpr _ (other @ UniOp{}) = simplify other -convertExpr _ other = other + before = substitute info cc' + after = convertExpr info before + aa' = convertExpr info aa + bb' = convertExpr info bb + cc' = convertExpr info cc +convertExpr info (BinOp op e1 e2) = + simplifyStep $ BinOp op + (convertExpr info e1) + (convertExpr info e2) +convertExpr info (UniOp op expr) = + simplifyStep $ UniOp op $ convertExpr info expr +convertExpr info (Repeat expr exprs) = + simplifyStep $ Repeat + (convertExpr info expr) + (map (convertExpr info) exprs) +convertExpr info (Concat exprs) = + simplifyStep $ Concat (map (convertExpr info) exprs) +convertExpr info expr = + traverseSinglyNestedExprs (convertExpr info) expr substitute :: Info -> Expr -> Expr substitute info expr = - traverseNestedExprs substitute' $ simplify expr + traverseNestedExprs substitute' expr where substitute' :: Expr -> Expr substitute' (Ident x) = diff --git a/src/Convert/SizeCast.hs b/src/Convert/SizeCast.hs index 4831d16..49a7f02 100644 --- a/src/Convert/SizeCast.hs +++ b/src/Convert/SizeCast.hs @@ -12,6 +12,7 @@ import Control.Monad.Writer import qualified Data.Map.Strict as Map import qualified Data.Set as Set +import Convert.ExprUtils import Convert.Traverse import Language.SystemVerilog.AST @@ -55,8 +56,8 @@ traverseModuleItemM item = traverseExprsM traverseExprM item traverseStmtM :: Stmt -> ST Stmt traverseStmtM stmt = traverseStmtExprsM traverseExprM stmt -pattern ConvertedUU :: Char -> Expr -pattern ConvertedUU ch = Number ['1', '\'', 's', 'b', ch] +pattern ConvertedUU :: Integer -> Integer -> Expr +pattern ConvertedUU a b = Number (Based 1 True Binary a b) traverseExprM :: Expr -> ST Expr traverseExprM = @@ -64,16 +65,25 @@ traverseExprM = where convertExprM :: Expr -> ST Expr convertExprM (Cast (Right (Number s)) (Number n)) = - if elem '\'' n && s == takeWhile (/= '\'') n - then return $ Number n - else case (readNumber s, readNumber n) of - (Just s', Just n') -> - return $ Number str + case n of + UnbasedUnsized{} -> fallback + Decimal (-32) True val -> + num $ Decimal (fromIntegral size) False val' where - str = (show size) ++ "'d" ++ (show num) - size = s' - num = n' `mod` (2 ^ s') - _ -> convertCastM (Number s) (Number n) + Just size = numberToInteger s + val' = val `mod` (2 ^ size) + Decimal size signed val -> + if sizesMatch + then num $ Decimal (abs size) signed val + else fallback + Based size signed base vals knds -> + if sizesMatch + then num $ Based (abs size) signed base vals knds + else fallback + where + sizesMatch = numberToInteger s == Just (numberBitLength n) + fallback = convertCastM (Number s) (Number n) + num = return . Number convertExprM (orig @ (Cast (Right DimsFn{}) _)) = return orig convertExprM (Cast (Right (Ident x)) e) = do @@ -91,13 +101,13 @@ traverseExprM = convertExprM other = return other convertCastM :: Expr -> Expr -> ST Expr - convertCastM (s @ (Number str)) (e @ (ConvertedUU ch)) = do - typeMap <- get - case (exprSigning typeMap e, readNumber str) of - (Just Unspecified, Just n) -> return $ Number $ - show n ++ "'b" ++ take (fromIntegral n) (repeat ch) - (Just sg, _) -> convertCastWithSigningM s e sg - _ -> return $ Cast (Right s) e + convertCastM (RawNum n) (ConvertedUU a b) = + return $ Number $ Based (fromIntegral n) False Binary + (extend a) (extend b) + where + extend 0 = 0 + extend 1 = (2 ^ n) - 1 + extend _ = error "not possible" convertCastM s e = do typeMap <- get case exprSigning typeMap e of @@ -117,7 +127,7 @@ castFn e sg = Function Automatic t fnName [decl] [Return $ Ident inp] where inp = "inp" - r = (simplify $ BinOp Sub e (Number "1"), Number "0") + r = (simplify $ BinOp Sub e (RawNum 1), RawNum 0) t = IntegerVector TLogic sg [r] fnName = castFnName e sg decl = Variable Input t inp [] Nil @@ -130,7 +140,7 @@ castFnName e sg = where sizeStr = case e of Number n -> - case readNumber n of + case numberToInteger n of Just v -> show v _ -> shortHash e _ -> shortHash e diff --git a/src/Convert/Stream.hs b/src/Convert/Stream.hs index 312a31b..17024a9 100644 --- a/src/Convert/Stream.hs +++ b/src/Convert/Stream.hs @@ -29,8 +29,8 @@ streamerBlock chunk size asgn output input = , asgn output (Ident out) ] where - lo = Number "0" - hi = BinOp Sub size (Number "1") + lo = RawNum 0 + hi = BinOp Sub size (RawNum 1) t = IntegerVector TLogic Unspecified [(hi, lo)] name = streamerBlockName chunk size inp = name ++ "_inp" @@ -49,7 +49,7 @@ streamerBlock chunk size asgn output input = lhs2 = LHSRange (LHSIdent out) IndexedMinus (BinOp Sub hi base, left) expr2 = Range (Ident inp) IndexedPlus (base, left) stmt2 = Asgn AsgnOpEq Nothing lhs2 expr2 - cmp2 = BinOp Gt left (Number "0") + cmp2 = BinOp Gt left (RawNum 0) streamerBlockName :: Expr -> Expr -> Identifier streamerBlockName chunk size = @@ -60,11 +60,14 @@ traverseStmt (Asgn op mt lhs expr) = traverseAsgn (lhs, expr) (Asgn op mt) traverseStmt other = other +zeroBit :: Expr +zeroBit = Number $ Based 1 False Binary 0 0 + traverseAsgn :: (LHS, Expr) -> (LHS -> Expr -> Stmt) -> Stmt traverseAsgn (lhs, Stream StreamR _ exprs) constructor = constructor lhs expr where - expr = Concat $ exprs ++ [Repeat delta [Number "1'b0"]] + expr = Concat $ exprs ++ [Repeat delta [zeroBit]] size = DimsFn FnBits $ Right $ lhsToExpr lhs exprSize = DimsFn FnBits $ Right (Concat exprs) delta = BinOp Sub size exprSize @@ -73,7 +76,7 @@ traverseAsgn (LHSStream StreamR _ lhss, expr) constructor = traverseAsgn (lhs, Stream StreamL chunk exprs) constructor = do streamerBlock chunk size constructor lhs expr where - expr = Concat $ Repeat delta [Number "1'b0"] : exprs + expr = Concat $ Repeat delta [zeroBit] : exprs size = DimsFn FnBits $ Right $ lhsToExpr lhs exprSize = DimsFn FnBits $ Right (Concat exprs) delta = BinOp Sub size exprSize diff --git a/src/Convert/Struct.hs b/src/Convert/Struct.hs index 0eb128d..3866159 100644 --- a/src/Convert/Struct.hs +++ b/src/Convert/Struct.hs @@ -12,6 +12,7 @@ import Data.Tuple (swap) import qualified Data.Map.Strict as Map import qualified Data.Set as Set +import Convert.ExprUtils import Convert.Scoper import Convert.Traverse import Language.SystemVerilog.AST @@ -43,7 +44,7 @@ convertStruct' isStruct sg fields = then Just (unstructType, unstructFields) else Nothing where - zero = Number "0" + zero = RawNum 0 typeRange :: Type -> Range typeRange t = case ranges of @@ -61,13 +62,13 @@ convertStruct' isStruct sg fields = -- used here because SystemVerilog structs are laid out backwards fieldLos = if isStruct - then map simplify $ tail $ scanr (BinOp Add) (Number "0") fieldSizes - else map simplify $ repeat (Number "0") + then map simplify $ tail $ scanr (BinOp Add) (RawNum 0) fieldSizes + else map simplify $ repeat (RawNum 0) fieldHis = if isStruct then map simplify $ init $ scanr (BinOp Add) minusOne fieldSizes else map simplify $ map (BinOp Add minusOne) fieldSizes - minusOne = UniOp UniSub $ Number "1" + minusOne = UniOp UniSub $ RawNum 1 -- create the mapping structure for the unstructured fields keys = map snd fields @@ -80,7 +81,7 @@ convertStruct' isStruct sg fields = if isStruct then foldl1 (BinOp Add) fieldSizes else head fieldSizes - packedRange = (simplify $ BinOp Sub structSize (Number "1"), zero) + packedRange = (simplify $ BinOp Sub structSize (RawNum 1), zero) unstructType = IntegerVector TLogic sg [packedRange] -- check if this struct can be packed into an integer vector; we only @@ -208,20 +209,20 @@ convertExpr (t @ IntegerVector{}) (Concat exprs) = caster = Cast (Left $ dropInnerTypeRange t) exprs' = map caster exprs isUnsizedNumber :: Expr -> Bool - isUnsizedNumber (Number n) = not $ elem '\'' n + isUnsizedNumber (Number n) = not $ numberIsSized n isUnsizedNumber (UniOp UniSub e) = isUnsizedNumber e isUnsizedNumber _ = False convertExpr (Struct packing fields (_:rs)) (Concat exprs) = Concat $ map (convertExpr (Struct packing fields rs)) exprs convertExpr (Struct packing fields (_:rs)) (Bit e _) = convertExpr (Struct packing fields rs) e -convertExpr (Struct packing fields []) (Pattern [("", Repeat (Number nStr) exprs)]) = - case fmap fromIntegral (readNumber nStr) of - Just n -> convertExpr (Struct packing fields []) $ Pattern $ - zip (repeat "") (concat $ take n $ repeat exprs) +convertExpr (Struct packing fields []) (Pattern [("", Repeat (Number n) exprs)]) = + case fmap fromIntegral (numberToInteger n) of + Just val -> convertExpr (Struct packing fields []) $ Pattern $ + zip (repeat "") (concat $ replicate val exprs) Nothing -> error $ "unable to handle repeat in pattern: " ++ - (show $ Repeat (Number nStr) exprs) + (show $ Repeat (Number n) exprs) convertExpr (struct @ (Struct _ fields [])) (Pattern itemsOrig) = if extraNames /= Set.empty then error $ "pattern " ++ show (Pattern itemsOrig) ++ @@ -332,7 +333,7 @@ convertSubExpr scopes (Dot e x) = (fieldType, bounds, dims) = lookupFieldInfo subExprType x base = fst bounds len = rangeSize bounds - undotted = if null dims || rangeSize (head dims) == Number "1" + undotted = if null dims || rangeSize (head dims) == RawNum 1 then Bit e' (fst bounds) else Range e' IndexedMinus (base, len) convertSubExpr scopes (Range (Dot e x) NonIndexed rOuter) = @@ -374,7 +375,7 @@ convertSubExpr scopes (Range (Dot e x) mode (baseO, lenO)) = NonIndexed -> error "invariant violated" base = endianCondExpr dim baseDec baseInc undotted = Range e' mode (base, lenO) - one = Number "1" + one = RawNum 1 convertSubExpr scopes (Range e mode r) = (dropInnerTypeRange t, Range e' mode r) where (t, e') = convertSubExpr scopes e diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index 279ef2f..4f505a9 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -78,6 +78,9 @@ module Convert.Traverse , traverseNestedExprsM , traverseNestedExprs , collectNestedExprsM +, traverseSinglyNestedExprsM +, traverseSinglyNestedExprs +, collectSinglyNestedExprsM , traverseNestedLHSsM , traverseNestedLHSs , collectNestedLHSsM @@ -211,8 +214,13 @@ traverseSinglyNestedStmtsM fullMapper = cs cs (DoWhile e stmt) = fullMapper stmt >>= return . DoWhile e cs (Forever stmt) = fullMapper stmt >>= return . Forever cs (Foreach x vars stmt) = fullMapper stmt >>= return . Foreach x vars - cs (If NoCheck (Number "1") s _) = fullMapper s - cs (If NoCheck (Number "0") _ s) = fullMapper s + cs (If NoCheck (Number n) s1 s2) = do + s1' <- fullMapper s1 + s2' <- fullMapper s2 + return $ case numberToInteger n of + Nothing -> If NoCheck (Number n) s1' s2' + Just 0 -> s2' + Just _ -> s1' cs (If u e s1 s2) = do s1' <- fullMapper s1 s2' <- fullMapper s2 @@ -379,8 +387,16 @@ collectStmtLHSsM = collectify traverseStmtLHSsM traverseNestedExprsM :: Monad m => MapperM m Expr -> MapperM m Expr traverseNestedExprsM mapper = exprMapper + where exprMapper = mapper >=> traverseSinglyNestedExprsM exprMapper + +traverseNestedExprs :: Mapper Expr -> Mapper Expr +traverseNestedExprs = unmonad traverseNestedExprsM +collectNestedExprsM :: Monad m => CollectorM m Expr -> CollectorM m Expr +collectNestedExprsM = collectify traverseNestedExprsM + +traverseSinglyNestedExprsM :: Monad m => MapperM m Expr -> MapperM m Expr +traverseSinglyNestedExprsM exprMapper = em where - exprMapper = mapper >=> em (_, _, _, typeMapper, _) = exprMapperHelpers exprMapper typeOrExprMapper (Left t) = typeMapper t >>= return . Left @@ -393,7 +409,8 @@ traverseNestedExprsM mapper = exprMapper e2' <- exprMapper e2 return $ Right (e1', e2') em (String s) = return $ String s - em (Number s) = return $ Number s + em (Real s) = return $ Real s + em (Number n) = return $ Number n em (Time s) = return $ Time s em (Ident i) = return $ Ident i em (PSIdent x y) = return $ PSIdent x y @@ -466,6 +483,11 @@ traverseNestedExprsM mapper = exprMapper return $ MinTypMax e1' e2' e3' em (Nil) = return Nil +traverseSinglyNestedExprs :: Mapper Expr -> Mapper Expr +traverseSinglyNestedExprs = unmonad traverseSinglyNestedExprsM +collectSinglyNestedExprsM :: Monad m => CollectorM m Expr -> CollectorM m Expr +collectSinglyNestedExprsM = collectify traverseSinglyNestedExprsM + exprMapperHelpers :: Monad m => MapperM m Expr -> ( MapperM m Range , MapperM m Decl @@ -1033,8 +1055,11 @@ traverseNestedModuleItemsM mapper = fullMapper Generate subItems -> GenBlock "" subItems _ -> GenModuleItem moduleItem' genItemMapper (GenIf _ GenNull GenNull) = return GenNull - genItemMapper (GenIf (Number "1") s _) = return s - genItemMapper (GenIf (Number "0") _ s) = return s + genItemMapper (GenIf (Number n) s1 s2) = do + case numberToInteger n of + Nothing -> return $ GenIf (Number n) s1 s2 + Just 0 -> genItemMapper s2 + Just _ -> genItemMapper s1 genItemMapper (GenBlock "" [item]) = return item genItemMapper (GenBlock _ []) = return GenNull genItemMapper other = return other @@ -1049,11 +1074,6 @@ traverseNestedStmts = unmonad traverseNestedStmtsM collectNestedStmtsM :: Monad m => CollectorM m Stmt -> CollectorM m Stmt collectNestedStmtsM = collectify traverseNestedStmtsM -traverseNestedExprs :: Mapper Expr -> Mapper Expr -traverseNestedExprs = unmonad traverseNestedExprsM -collectNestedExprsM :: Monad m => CollectorM m Expr -> CollectorM m Expr -collectNestedExprsM = collectify traverseNestedExprsM - -- Traverse all the declaration scopes within a ModuleItem. Note that Functions, -- Tasks, Always/Initial/Final blocks are all NOT passed through ModuleItem -- mapper, and Decl ModuleItems are NOT passed through the Decl mapper. The diff --git a/src/Convert/TypeOf.hs b/src/Convert/TypeOf.hs index 2422aef..0b22d85 100644 --- a/src/Convert/TypeOf.hs +++ b/src/Convert/TypeOf.hs @@ -6,7 +6,6 @@ module Convert.TypeOf (convert) where -import Data.List (elemIndex) import Data.Tuple (swap) import qualified Data.Map.Strict as Map @@ -76,8 +75,9 @@ typeof :: Expr -> Scoper Type Type typeof (Number n) = return $ IntegerVector TLogic sg [r] where - (size, sg) = parseNumber n - r = (Number $ show (size - 1), Number "0") + r = (RawNum $ size - 1, RawNum 0) + size = numberBitLength n + sg = if numberIsSigned n then Signed else Unspecified typeof (Call (Ident x) _) = typeof $ Ident x typeof (orig @ (Bit e _)) = do @@ -94,8 +94,8 @@ typeof (orig @ (Range e mode r)) = do lo = fst r hi = case mode of NonIndexed -> snd r - IndexedPlus -> BinOp Sub (uncurry (BinOp Add) r) (Number "1") - IndexedMinus -> BinOp Add (uncurry (BinOp Sub) r) (Number "1") + IndexedPlus -> BinOp Sub (uncurry (BinOp Add) r) (RawNum 1) + IndexedMinus -> BinOp Add (uncurry (BinOp Sub) r) (RawNum 1) typeof (orig @ (Dot e x)) = do t <- typeof e case t of @@ -133,19 +133,6 @@ typeof (Repeat reps exprs) = return $ typeOfSize size where size = BinOp Mul reps (concatSize exprs) typeof other = lookupTypeOf other --- determines the size and sign of a number literal -parseNumber :: String -> (Integer, Signing) -parseNumber s = - case elemIndex '\'' s of - Nothing -> (32, Signed) - Just 0 -> parseNumber $ '3' : '2' : s - Just idx -> (size, signing) - where - Just size = readNumber $ take idx s - signing = case drop (idx + 1) s of - 's' : _ -> Signed - _ -> Unsigned - -- produces a type large enough to hold either expression largerSizeType :: Expr -> Expr -> Type largerSizeType a b = @@ -158,7 +145,7 @@ largerSizeType a b = -- returns the total size of concatenated list of expressions concatSize :: [Expr] -> Expr concatSize exprs = - foldl (BinOp Add) (Number "0") $ + foldl (BinOp Add) (RawNum 0) $ map sizeof exprs where sizeof = DimsFn FnBits . Right @@ -166,10 +153,10 @@ concatSize exprs = -- produces a generic type of the given size typeOfSize :: Expr -> Type typeOfSize size = - IntegerVector TLogic sg [(hi, Number "0")] + IntegerVector TLogic sg [(hi, RawNum 0)] where sg = Unspecified -- suitable for now - hi = BinOp Sub size (Number "1") + hi = BinOp Sub size (RawNum 1) -- combines a type with unpacked ranges injectRanges :: Type -> [Range] -> Type diff --git a/src/Convert/UnbasedUnsized.hs b/src/Convert/UnbasedUnsized.hs index 7ca1434..b27ac55 100644 --- a/src/Convert/UnbasedUnsized.hs +++ b/src/Convert/UnbasedUnsized.hs @@ -76,7 +76,7 @@ bindItem ports bind = where portName = lookupPort ports (bPort bind) size = DimsFn FnBits $ Right $ Ident portName - rng = (BinOp Sub size (Number "1"), Number "0") + rng = (BinOp Sub size (RawNum 1), RawNum 0) typ = Implicit Unspecified [rng] name = bindName bind expr = literalFor $ bBit bind @@ -102,8 +102,8 @@ convertModuleItemM (Instance moduleName params instanceName [] bindings) = do expr'' <- traverseNestedExprsM (replaceBindingExpr port) expr' return (portName, expr'') replaceBindingExpr :: Port -> Expr -> Writer Binds Expr - replaceBindingExpr port (orig @ (Cast Right{} (Number num))) = do - let ch = last num + replaceBindingExpr port (orig @ (Cast Right{} (ConvertedUU a b))) = do + let ch = charForBit a b if orig == sizedLiteralFor tag ch then do let bind = Bind moduleName ch port @@ -120,14 +120,24 @@ convertModuleItem = traverseTypes (traverseNestedTypes convertType) . traverseAsgns convertAsgn -digits :: [Char] -digits = ['0', '1', 'x', 'z', 'X', 'Z'] - literalFor :: Char -> Expr -literalFor ch = - if elem ch digits - then Number ("1'sb" ++ [ch]) - else error $ "unexpected unbased-unsized digit: " ++ [ch] +literalFor 'Z' = literalFor 'z' +literalFor 'X' = literalFor 'x' +literalFor '0' = Number $ Based 1 True Binary 0 0 +literalFor '1' = Number $ Based 1 True Binary 1 0 +literalFor 'x' = Number $ Based 1 True Binary 0 1 +literalFor 'z' = Number $ Based 1 True Binary 1 1 +literalFor ch = error $ "unexpected unbased-unsized digit: " ++ [ch] + +pattern ConvertedUU :: Integer -> Integer -> Expr +pattern ConvertedUU a b = Number (Based 1 True Binary a b) + +charForBit :: Integer -> Integer -> Char +charForBit 0 0 = '0' +charForBit 1 0 = '1' +charForBit 0 1 = 'x' +charForBit 1 1 = 'z' +charForBit _ _ = error "charForBit invariant violated" sizedLiteralFor :: Expr -> Char -> Expr sizedLiteralFor expr ch = @@ -206,7 +216,7 @@ convertExpr (ContextDetermined expr) (UU ch) = convertExpr _ other = other pattern UU :: Char -> Expr -pattern UU ch = Number ['\'', ch] +pattern UU ch = Number (UnbasedUnsized ch) convertType :: Type -> Type convertType (TypeOf e) = TypeOf $ convertExpr SelfDetermined e diff --git a/src/Convert/Wildcard.hs b/src/Convert/Wildcard.hs index a50f416..318a1bc 100644 --- a/src/Convert/Wildcard.hs +++ b/src/Convert/Wildcard.hs @@ -34,7 +34,7 @@ import qualified Data.Map.Strict as Map import Convert.Traverse import Language.SystemVerilog.AST -type Patterns = Map.Map Identifier String +type Patterns = Map.Map Identifier Number convert :: [AST] -> [AST] convert = map $ traverseDescriptions convertDescription @@ -64,10 +64,7 @@ traverseExprM = traverseNestedExprsM $ stately convertExpr isPlainPattern :: Patterns -> Expr -> Bool isPlainPattern _ (Number n) = - not $ any isWildcardChar n - where - isWildcardChar :: Char -> Bool - isWildcardChar = flip elem "xzXZ?" + numberToInteger n /= Nothing isPlainPattern patterns (Ident x) = case Map.lookup x patterns of Nothing -> False @@ -81,7 +78,7 @@ convertExpr patterns (BinOp WEq l r) = else BinOp BitAnd couldMatch $ BinOp BitOr noExtraXZs $ - Number "1'bx" + Number (Based 1 False Binary 0 1) where lxl = BinOp BitXor l l rxr = BinOp BitXor r r diff --git a/src/Language/SystemVerilog/AST.hs b/src/Language/SystemVerilog/AST.hs index ee22105..4d93f85 100644 --- a/src/Language/SystemVerilog/AST.hs +++ b/src/Language/SystemVerilog/AST.hs @@ -22,6 +22,7 @@ module Language.SystemVerilog.AST , module GenItem , module LHS , module ModuleItem + , module Number , module Op , module Stmt , module Type @@ -40,6 +41,7 @@ import Language.SystemVerilog.AST.Expr as Expr import Language.SystemVerilog.AST.GenItem as GenItem import Language.SystemVerilog.AST.LHS as LHS import Language.SystemVerilog.AST.ModuleItem as ModuleItem +import Language.SystemVerilog.AST.Number as Number import Language.SystemVerilog.AST.Op as Op import Language.SystemVerilog.AST.Stmt as Stmt import Language.SystemVerilog.AST.Type as Type diff --git a/src/Language/SystemVerilog/AST/Expr.hs b/src/Language/SystemVerilog/AST/Expr.hs index 32e88da..b811532 100644 --- a/src/Language/SystemVerilog/AST/Expr.hs +++ b/src/Language/SystemVerilog/AST/Expr.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE PatternSynonyms #-} {- sv2v - Author: Zachary Snow - Initial Verilog AST Author: Tom Hawkins @@ -17,23 +18,15 @@ module Language.SystemVerilog.AST.Expr , showAssignment , showRanges , showExprOrRange - , simplify - , rangeSize - , rangeSizeHiLo - , endianCondExpr - , endianCondRange - , dimensionsSize - , readNumber , ParamBinding , showParams + , pattern RawNum ) where -import Data.Bits (shiftL, shiftR) import Data.List (intercalate) -import Numeric (readHex) import Text.Printf (printf) -import Text.Read (readMaybe) +import Language.SystemVerilog.AST.Number (Number(..)) import Language.SystemVerilog.AST.Op import Language.SystemVerilog.AST.ShowHelp import {-# SOURCE #-} Language.SystemVerilog.AST.Type @@ -43,9 +36,13 @@ type Range = (Expr, Expr) type TypeOrExpr = Either Type Expr type ExprOrRange = Either Expr Range +pattern RawNum :: Integer -> Expr +pattern RawNum n = Number (Decimal (-32) True n) + data Expr = String String - | Number String + | Real String + | Number Number | Time String | Ident Identifier | PSIdent Identifier Identifier @@ -71,9 +68,10 @@ data Expr instance Show Expr where show (Nil ) = "" - show (Number str ) = str show (Time str ) = str show (Ident str ) = str + show (Real str ) = str + show (Number n ) = show n show (PSIdent x y ) = printf "%s::%s" x y show (CSIdent x p y) = printf "%s#%s::%s" x (showParams p) y show (String str ) = printf "\"%s\"" str @@ -193,24 +191,6 @@ showExprOrRange :: ExprOrRange -> String showExprOrRange (Left x) = show x showExprOrRange (Right x) = show x -clog2Help :: Integer -> Integer -> Integer -clog2Help p n = if p >= n then 0 else 1 + clog2Help (p*2) n -clog2 :: Integer -> Integer -clog2 n = if n < 2 then 0 else clog2Help 1 n - -readNumber :: String -> Maybe Integer -readNumber ('3' : '2' : '\'' : 'd' : rest) = readMaybe rest -readNumber ( '\'' : 'd' : rest) = readMaybe rest -readNumber ('3' : '2' : '\'' : 'h' : rest) = - case readHex rest of - [(v, _)] -> Just v - _ -> Nothing -readNumber ('\'' : 'h' : rest) = - case readHex rest of - [(v, _)] -> Just v - _ -> Nothing -readNumber n = readMaybe n - showUniOpPrec :: Expr -> ShowS showUniOpPrec (e @ UniOp{}) = (showParen True . shows) e showUniOpPrec (e @ BinOp{}) = (showParen True . shows) e @@ -220,154 +200,6 @@ showBinOpPrec :: Expr -> ShowS showBinOpPrec (e @ BinOp{}) = (showParen True . shows) e showBinOpPrec e = shows e --- basic expression simplfication utility to help us generate nicer code in the --- common case of ranges like `[FOO-1:0]` -simplify :: Expr -> Expr -simplify (UniOp LogNot (Number "1")) = Number "0" -simplify (UniOp LogNot (Number "0")) = Number "1" -simplify (UniOp LogNot (BinOp Eq a b)) = BinOp Ne a b -simplify (orig @ (Repeat (Number n) exprs)) = - case readNumber n of - Nothing -> orig - Just 0 -> Concat [] - Just 1 -> Concat exprs - Just x -> - if x < 0 - then error $ "negative repeat count: " ++ show orig - else orig -simplify (Concat [expr]) = expr -simplify (Concat exprs) = - Concat $ filter (/= Concat []) exprs -simplify (orig @ (Call (Ident "$clog2") (Args [Number n] []))) = - case readNumber n of - Nothing -> orig - Just x -> toLiteral $ clog2 x -simplify (Mux cc e1 e2) = - case cc' of - Number "1" -> e1' - Number "0" -> e2' - _ -> Mux cc' e1' e2' - where - cc' = simplify cc - e1' = simplify e1 - e2' = simplify e2 -simplify (Range e NonIndexed r) = Range e NonIndexed r -simplify (Range e _ (i, Number "0")) = Bit e i -simplify (BinOp Sub (Number n1) (BinOp Sub (Number n2) e)) = - simplify $ BinOp Add (BinOp Sub (Number n1) (Number n2)) e -simplify (BinOp Sub (Number n1) (BinOp Sub e (Number n2))) = - simplify $ BinOp Sub (BinOp Add (Number n1) (Number n2)) e -simplify (BinOp Sub (BinOp Add e (Number n1)) (Number n2)) = - simplify $ BinOp Add e (BinOp Sub (Number n1) (Number n2)) -simplify (BinOp Add (Number n1) (BinOp Add (Number n2) e)) = - simplify $ BinOp Add (BinOp Add (Number n1) (Number n2)) e -simplify (BinOp Ge (BinOp Sub e (Number "1")) (Number "0")) = - simplify $ BinOp Ge e (Number "1") -simplify (BinOp Add e1 (UniOp UniSub e2)) = - simplify $ BinOp Sub e1 e2 -simplify (BinOp Add (UniOp UniSub e2) e1) = - simplify $ BinOp Sub e1 e2 -simplify (BinOp Add (BinOp Sub (Number n1) e) (Number n2)) = - case (readNumber n1, readNumber n2) of - (Just x, Just y) -> - simplify $ BinOp Sub (toLiteral (x + y)) e' - _ -> nochange - where - e' = simplify e - nochange = BinOp Add (BinOp Sub (Number n1) e') (Number n2) -simplify (BinOp op e1 e2) = - case (op, e1', e2') of - (Add, Number "0", e) -> e - (Add, e, Number "0") -> e - (Mul, _, Number "0") -> Number "0" - (Mul, Number "0", _) -> Number "0" - (Mul, e, Number "1") -> e - (Mul, Number "1", e) -> e - (Sub, e, Number "0") -> e - (Add, BinOp Sub e (Number "1"), Number "1") -> e - (Add, e, BinOp Sub (Number "0") (Number "1")) -> BinOp Sub e (Number "1") - (_ , Number a, Number b) -> - case (op, readNumber a, readNumber b) of - (Add, Just x, Just y) -> toLiteral (x + y) - (Sub, Just x, Just y) -> toLiteral (x - y) - (Mul, Just x, Just y) -> toLiteral (x * y) - (Div, Just _, Just 0) -> Number "x" - (Div, Just x, Just y) -> toLiteral (x `quot` y) - (Mod, Just x, Just y) -> toLiteral (x `rem` y) - (Pow, Just x, Just y) -> toLiteral (x ^ y) - (Eq , Just x, Just y) -> bool $ x == y - (Ne , Just x, Just y) -> bool $ x /= y - (Gt , Just x, Just y) -> bool $ x > y - (Ge , Just x, Just y) -> bool $ x >= y - (Lt , Just x, Just y) -> bool $ x < y - (Le , Just x, Just y) -> bool $ x <= y - (ShiftAL, Just x, Just y) -> toLiteral $ shiftL x (toInt y) - (ShiftAR, Just x, Just y) -> toLiteral $ shiftR x (toInt y) - (ShiftL , Just x, Just y) -> toLiteral $ shiftL x (toInt y) - (ShiftR , Just x, Just y) -> - if x < 0 && y > 0 - then BinOp ShiftR (Number a) (Number b) - else toLiteral $ shiftR x (toInt y) - _ -> BinOp op e1' e2' - where - toInt :: Integer -> Int - toInt = fromIntegral - (Add, BinOp Add e (Number a), Number b) -> - case (readNumber a, readNumber b) of - (Just x, Just y) -> BinOp Add e $ toLiteral (x + y) - _ -> BinOp op e1' e2' - (Sub, e, Number "-1") -> BinOp Add e (Number "1") - _ -> BinOp op e1' e2' - where - e1' = simplify e1 - e2' = simplify e2 - bool True = Number "1" - bool False = Number "0" -simplify other = other - -toLiteral :: Integer -> Expr -toLiteral n = - if n >= 4294967296 - then Number $ show (bits n) ++ "'d" ++ show n - else Number $ show n - -bits :: Integer -> Integer -bits 0 = 0 -bits n = 1 + bits (quot n 2) - -rangeSize :: Range -> Expr -rangeSize (s, e) = - endianCondExpr (s, e) a b - where - a = rangeSizeHiLo (s, e) - b = rangeSizeHiLo (e, s) - -rangeSizeHiLo :: Range -> Expr -rangeSizeHiLo (hi, lo) = - simplify $ BinOp Add (BinOp Sub hi lo) (Number "1") - --- chooses one or the other expression based on the endianness of the given --- range; [hi:lo] chooses the first expression -endianCondExpr :: Range -> Expr -> Expr -> Expr -endianCondExpr r e1 e2 = simplify $ Mux (uncurry (BinOp Ge) r) e1 e2 - --- chooses one or the other range based on the endianness of the given range, --- but in such a way that the result is itself also usable as a range even if --- the endianness cannot be resolved during conversion, i.e. if it's dependent --- on a parameter value; [hi:lo] chooses the first range -endianCondRange :: Range -> Range -> Range -> Range -endianCondRange r r1 r2 = - ( endianCondExpr r (fst r1) (fst r2) - , endianCondExpr r (snd r1) (snd r2) - ) - -dimensionsSize :: [Range] -> Expr -dimensionsSize ranges = - simplify $ - foldl (BinOp Mul) (Number "1") $ - map rangeSize $ - ranges - type ParamBinding = (Identifier, TypeOrExpr) showParams :: [ParamBinding] -> String diff --git a/src/Language/SystemVerilog/AST/Number.hs b/src/Language/SystemVerilog/AST/Number.hs new file mode 100644 index 0000000..eb9cec5 --- /dev/null +++ b/src/Language/SystemVerilog/AST/Number.hs @@ -0,0 +1,298 @@ +{- sv2v + - Author: Zachary Snow + - + - SystemVerilog number literals + -} + +module Language.SystemVerilog.AST.Number + ( Number (..) + , Base (..) + , parseNumber + , numberBitLength + , numberIsSigned + , numberIsSized + , numberToInteger + ) where + +import Data.Char (digitToInt, intToDigit, toLower) +import Data.List (elemIndex) +import Text.Read (readMaybe) + +-- normalize the number first, making everything lowercase and removing +-- visual niceties like spaces and underscores +parseNumber :: String -> Number +parseNumber = parseNumber' . map toLower . filter (not . isPad) + where isPad ch = ch == '_' || ch == ' ' + +parseNumber' :: String -> Number +parseNumber' ['\'', ch] = UnbasedUnsized ch +parseNumber' str = + -- simple decimal number + if maybeIdx == Nothing then + let n = readDecimal str + in Decimal (negate $ decimalSize True n) True n + -- non-decimal based integral number + else if maybeBase /= Nothing then + let (values, kinds) = parseBasedDigits (baseSize base) digitsExtended + in Based size signed base values kinds + -- decimal X or Z literal + else if numDigits == 1 && elem leadDigit xzDigits then + let (vals, knds) = parseBasedDigits 2 $ replicate (abs size) leadDigit + in Based size signed Binary vals knds + -- explicitly-based decimal number + else + let num = readDecimal digits + in if rawSize == 0 + then Decimal (negate $ decimalSize signed num) signed num + else Decimal size signed num + where + -- pull out the components of the literals + maybeIdx = elemIndex '\'' str + Just idx = maybeIdx + signBasedAndDigits = drop (idx + 1) str + (signed, baseAndDigits) = takeSign signBasedAndDigits + (maybeBase, digits) = takeBase baseAndDigits + + -- high-order X or Z is extended up to the size of the literal + leadDigit = head digits + numDigits = length digits + digitsExtended = + if elem leadDigit xzDigits + then replicate (sizeDigits - numDigits) leadDigit ++ digits + else digits + + -- determine the number of digits needed based on the size + sizeDigits = ((abs size) `div` bitsPerDigit) + sizeExtraDigit + sizeExtraDigit = + if (abs size) `mod` bitsPerDigit == 0 + then 0 + else 1 + + -- determine the explicit size of the literal in bites + Just base = maybeBase + rawSize = + if idx == 0 + then 0 + else readDecimal $ take idx str + size = + if rawSize /= 0 then + rawSize + else if maybeBase /= Nothing then + negate $ max 32 (bitsPerDigit * numDigits) + else + -32 + bitsPerDigit = bits $ baseSize base - 1 + +-- read a simple unsigned decimal number +readDecimal :: Read a => String -> a +readDecimal str = + case readMaybe str of + Nothing -> error $ "could not parse decimal " ++ show str + Just n -> n + +-- returns the number of bits necessary to represent a number; it gives an extra +-- bit for signed numbers so that the literal doesn't sign extend unnecessarily +decimalSize :: Bool -> Integer -> Int +decimalSize True = max 32 . fromIntegral . bits . (* 2) +decimalSize False = max 32 . fromIntegral . bits + +-- remove the leading sign specified, if it is present +takeSign :: String -> (Bool, String) +takeSign ('s' : rest) = (True, rest) +takeSign rest = (False, rest) + +-- pop the leading base specified from a based coda +takeBase :: String -> (Maybe Base, String) +takeBase ('d' : rest) = (Nothing, rest) +takeBase ('b' : rest) = (Just Binary, rest) +takeBase ('o' : rest) = (Just Octal, rest) +takeBase ('h' : rest) = (Just Hex, rest) +takeBase rest = error $ "cannot parse based coda " ++ show rest + +-- convert the digits of a based number to its corresponding value and kind bits +parseBasedDigits :: Integer -> String -> (Integer, Integer) +parseBasedDigits base str = + (values, kinds) + where + values = parseDigits parseValueDigit str + kinds = parseDigits parseKindDigit str + + parseDigits :: (Char -> Integer) -> String -> Integer + parseDigits f = foldl sumStep 0 . map f + sumStep :: Integer -> Integer -> Integer + sumStep total digit = total * base + digit + + parseValueDigit :: Char -> Integer + parseValueDigit x = + if elem x xDigits then + 0 + else if elem x zDigits then + base - 1 + else + fromIntegral $ digitToInt x + + parseKindDigit :: Char -> Integer + parseKindDigit x = + if elem x xzDigits + then base - 1 + else 0 + +xDigits :: [Char] +xDigits = ['x'] +zDigits :: [Char] +zDigits = ['z', '?'] +xzDigits :: [Char] +xzDigits = xDigits ++ zDigits + +data Base + = Binary + | Octal + | Hex + deriving (Eq, Ord) + +instance Show Base where + show Binary = "b" + show Octal = "o" + show Hex = "h" + +data Number + = UnbasedUnsized Char + | Decimal Int Bool Integer + | Based Int Bool Base Integer Integer + deriving (Eq, Ord) + +baseSize :: Integral a => Base -> a +baseSize Binary = 2 +baseSize Octal = 8 +baseSize Hex = 16 + +-- get the number of bits in a number +numberBitLength :: Number -> Integer +numberBitLength UnbasedUnsized{} = 32 +numberBitLength (Decimal size _ _) = fromIntegral $ abs size +numberBitLength (Based size _ _ _ _) = fromIntegral $ abs size + +-- get whether or not a number is signed +numberIsSized :: Number -> Bool +numberIsSized UnbasedUnsized{} = False +numberIsSized (Decimal size _ _) = size > 0 +numberIsSized (Based size _ _ _ _) = size > 0 + +-- get whether or not a number is signed +numberIsSigned :: Number -> Bool +numberIsSigned UnbasedUnsized{} = False +numberIsSigned (Decimal _ signed _) = signed +numberIsSigned (Based _ signed _ _ _) = signed + +-- get the integer value of a number, provided it has not X or Z bits +numberToInteger :: Number -> Maybe Integer +numberToInteger (UnbasedUnsized '1') = Just 1 +numberToInteger (UnbasedUnsized '0') = Just 0 +numberToInteger UnbasedUnsized{} = Nothing +numberToInteger (Decimal _ _ num) = Just num +numberToInteger (Based _ _ _ num 0) = Just num +numberToInteger Based{} = Nothing + +-- return the number of bits in a number (i.e. ilog2) +bits :: Integral a => a -> a +bits 0 = 0 +bits n = 1 + bits (quot n 2) + +-- number to string conversion +instance Show Number where + show (UnbasedUnsized ch) = + if elem ch "01xzXZ" + then ['\'', ch] + else error $ "illegal unbased-unsized char: " ++ show ch + show (Decimal (-32) True value) = + if value < 0 + then error $ "illegal decimal: " ++ show value + else show value + show (Decimal size signed value) = + if size == 0 + then error $ "illegal decimal literal: " + ++ show (size, signed, value) + else sizeStr ++ '\'' : signedStr ++ 'd' : valueStr + where + sizeStr = if size > 0 then show size else "" + signedStr = if signed then "s" else "" + valueStr = show value + show (Based size signed base value kinds) = + if size == 0 || value < 0 || kinds < 0 + then error $ "illegal based literal: " + ++ show (size, signed, base, value, kinds) + else sizeStr ++ '\'' : signedStr ++ baseCh : valueStr + where + sizeStr = if size > 0 then show size else "" + signedStr = if signed then "s" else "" + [baseCh] = show base + valueStr = showBasedDigits (baseSize base) size value kinds + +showBasedDigits :: Int -> Int -> Integer -> Integer -> String +showBasedDigits base size values kinds = + if numDigits > sizeDigits then + error $ "invalid based literal digits: " + ++ show (base, size, values, kinds, numDigits, sizeDigits) + else if size < -32 then + padList '0' sizeDigits digits + else if leadingXZ && size < 0 then + removeExtraPadding digits + else if leadingXZ then + padList '0' sizeDigits digits + else + digits + where + valChunks = chunk (fromIntegral base) values + kndChunks = chunk (fromIntegral base) kinds + numDigits = max (length valChunks) (length kndChunks) + + digits = zipWith combineChunks + (padList 0 numDigits valChunks) + (padList 0 numDigits kndChunks) + leadingXZ = elem (head digits) xzDigits + + removeExtraPadding :: String -> String + removeExtraPadding ('x' : 'x' : chs) = removeExtraPadding ('x' : chs) + removeExtraPadding ('z' : 'z' : chs) = removeExtraPadding ('z' : chs) + removeExtraPadding chs = chs + + -- determine the number of digits needed based on the explicit size + sizeDigits = ((abs size) `div` bitsPerDigit) + sizeExtraDigit + sizeExtraDigit = + if (abs size) `mod` bitsPerDigit == 0 + then 0 + else 1 + bitsPerDigit = bits $ base - 1 + + -- combine a value and kind digit into their corresponding character + combineChunks :: Int -> Int -> Char + combineChunks value kind = + if kind == 0 then + intToDigit value + else if kind /= base - 1 then + invalid + else if value == 0 then + 'x' + else if value == base - 1 then + 'z' + else + invalid + where + invalid = error $ "based bits inconsistent: " + ++ show (base, values, kinds, value, kind) + +-- pad the left side of a list with `padding` to be at least `size` elements +padList :: a -> Int -> [a] -> [a] +padList padding size values = + replicate (size - length values) padding ++ values + +-- split an integer into chunks of `base` bits +chunk :: Integer -> Integer -> [Int] +chunk base n0 = + reverse $ chunkStep (quotRem n0 base) + where + chunkStep (n, d) = + case n of + 0 -> [d'] + _ -> d' : chunkStep (quotRem n base) + where d' = fromIntegral d diff --git a/src/Language/SystemVerilog/AST/Type.hs b/src/Language/SystemVerilog/AST/Type.hs index cb26853..f1fea7e 100644 --- a/src/Language/SystemVerilog/AST/Type.hs +++ b/src/Language/SystemVerilog/AST/Type.hs @@ -112,10 +112,10 @@ typeRanges (UnpackedType t rs) = (UnpackedType t, rs) nullRange :: Type -> ([Range] -> Type) nullRange t [] = t -nullRange t [(Number "0", Number "0")] = t +nullRange t [(RawNum 0, RawNum 0)] = t nullRange (IntegerAtom TInteger sg) rs = -- integer arrays are allowed in SystemVerilog but not in Verilog - IntegerVector TBit sg (rs ++ [(Number "31", Number "0")]) + IntegerVector TBit sg (rs ++ [(RawNum 31, RawNum 0)]) nullRange t rs1 = if t == t' then error $ "non-vector type " ++ show t ++ @@ -136,9 +136,9 @@ elaborateIntegerAtom other = other -- size; if not unspecified, the first signing overrides the second baseIntType :: Signing -> Signing -> Int -> Type baseIntType sgOverride sgBase size = - IntegerVector TReg sg [(Number hi, Number "0")] + IntegerVector TReg sg [(RawNum hi, RawNum 0)] where - hi = show (size - 1) + hi = fromIntegral $ size - 1 sg = if sgOverride /= Unspecified then sgOverride else sgBase diff --git a/src/Language/SystemVerilog/Parser/Lex.x b/src/Language/SystemVerilog/Parser/Lex.x index a45bb7d..528ab00 100644 --- a/src/Language/SystemVerilog/Parser/Lex.x +++ b/src/Language/SystemVerilog/Parser/Lex.x @@ -74,9 +74,6 @@ import Language.SystemVerilog.Parser.Tokens | @binaryNumber | @hexNumber | @unbasedUnsizedLiteral -@number - = @integralNumber - | @realNumber -- Strings @@ -366,7 +363,8 @@ tokens :- @escapedIdentifier { tok Id_escaped } @systemIdentifier { tok Id_system } - @number { tok Lit_number } + @realNumber { tok Lit_real } + @integralNumber { tok Lit_number } @string { tok Lit_string } @time { tok Lit_time } diff --git a/src/Language/SystemVerilog/Parser/Parse.y b/src/Language/SystemVerilog/Parser/Parse.y index 19fbfe7..ab51ef6 100644 --- a/src/Language/SystemVerilog/Parser/Parse.y +++ b/src/Language/SystemVerilog/Parser/Parse.y @@ -295,6 +295,7 @@ import Language.SystemVerilog.Parser.Tokens simpleIdentifier { Token Id_simple _ _ } escapedIdentifier { Token Id_escaped _ _ } systemIdentifier { Token Id_system _ _ } +real { Token Lit_real _ _ } number { Token Lit_number _ _ } string { Token Lit_string _ _ } time { Token Lit_time _ _ } @@ -630,10 +631,10 @@ DeclToken :: { DeclToken } | ExplicitLifetime {% posInject \p -> DTLifetime p $1 } | "const" PartialType {% posInject \p -> DTType p $2 } | "{" StreamOp StreamSize Concat "}" {% posInject \p -> DTStream p $2 $3 (map toLHS $4) } - | "{" StreamOp Concat "}" {% posInject \p -> DTStream p $2 (Number "1") (map toLHS $3) } + | "{" StreamOp Concat "}" {% posInject \p -> DTStream p $2 (RawNum 1) (map toLHS $3) } | opt("var") "type" "(" Expr ")" {% posInject \p -> DTType p (\Unspecified -> \[] -> TypeOf $4) } | "<=" opt(DelayOrEvent) Expr {% posInject \p -> DTAsgn p AsgnOpNonBlocking $2 $3 } - | IncOrDecOperator {% posInject \p -> DTAsgn p (AsgnOp $1) Nothing (Number "1") } + | IncOrDecOperator {% posInject \p -> DTAsgn p (AsgnOp $1) Nothing (RawNum 1) } | Identifier "::" Identifier {% posInject \p -> DTPSIdent p $1 $3 } | Identifier ParamBindings "::" Identifier {% posInject \p -> DTCSIdent p $1 $2 $4 } DeclTokenAsgn :: { DeclToken } @@ -905,7 +906,7 @@ DimensionsNonEmpty :: { [Range] } | DimensionsNonEmpty Dimension { $1 ++ [$2] } Dimension :: { Range } : Range { $1 } - | "[" Expr "]" { (Number "0", BinOp Sub $2 (Number "1")) } + | "[" Expr "]" { (RawNum 0, BinOp Sub $2 (RawNum 1)) } DeclAsgns :: { [(Identifier, Expr, [Range])] } : DeclAsgn { [$1] } @@ -928,8 +929,8 @@ LHS :: { LHS } | LHS "[" Expr "]" { LHSBit $1 $3 } | LHS "." Identifier { LHSDot $1 $3 } | LHSConcat { LHSConcat $1 } - | "{" StreamOp StreamSize Concat "}" { LHSStream $2 $3 (map toLHS $4) } - | "{" StreamOp Concat "}" { LHSStream $2 (Number "1") (map toLHS $3) } + | "{" StreamOp StreamSize Concat "}" { LHSStream $2 $3 (map toLHS $4) } + | "{" StreamOp Concat "}" { LHSStream $2 (RawNum 1) (map toLHS $3) } LHSConcat :: { [LHS] } : "{" LHSs "}" { $2 } @@ -972,8 +973,8 @@ StmtAsgn :: { Stmt } : LHS "=" opt(DelayOrEvent) Expr ";" { Asgn AsgnOpEq $3 $1 $4 } | LHS "<=" opt(DelayOrEvent) Expr ";" { Asgn AsgnOpNonBlocking $3 $1 $4 } | LHS AsgnBinOp Expr ";" { Asgn $2 Nothing $1 $3 } - | LHS IncOrDecOperator ";" { Asgn (AsgnOp $2) Nothing $1 (Number "1") } - | IncOrDecOperator LHS ";" { Asgn (AsgnOp $1) Nothing $2 (Number "1") } + | LHS IncOrDecOperator ";" { Asgn (AsgnOp $2) Nothing $1 (RawNum 1) } + | IncOrDecOperator LHS ";" { Asgn (AsgnOp $1) Nothing $2 (RawNum 1) } | LHS ";" { Subroutine (lhsToExpr $1) (Args [] []) } | LHS CallArgs ";" { Subroutine (lhsToExpr $1) $2 } StmtNonAsgn :: { Stmt } @@ -1021,7 +1022,7 @@ ForInit :: { Either [Decl] [(LHS, Expr)] } | DeclTokens(";") { parseDTsAsDeclsOrAsgns $1 } ForCond :: { Expr } - : ";" { Number "1" } + : ";" { RawNum 1 } | Expr ";" { $1 } ForStep :: { [(LHS, AsgnOp, Expr)] } @@ -1032,8 +1033,8 @@ ForStepNonEmpty :: { [(LHS, AsgnOp, Expr)] } | ForStepNonEmpty "," ForStepAssignment { $1 ++ [$3] } ForStepAssignment :: { (LHS, AsgnOp, Expr) } : LHS AsgnOp Expr { ($1, $2, $3) } - | IncOrDecOperator LHS { ($2, AsgnOp $1, Number "1") } - | LHS IncOrDecOperator { ($1, AsgnOp $2, Number "1") } + | IncOrDecOperator LHS { ($2, AsgnOp $1, RawNum 1) } + | LHS IncOrDecOperator { ($1, AsgnOp $2, RawNum 1) } IdxVars :: { [Identifier] } : "[" IdxVarsInside "]" { $2 } @@ -1122,8 +1123,11 @@ InsideCase :: { ([ExprOrRange], Stmt) } : OpenRangeList ":" Stmt { ($1, $3) } | "default" opt(":") Stmt { ([], $3) } -Number :: { String } - : number { tokenString $1 } +Real :: { String } + : real { tokenString $1 } + +Number :: { Number } + : number { parseNumber $ tokenString $1 } String :: { String } : string { tail $ init $ tokenString $1 } @@ -1169,11 +1173,12 @@ ValueRange :: { ExprOrRange } Expr :: { Expr } : "(" Expr ")" { $2 } | String { String $1 } + | Real { Real $1 } | Number { Number $1 } | Time { Time $1 } | Expr CallArgs { Call $1 $2 } | DimsFn "(" TypeOrExpr ")" { DimsFn $1 $3 } - | DimFn "(" TypeOrExpr ")" { DimFn $1 $3 (Number "1") } + | DimFn "(" TypeOrExpr ")" { DimFn $1 $3 (RawNum 1) } | DimFn "(" TypeOrExpr "," Expr ")" { DimFn $1 $3 $5 } | Expr PartSelect { Range $1 (fst $2) (snd $2) } | Expr "[" Expr "]" { Bit $1 $3 } @@ -1184,8 +1189,8 @@ Expr :: { Expr } | "'" "{" PatternItems "}" { Pattern $3 } | CastingType "'" "(" Expr ")" { Cast (Left $1) $4 } | Expr "'" "(" Expr ")" { Cast (Right $1) $4 } - | "{" StreamOp StreamSize Concat "}" { Stream $2 $3 $4 } - | "{" StreamOp Concat "}" { Stream $2 (Number "1") $3 } + | "{" StreamOp StreamSize Concat "}" { Stream $2 $3 $4 } + | "{" StreamOp Concat "}" { Stream $2 (RawNum 1) $3 } | Expr "inside" "{" OpenRangeList "}" { Inside $1 $4 } | "(" Expr ":" Expr ":" Expr ")" { MinTypMax $2 $4 $6 } | Identifier %prec REDUCE_OP {- defer -} { Ident $1 } @@ -1302,8 +1307,8 @@ GenvarInitialization :: { Expr -> (Identifier, AsgnOp, Expr) -> GenItem -> GenIt GenvarIteration :: { (Identifier, AsgnOp, Expr) } : Identifier AsgnOp Expr { ($1, $2, $3) } - | IncOrDecOperator Identifier { ($2, AsgnOp $1, Number "1") } - | Identifier IncOrDecOperator { ($1, AsgnOp $2, Number "1") } + | IncOrDecOperator Identifier { ($2, AsgnOp $1, RawNum 1) } + | Identifier IncOrDecOperator { ($1, AsgnOp $2, RawNum 1) } AsgnOp :: { AsgnOp } : "=" { AsgnOpEq } diff --git a/src/Language/SystemVerilog/Parser/ParseDecl.hs b/src/Language/SystemVerilog/Parser/ParseDecl.hs index cb60e52..23be5ea 100644 --- a/src/Language/SystemVerilog/Parser/ParseDecl.hs +++ b/src/Language/SystemVerilog/Parser/ParseDecl.hs @@ -183,7 +183,7 @@ parseDTsAsIntantiations (DTIdent _ name : tokens) = follow = if null toks' then [] else step (tail toks') asRange :: DeclToken -> Range asRange (DTRange _ (NonIndexed, s)) = s - asRange (DTBit _ s) = (Number "0", BinOp Sub s (Number "1")) + asRange (DTBit _ s) = (RawNum 0, BinOp Sub s (RawNum 1)) asRange _ = failure failure = error $ "unrecognized instantiation of " ++ name ++ ": " ++ show inst @@ -439,14 +439,14 @@ takeRanges (token : tokens) = _ -> ([] , token : tokens) where (rs, rest) = takeRanges tokens - asRange s = (Number "0", BinOp Sub s (Number "1")) + asRange s = (RawNum 0, BinOp Sub s (RawNum 1)) autoDim :: [a] -> ([Range], [DeclToken]) autoDim l = ((lo, hi) : rs, rest) where n = length l - lo = Number "0" - hi = Number $ show (n - 1) + lo = RawNum 0 + hi = RawNum $ fromIntegral $ n - 1 -- Matching `AsgnOpEq` and `AsgnOpNonBlocking` here allows tripLookahead to work -- both for standard declarations and in `parseDTsAsDeclOrStmt`, where we're diff --git a/src/Language/SystemVerilog/Parser/Tokens.hs b/src/Language/SystemVerilog/Parser/Tokens.hs index 20d3f45..ebc6877 100644 --- a/src/Language/SystemVerilog/Parser/Tokens.hs +++ b/src/Language/SystemVerilog/Parser/Tokens.hs @@ -302,6 +302,7 @@ data TokenName | Id_simple | Id_escaped | Id_system + | Lit_real | Lit_number | Lit_string | Lit_time diff --git a/sv2v.cabal b/sv2v.cabal index 62e1074..e0df76e 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -43,6 +43,7 @@ executable sv2v Language.SystemVerilog.AST.GenItem Language.SystemVerilog.AST.LHS Language.SystemVerilog.AST.ModuleItem + Language.SystemVerilog.AST.Number Language.SystemVerilog.AST.Op Language.SystemVerilog.AST.ShowHelp Language.SystemVerilog.AST.Stmt @@ -64,6 +65,7 @@ executable sv2v Convert.DuplicateGenvar Convert.EmptyArgs Convert.Enum + Convert.ExprUtils Convert.ForDecl Convert.Foreach Convert.FuncRet diff --git a/test/basic/dimensions.sv b/test/basic/dimensions.sv index ef9af85..50e0b61 100644 --- a/test/basic/dimensions.sv +++ b/test/basic/dimensions.sv @@ -25,6 +25,14 @@ module top; $display($size(Ram[0])); $display($bits(foo)); + $display("args %b", $size(RamPair, 1)); + $display("args %b", $size(RamPair, 1'b1)); + $display("args %b", $size(RamPair, '1)); + $display("args %b", $size(RamPair, 'o1)); + $display("args %b", $size(RamPair, 1'h1)); + $display("args %b", $size(RamPair, 1'd1)); + $display("args %b", $size(RamPair, 1'dx)); + `EXHAUST(Ram); `EXHAUST(Ram[0+:2]); `EXHAUST(Ram[1+:2]); diff --git a/test/basic/dimensions.v b/test/basic/dimensions.v index d77c1cd..f9d38f8 100644 --- a/test/basic/dimensions.v +++ b/test/basic/dimensions.v @@ -5,6 +5,14 @@ module top; $display(16); $display(3); + $display("args %b", 2); + $display("args %b", 2); + $display("args %b", 2); + $display("args %b", 2); + $display("args %b", 2); + $display("args %b", 2); + $display("args %b", 1'bx); + $display(10, 10, 16); $display(0, 0, 16); $display(9, 9, 1); diff --git a/test/basic/div.sv b/test/basic/div.sv new file mode 100644 index 0000000..e8eca02 --- /dev/null +++ b/test/basic/div.sv @@ -0,0 +1,8 @@ +module top; + localparam X = 1 / 0; + localparam Y = 'dx; + localparam Z = 40'dx____; + initial $display("%b", X); + initial $display("%b", Y); + initial $display("%b", Z); +endmodule diff --git a/test/basic/div.v b/test/basic/div.v new file mode 100644 index 0000000..40d6d89 --- /dev/null +++ b/test/basic/div.v @@ -0,0 +1 @@ +`include "div.sv" diff --git a/test/lex/number.sv b/test/lex/number.sv new file mode 100644 index 0000000..fb8a3a8 --- /dev/null +++ b/test/lex/number.sv @@ -0,0 +1,41 @@ +`define TEST(N) \ + $display(`"N -> %0d %b`", N, N); \ + $display(`"$bits(N) -> %0d`", $bits(N)); + +module top; + initial begin + `TEST(0) `TEST(1) `TEST(2) + `TEST(-0) `TEST(-1) `TEST(-2) + `TEST('d0) `TEST('d1) `TEST('d2) + `TEST('sd0) `TEST('sd1) `TEST('sd2) + `TEST('b0) `TEST('b1) `TEST('b10) + `TEST('sd0) `TEST('sd1) `TEST('sd2) + `TEST(1'sox) `TEST(2'sox) `TEST(3'sox) `TEST(7'sox) `TEST(8'sox) `TEST(9'sox) `TEST(9'soxx) `TEST(10'soxx) + `TEST(1'soz) `TEST(2'soz) `TEST(3'soz) `TEST(7'soz) `TEST(8'soz) `TEST(9'soz) `TEST(9'sozz) `TEST(10'sozz) + `TEST(1'SOZ) `TEST(2'SOZ) `TEST(3'SOZ) `TEST(7'SOZ) `TEST(8'SOZ) `TEST(9'SOZ) `TEST(9'SOZZ) `TEST(10'SOZZ) + + `TEST(1234_5678) `TEST('h1234_5678) `TEST('o1234_5677) `TEST('b0101_1100) + `TEST('d4294967295) `TEST('d4294967296) `TEST('d4294967297) `TEST('d4294967298) `TEST('d4294967299) + `TEST('d004294967295) `TEST('d004294967296) `TEST('d004294967297) `TEST('d004294967298) `TEST('d004294967299) + + `TEST(4294967295) `TEST(4294967296) `TEST(4294967297) `TEST(4294967298) `TEST(4294967299) + `TEST(-4294967295) `TEST(-4294967297) `TEST(-4294967298) `TEST(-4294967299) + `TEST(-8589934593) `TEST(8589934592) `TEST(8589934593) + // iverlog does weird things with these: `TEST(-4294967296) `TEST(-8589934592) + + `TEST(659) `TEST('h 837FF) `TEST('o7460) + `TEST(4'b1001) `TEST(5 'D 3) `TEST(3'b01x) `TEST(12'hx) `TEST(16'hz) + `TEST(-8 'd 6) `TEST(4 'shf) `TEST(-4 'sd15) `TEST(16'sd?) + + `TEST('bx) `TEST('bz) `TEST('bzx) `TEST('bxz) + `TEST(3'bx) `TEST(3'b1x) `TEST(3'bx1) `TEST('b1x) `TEST('bx1) `TEST(3'b0x1) `TEST(3'b0z1) + `TEST('hf & 10'hf) `TEST(7'hf & 10'hf) + + `TEST('b01xz01xz01xz01xz01xz01xz01xz01xz01xz) `TEST('b101xz01xz01xz01xz01xz01xz01xz01xz01xz) + `TEST(36'b01xz01xz01xz01xz01xz01xz01xz01xz01xz) `TEST(37'b01xz01xz01xz01xz01xz01xz01xz01xz01xz) + `TEST(36'sb01xz01xz01xz01xz01xz01xz01xz01xz01xz) `TEST(37'sb01xz01xz01xz01xz01xz01xz01xz01xz01xz) + `TEST('h01xz01xz) `TEST('h101xz01xz) + `TEST(36'h01xz01xz) `TEST(37'h01xz01xz) + `TEST(36'hb01xz01xz) `TEST(37'hb01xz01xz) + end +endmodule diff --git a/test/lex/number.v b/test/lex/number.v new file mode 100644 index 0000000..2dc2720 --- /dev/null +++ b/test/lex/number.v @@ -0,0 +1 @@ +`include "number.sv"