2019-03-23 00:24:45 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
- Initial Verilog AST Author: Tom Hawkins <tomahawkins@gmail.com>
|
|
|
|
|
-
|
|
|
|
|
- SystemVerilog expressions
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Language.SystemVerilog.AST.Expr
|
|
|
|
|
( Expr (..)
|
|
|
|
|
, Range
|
2019-09-09 07:38:14 +02:00
|
|
|
, TypeOrExpr
|
2019-04-04 02:24:09 +02:00
|
|
|
, Args (..)
|
2019-04-05 19:53:52 +02:00
|
|
|
, PartSelectMode (..)
|
2019-03-23 00:24:45 +01:00
|
|
|
, showAssignment
|
|
|
|
|
, showRanges
|
2019-04-04 02:24:09 +02:00
|
|
|
, simplify
|
|
|
|
|
, rangeSize
|
2019-04-05 19:53:52 +02:00
|
|
|
, endianCondExpr
|
|
|
|
|
, endianCondRange
|
2019-04-19 07:02:07 +02:00
|
|
|
, sizedExpr
|
2019-04-19 19:32:25 +02:00
|
|
|
, dimensionsSize
|
2019-03-23 00:24:45 +01:00
|
|
|
) where
|
|
|
|
|
|
|
|
|
|
import Data.List (intercalate)
|
|
|
|
|
import Text.Printf (printf)
|
2019-04-04 02:24:09 +02:00
|
|
|
import Text.Read (readMaybe)
|
2019-03-23 00:24:45 +01:00
|
|
|
|
|
|
|
|
import Language.SystemVerilog.AST.Op
|
|
|
|
|
import Language.SystemVerilog.AST.ShowHelp
|
|
|
|
|
import {-# SOURCE #-} Language.SystemVerilog.AST.Type
|
|
|
|
|
|
|
|
|
|
type Range = (Expr, Expr)
|
|
|
|
|
|
2019-09-09 07:38:14 +02:00
|
|
|
type TypeOrExpr = Either Type Expr
|
|
|
|
|
|
2019-03-23 00:24:45 +01:00
|
|
|
data Expr
|
|
|
|
|
= String String
|
|
|
|
|
| Number String
|
|
|
|
|
| Ident Identifier
|
2019-04-23 21:53:51 +02:00
|
|
|
| PSIdent Identifier Identifier
|
2019-04-05 19:53:52 +02:00
|
|
|
| Range Expr PartSelectMode Range
|
2019-03-23 00:24:45 +01:00
|
|
|
| Bit Expr Expr
|
|
|
|
|
| Repeat Expr [Expr]
|
|
|
|
|
| Concat [Expr]
|
2019-09-02 00:42:13 +02:00
|
|
|
| Stream StreamOp Expr [Expr]
|
2019-04-24 09:37:47 +02:00
|
|
|
| Call (Maybe Identifier) Identifier Args
|
2019-03-23 00:24:45 +01:00
|
|
|
| UniOp UniOp Expr
|
|
|
|
|
| BinOp BinOp Expr Expr
|
|
|
|
|
| Mux Expr Expr Expr
|
2019-09-09 07:38:14 +02:00
|
|
|
| Cast TypeOrExpr Expr
|
|
|
|
|
| Bits TypeOrExpr
|
2019-03-23 00:24:45 +01:00
|
|
|
| Dot Expr Identifier
|
|
|
|
|
| Pattern [(Maybe Identifier, Expr)]
|
2019-09-09 07:38:14 +02:00
|
|
|
| Nil
|
2019-03-23 00:24:45 +01:00
|
|
|
deriving (Eq, Ord)
|
|
|
|
|
|
|
|
|
|
instance Show Expr where
|
2019-09-09 07:38:14 +02:00
|
|
|
show (Nil ) = ""
|
2019-03-23 00:24:45 +01:00
|
|
|
show (Number str ) = str
|
|
|
|
|
show (Ident str ) = str
|
2019-04-24 09:37:47 +02:00
|
|
|
show (PSIdent x y ) = printf "%s::%s" x y
|
2019-03-23 00:24:45 +01:00
|
|
|
show (String str ) = printf "\"%s\"" str
|
|
|
|
|
show (Bit e b ) = printf "%s[%s]" (show e) (show b)
|
2019-04-05 19:53:52 +02:00
|
|
|
show (Range e m r) = printf "%s[%s%s%s]" (show e) (show $ fst r) (show m) (show $ snd r)
|
2019-03-23 00:24:45 +01:00
|
|
|
show (Repeat e l ) = printf "{%s {%s}}" (show e) (commas $ map show l)
|
|
|
|
|
show (Concat l ) = printf "{%s}" (commas $ map show l)
|
2019-09-02 00:42:13 +02:00
|
|
|
show (Stream o e l) = printf "{%s %s%s}" (show o) (show e) (show $ Concat l)
|
2019-03-23 00:24:45 +01:00
|
|
|
show (UniOp a b ) = printf "(%s %s)" (show a) (show b)
|
2019-03-25 19:40:57 +01:00
|
|
|
show (BinOp o a b) = printf "(%s %s %s)" (show a) (show o) (show b)
|
2019-03-23 00:24:45 +01:00
|
|
|
show (Dot e n ) = printf "%s.%s" (show e) n
|
|
|
|
|
show (Mux c a b) = printf "(%s ? %s : %s)" (show c) (show a) (show b)
|
2019-04-24 09:37:47 +02:00
|
|
|
show (Call ps f l) = printf "%s%s(%s)" (maybe "" (++ "::") ps) f (show l)
|
2019-04-02 06:16:06 +02:00
|
|
|
show (Cast tore e ) = printf "%s'(%s)" (showEither tore) (show e)
|
|
|
|
|
show (Bits tore ) = printf "$bits(%s)" (showEither tore)
|
2019-03-23 00:24:45 +01:00
|
|
|
show (Pattern l ) =
|
|
|
|
|
printf "'{\n%s\n}" (indent $ intercalate ",\n" $ map showPatternItem l)
|
|
|
|
|
where
|
|
|
|
|
showPatternItem :: (Maybe Identifier, Expr) -> String
|
|
|
|
|
showPatternItem (Nothing, e) = show e
|
|
|
|
|
showPatternItem (Just n , e) = printf "%s: %s" n (show e)
|
|
|
|
|
|
2019-03-30 06:27:48 +01:00
|
|
|
data Args
|
|
|
|
|
= Args [Maybe Expr] [(Identifier, Maybe Expr)]
|
|
|
|
|
deriving (Eq, Ord)
|
|
|
|
|
|
|
|
|
|
instance Show Args where
|
|
|
|
|
show (Args pnArgs kwArgs) = commas strs
|
|
|
|
|
where
|
|
|
|
|
strs = (map showPnArg pnArgs) ++ (map showKwArg kwArgs)
|
|
|
|
|
showPnArg = maybe "" show
|
2019-03-31 20:08:18 +02:00
|
|
|
showKwArg (x, me) = printf ".%s(%s)" x (showPnArg me)
|
2019-03-30 06:27:48 +01:00
|
|
|
|
2019-04-05 19:53:52 +02:00
|
|
|
data PartSelectMode
|
|
|
|
|
= NonIndexed
|
|
|
|
|
| IndexedPlus
|
|
|
|
|
| IndexedMinus
|
|
|
|
|
deriving (Eq, Ord)
|
|
|
|
|
|
|
|
|
|
instance Show PartSelectMode where
|
|
|
|
|
show NonIndexed = ":"
|
|
|
|
|
show IndexedPlus = "+:"
|
|
|
|
|
show IndexedMinus = "-:"
|
|
|
|
|
|
2019-09-07 04:29:14 +02:00
|
|
|
showAssignment :: Show a => Maybe a -> String
|
2019-03-23 00:24:45 +01:00
|
|
|
showAssignment Nothing = ""
|
|
|
|
|
showAssignment (Just val) = " = " ++ show val
|
|
|
|
|
|
|
|
|
|
showRanges :: [Range] -> String
|
|
|
|
|
showRanges [] = ""
|
|
|
|
|
showRanges l = " " ++ (concatMap showRange l)
|
|
|
|
|
|
|
|
|
|
showRange :: Range -> String
|
|
|
|
|
showRange (h, l) = printf "[%s:%s]" (show h) (show l)
|
2019-04-04 02:24:09 +02:00
|
|
|
|
2019-04-09 03:57:50 +02:00
|
|
|
clog2Help :: Int -> Int -> Int
|
|
|
|
|
clog2Help p n = if p >= n then 0 else 1 + clog2Help (p*2) n
|
|
|
|
|
clog2 :: Int -> Int
|
|
|
|
|
clog2 n = if n < 2 then 0 else clog2Help 1 n
|
|
|
|
|
|
2019-04-09 19:07:43 +02:00
|
|
|
readNumber :: String -> Maybe Int
|
|
|
|
|
readNumber n =
|
|
|
|
|
readMaybe n' :: Maybe Int
|
|
|
|
|
where
|
|
|
|
|
n' = case n of
|
|
|
|
|
'\'' : 'd' : rest -> rest
|
|
|
|
|
_ -> n
|
|
|
|
|
|
2019-04-04 02:24:09 +02:00
|
|
|
-- basic expression simplfication utility to help us generate nicer code in the
|
|
|
|
|
-- common case of ranges like `[FOO-1:0]`
|
|
|
|
|
simplify :: Expr -> Expr
|
2019-09-04 05:36:29 +02:00
|
|
|
simplify (Repeat (Number "0") _) = Concat []
|
|
|
|
|
simplify (Concat [expr]) = expr
|
|
|
|
|
simplify (Concat exprs) =
|
|
|
|
|
Concat $ filter (/= Concat []) exprs
|
2019-04-24 09:37:47 +02:00
|
|
|
simplify (orig @ (Call Nothing "$clog2" (Args [Just (Number n)] []))) =
|
2019-04-09 19:07:43 +02:00
|
|
|
case readNumber n of
|
2019-04-09 03:57:50 +02:00
|
|
|
Nothing -> orig
|
|
|
|
|
Just x -> Number $ show $ clog2 x
|
2019-08-29 05:26:12 +02:00
|
|
|
simplify (Mux (Number "0") e _) = e
|
2019-04-05 01:40:19 +02:00
|
|
|
simplify (Mux (BinOp Ge c1 c2) e1 e2) =
|
|
|
|
|
case (c1', c2') of
|
|
|
|
|
(Number a, Number b) ->
|
2019-04-09 19:07:43 +02:00
|
|
|
case (readNumber a, readNumber b) of
|
2019-04-05 01:40:19 +02:00
|
|
|
(Just x, Just y) ->
|
|
|
|
|
if x >= y
|
|
|
|
|
then e1
|
|
|
|
|
else e2
|
|
|
|
|
_ -> nochange
|
|
|
|
|
_ -> nochange
|
|
|
|
|
where
|
|
|
|
|
c1' = simplify c1
|
|
|
|
|
c2' = simplify c2
|
|
|
|
|
e1' = simplify e1
|
|
|
|
|
e2' = simplify e2
|
|
|
|
|
nochange = Mux (BinOp Ge c1' c2') e1' e2'
|
2019-08-31 02:34:56 +02:00
|
|
|
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 Add (BinOp Sub (Number n1) e) (Number n2)) =
|
|
|
|
|
case (readNumber n1, readNumber n2) of
|
|
|
|
|
(Just x, Just y) ->
|
|
|
|
|
simplify $ BinOp Sub (Number $ show (x + y)) e'
|
|
|
|
|
_ -> nochange
|
|
|
|
|
where
|
|
|
|
|
e' = simplify e
|
|
|
|
|
nochange = BinOp Add (BinOp Sub (Number n1) e') (Number n2)
|
2019-04-04 02:24:09 +02:00
|
|
|
simplify (BinOp op e1 e2) =
|
|
|
|
|
case (op, e1', e2') of
|
|
|
|
|
(Add, Number "0", e) -> e
|
|
|
|
|
(Add, e, Number "0") -> e
|
2019-04-09 03:57:50 +02:00
|
|
|
(Mul, _, Number "0") -> Number "0"
|
|
|
|
|
(Mul, Number "0", _) -> Number "0"
|
|
|
|
|
(Mul, e, Number "1") -> e
|
|
|
|
|
(Mul, Number "1", e) -> e
|
2019-04-04 02:24:09 +02:00
|
|
|
(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) ->
|
2019-04-09 19:07:43 +02:00
|
|
|
case (op, readNumber a, readNumber b) of
|
2019-04-04 02:24:09 +02:00
|
|
|
(Add, Just x, Just y) -> Number $ show (x + y)
|
|
|
|
|
(Sub, Just x, Just y) -> Number $ show (x - y)
|
|
|
|
|
(Mul, Just x, Just y) -> Number $ show (x * y)
|
2019-04-09 19:07:43 +02:00
|
|
|
(Div, Just _, Just 0) -> Number "x"
|
|
|
|
|
(Div, Just x, Just y) -> Number $ show (x `quot` y)
|
2019-04-04 02:24:09 +02:00
|
|
|
_ -> BinOp op e1' e2'
|
2019-04-05 01:40:19 +02:00
|
|
|
(Add, BinOp Add e (Number a), Number b) ->
|
2019-04-09 19:07:43 +02:00
|
|
|
case (readNumber a, readNumber b) of
|
2019-04-05 01:40:19 +02:00
|
|
|
(Just x, Just y) -> BinOp Add e $ Number $ show (x + y)
|
|
|
|
|
_ -> BinOp op e1' e2'
|
2019-04-04 02:24:09 +02:00
|
|
|
_ -> BinOp op e1' e2'
|
|
|
|
|
where
|
|
|
|
|
e1' = simplify e1
|
|
|
|
|
e2' = simplify e2
|
|
|
|
|
simplify other = other
|
|
|
|
|
|
|
|
|
|
rangeSize :: Range -> Expr
|
|
|
|
|
rangeSize (s, e) =
|
2019-04-09 03:28:33 +02:00
|
|
|
endianCondExpr (s, e) a b
|
|
|
|
|
where
|
|
|
|
|
a = simplify $ BinOp Add (BinOp Sub s e) (Number "1")
|
|
|
|
|
b = simplify $ BinOp Add (BinOp Sub e s) (Number "1")
|
2019-04-05 19:53:52 +02:00
|
|
|
|
|
|
|
|
-- 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)
|
|
|
|
|
)
|
2019-04-19 07:02:07 +02:00
|
|
|
|
|
|
|
|
-- attempts to make a number literal have an explicit size
|
|
|
|
|
sizedExpr :: Identifier -> Range -> Expr -> Expr
|
|
|
|
|
sizedExpr x r (Number n) =
|
|
|
|
|
if size /= show resSize
|
|
|
|
|
then error $ "literal " ++ show n ++ " for " ++ show x
|
|
|
|
|
++ " doesn't have size " ++ show size
|
|
|
|
|
else Number res
|
|
|
|
|
where
|
|
|
|
|
Number size = simplify $ rangeSize r
|
|
|
|
|
unticked = case n of
|
|
|
|
|
'\'' : rest -> rest
|
|
|
|
|
rest -> rest
|
|
|
|
|
resSize = (read $ takeWhile (/= '\'') res) :: Int
|
|
|
|
|
res = case readMaybe unticked :: Maybe Int of
|
|
|
|
|
Nothing ->
|
|
|
|
|
if unticked == n
|
|
|
|
|
then n
|
|
|
|
|
else size ++ n
|
|
|
|
|
Just num -> size ++ "'d" ++ show num
|
|
|
|
|
sizedExpr _ _ e = e
|
2019-04-19 19:32:25 +02:00
|
|
|
|
|
|
|
|
dimensionsSize :: [Range] -> Expr
|
|
|
|
|
dimensionsSize ranges =
|
|
|
|
|
simplify $
|
|
|
|
|
foldl (BinOp Mul) (Number "1") $
|
|
|
|
|
map rangeSize $
|
|
|
|
|
ranges
|