2019-02-22 02:12:34 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
2019-09-27 04:47:36 +02:00
|
|
|
- Conversion for flattening variables with multiple packed dimensions
|
2019-02-22 02:12:34 +01:00
|
|
|
-
|
2019-09-27 04:47:36 +02:00
|
|
|
- This removes one packed dimension per identifier per pass. This works fine
|
|
|
|
|
- because all conversions are repeatedly applied.
|
2019-02-22 02:12:34 +01:00
|
|
|
-
|
2019-04-09 03:28:33 +02:00
|
|
|
- We previously had a very complex conversion which used `generate` to make
|
|
|
|
|
- flattened and unflattened versions of the array as necessary. This has now
|
|
|
|
|
- been "simplified" to always flatten the array, and then rewrite all usages of
|
|
|
|
|
- the array as appropriate.
|
2019-03-01 01:48:58 +01:00
|
|
|
-
|
2019-09-27 04:47:36 +02:00
|
|
|
- A previous iteration of this conversion aggressively flattened all dimensions
|
|
|
|
|
- (even if unpacked) in any multidimensional data declaration. This had the
|
|
|
|
|
- unfortunate side effect of packing memories, which could hinder efficient
|
|
|
|
|
- synthesis. Now this conversion only flattens packed dimensions and leaves the
|
|
|
|
|
- (only potentially necessary) movement of dimensions from unpacked to packed
|
|
|
|
|
- to the separate UnpackedArray conversion.
|
|
|
|
|
-
|
2019-04-09 03:28:33 +02:00
|
|
|
- Note that the ranges being combined may not be of the form [hi:lo], and need
|
2019-04-18 02:05:55 +02:00
|
|
|
- not even be the same direction! Because of this, we have to flip around the
|
|
|
|
|
- indices of certain accesses.
|
2019-02-22 02:12:34 +01:00
|
|
|
-}
|
|
|
|
|
|
2019-09-27 04:47:36 +02:00
|
|
|
module Convert.MultiplePacked (convert) where
|
2019-02-22 02:12:34 +01:00
|
|
|
|
2019-02-28 06:16:53 +01:00
|
|
|
import Control.Monad.State
|
2019-04-05 01:40:19 +02:00
|
|
|
import Data.Tuple (swap)
|
2019-09-27 04:47:36 +02:00
|
|
|
import Data.Maybe (isJust, fromJust)
|
2019-02-22 02:12:34 +01:00
|
|
|
import qualified Data.Map.Strict as Map
|
|
|
|
|
|
2019-02-28 06:16:53 +01:00
|
|
|
import Convert.Traverse
|
2019-02-22 02:12:34 +01:00
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
2019-11-20 05:15:22 +01:00
|
|
|
type TypeInfo = (Type, [Range])
|
|
|
|
|
type Info = Map.Map Identifier TypeInfo
|
2019-04-18 02:05:55 +02:00
|
|
|
|
2019-04-24 00:44:45 +02:00
|
|
|
convert :: [AST] -> [AST]
|
|
|
|
|
convert = map $ traverseDescriptions convertDescription
|
2019-02-22 02:12:34 +01:00
|
|
|
|
|
|
|
|
convertDescription :: Description -> Description
|
2019-04-19 19:32:25 +02:00
|
|
|
convertDescription =
|
2019-09-27 04:47:36 +02:00
|
|
|
scopedConversion traverseDeclM traverseModuleItemM traverseStmtM Map.empty
|
2019-02-22 02:12:34 +01:00
|
|
|
|
2019-09-27 04:47:36 +02:00
|
|
|
-- collects and converts declarations with multiple packed dimensions
|
2019-04-18 21:51:39 +02:00
|
|
|
traverseDeclM :: Decl -> State Info Decl
|
2019-08-29 04:32:36 +02:00
|
|
|
traverseDeclM (Variable dir t ident a me) = do
|
2019-09-27 04:47:36 +02:00
|
|
|
t' <- traverseTypeM t a ident
|
|
|
|
|
return $ Variable dir t' ident a me
|
2019-09-07 04:29:14 +02:00
|
|
|
traverseDeclM (Param s t ident e) = do
|
2019-09-27 04:47:36 +02:00
|
|
|
t' <- traverseTypeM t [] ident
|
2019-09-07 04:29:14 +02:00
|
|
|
return $ Param s t' ident e
|
2020-01-31 04:17:17 +01:00
|
|
|
traverseDeclM other = return other
|
2019-08-07 05:11:06 +02:00
|
|
|
|
2019-09-27 04:47:36 +02:00
|
|
|
traverseTypeM :: Type -> [Range] -> Identifier -> State Info Type
|
|
|
|
|
traverseTypeM t a ident = do
|
2019-11-20 05:15:22 +01:00
|
|
|
modify $ Map.insert ident (t, a)
|
|
|
|
|
t' <- case t of
|
|
|
|
|
Struct pk fields rs -> do
|
|
|
|
|
fields' <- flattenFields fields
|
|
|
|
|
return $ Struct pk fields' rs
|
|
|
|
|
Union pk fields rs -> do
|
|
|
|
|
fields' <- flattenFields fields
|
|
|
|
|
return $ Union pk fields' rs
|
|
|
|
|
_ -> return t
|
|
|
|
|
let (tf, rs) = typeRanges t'
|
2019-04-18 21:51:39 +02:00
|
|
|
if length rs <= 1
|
2019-11-20 05:15:22 +01:00
|
|
|
then return t'
|
2019-04-18 21:51:39 +02:00
|
|
|
else do
|
|
|
|
|
let r1 : r2 : rest = rs
|
|
|
|
|
let rs' = (combineRanges r1 r2) : rest
|
2019-08-07 05:11:06 +02:00
|
|
|
return $ tf rs'
|
2019-11-20 05:15:22 +01:00
|
|
|
where
|
|
|
|
|
flattenFields fields = do
|
|
|
|
|
let (fieldTypes, fieldNames) = unzip fields
|
|
|
|
|
fieldTypes' <- mapM (\x -> traverseTypeM x [] "") fieldTypes
|
|
|
|
|
return $ zip fieldTypes' fieldNames
|
2019-04-18 02:05:55 +02:00
|
|
|
|
|
|
|
|
-- combines two ranges into one flattened range
|
|
|
|
|
combineRanges :: Range -> Range -> Range
|
|
|
|
|
combineRanges r1 r2 = r
|
2019-02-22 02:12:34 +01:00
|
|
|
where
|
2019-04-18 02:05:55 +02:00
|
|
|
rYY = combine r1 r2
|
|
|
|
|
rYN = combine r1 (swap r2)
|
|
|
|
|
rNY = combine (swap r1) r2
|
|
|
|
|
rNN = combine (swap r1) (swap r2)
|
2019-04-05 19:53:52 +02:00
|
|
|
rY = endianCondRange r2 rYY rYN
|
|
|
|
|
rN = endianCondRange r2 rNY rNN
|
2019-04-09 03:28:33 +02:00
|
|
|
r = endianCondRange r1 rY rN
|
2019-04-05 01:40:19 +02:00
|
|
|
|
2019-04-18 02:05:55 +02:00
|
|
|
combine :: Range -> Range -> Range
|
|
|
|
|
combine (s1, e1) (s2, e2) =
|
|
|
|
|
(simplify upper, simplify lower)
|
|
|
|
|
where
|
|
|
|
|
size1 = rangeSize (s1, e1)
|
|
|
|
|
size2 = rangeSize (s2, e2)
|
|
|
|
|
lower = BinOp Add e2 (BinOp Mul e1 size2)
|
|
|
|
|
upper = BinOp Add (BinOp Mul size1 size2)
|
|
|
|
|
(BinOp Sub lower (Number "1"))
|
2019-02-22 02:12:34 +01:00
|
|
|
|
2019-04-18 21:51:39 +02:00
|
|
|
traverseModuleItemM :: ModuleItem -> State Info ModuleItem
|
|
|
|
|
traverseModuleItemM item =
|
|
|
|
|
traverseLHSsM traverseLHSM item >>=
|
|
|
|
|
traverseExprsM traverseExprM
|
|
|
|
|
|
|
|
|
|
traverseStmtM :: Stmt -> State Info Stmt
|
|
|
|
|
traverseStmtM stmt =
|
|
|
|
|
traverseStmtLHSsM traverseLHSM stmt >>=
|
|
|
|
|
traverseStmtExprsM traverseExprM
|
|
|
|
|
|
|
|
|
|
traverseExprM :: Expr -> State Info Expr
|
|
|
|
|
traverseExprM = traverseNestedExprsM $ stately traverseExpr
|
|
|
|
|
|
2019-09-27 04:47:36 +02:00
|
|
|
-- LHSs need to be converted too. Rather than duplicating the procedures, we
|
|
|
|
|
-- turn LHSs into expressions temporarily and use the expression conversion.
|
2019-04-18 21:51:39 +02:00
|
|
|
traverseLHSM :: LHS -> State Info LHS
|
2019-09-27 04:47:36 +02:00
|
|
|
traverseLHSM lhs = do
|
|
|
|
|
let expr = lhsToExpr lhs
|
|
|
|
|
expr' <- traverseExprM expr
|
|
|
|
|
return $ fromJust $ exprToLHS expr'
|
2019-04-18 21:51:39 +02:00
|
|
|
|
|
|
|
|
traverseExpr :: Info -> Expr -> Expr
|
2019-11-20 05:15:22 +01:00
|
|
|
traverseExpr typeMap =
|
2019-04-18 21:51:39 +02:00
|
|
|
rewriteExpr
|
2019-02-22 02:12:34 +01:00
|
|
|
where
|
2019-11-20 05:15:22 +01:00
|
|
|
-- removes the innermost dimensions of the given type information, and
|
|
|
|
|
-- applies the given transformation to the expression
|
|
|
|
|
dropLevel :: (Expr -> Expr) -> (TypeInfo, Expr) -> (TypeInfo, Expr)
|
|
|
|
|
dropLevel nest ((t, a), expr) =
|
|
|
|
|
((tf rs', a'), nest expr)
|
|
|
|
|
where
|
|
|
|
|
(tf, rs) = typeRanges t
|
|
|
|
|
(rs', a') = case (rs, a) of
|
|
|
|
|
([], []) -> ([], [])
|
|
|
|
|
(packed, []) -> (tail packed, [])
|
|
|
|
|
(packed, unpacked) -> (packed, tail unpacked)
|
|
|
|
|
|
|
|
|
|
-- given an expression, returns its type information and a tagged
|
|
|
|
|
-- version of the expression, if possible
|
|
|
|
|
levels :: Expr -> Maybe (TypeInfo, Expr)
|
2019-09-27 04:47:36 +02:00
|
|
|
levels (Ident x) =
|
2019-11-20 05:15:22 +01:00
|
|
|
case Map.lookup x typeMap of
|
|
|
|
|
Just a -> Just (a, Ident $ tag : x)
|
2019-09-27 04:47:36 +02:00
|
|
|
Nothing -> Nothing
|
|
|
|
|
levels (Bit expr a) =
|
|
|
|
|
fmap (dropLevel $ \expr' -> Bit expr' a) (levels expr)
|
|
|
|
|
levels (Range expr a b) =
|
|
|
|
|
fmap (dropLevel $ \expr' -> Range expr' a b) (levels expr)
|
2019-11-20 05:15:22 +01:00
|
|
|
levels (Dot expr x) =
|
|
|
|
|
case levels expr of
|
|
|
|
|
Just ((Struct _ fields [], []), expr') -> dropDot fields expr'
|
|
|
|
|
Just ((Union _ fields [], []), expr') -> dropDot fields expr'
|
|
|
|
|
_ -> Nothing
|
|
|
|
|
where
|
|
|
|
|
dropDot :: [Field] -> Expr -> Maybe (TypeInfo, Expr)
|
|
|
|
|
dropDot fields expr' =
|
|
|
|
|
if Map.member x fieldMap
|
|
|
|
|
then Just ((fieldType, []), Dot expr' x)
|
|
|
|
|
else Nothing
|
|
|
|
|
where
|
|
|
|
|
fieldMap = Map.fromList $ map swap fields
|
|
|
|
|
fieldType = fieldMap Map.! x
|
2019-09-27 04:47:36 +02:00
|
|
|
levels _ = Nothing
|
|
|
|
|
|
|
|
|
|
-- given an expression, returns the two innermost packed dimensions and a
|
|
|
|
|
-- tagged version of the expression, if possible
|
|
|
|
|
dims :: Expr -> Maybe (Range, Range, Expr)
|
|
|
|
|
dims expr =
|
|
|
|
|
case levels expr of
|
2019-11-20 05:15:22 +01:00
|
|
|
Just ((t, []), expr') ->
|
|
|
|
|
case snd $ typeRanges t of
|
|
|
|
|
dimInner : dimOuter : _ ->
|
|
|
|
|
Just (dimInner, dimOuter, expr')
|
|
|
|
|
_ -> Nothing
|
2019-09-27 04:47:36 +02:00
|
|
|
_ -> Nothing
|
2019-03-01 01:48:58 +01:00
|
|
|
|
2019-04-18 02:05:55 +02:00
|
|
|
-- if the given range is flipped, the result will flip around the given
|
|
|
|
|
-- indexing expression
|
2019-04-09 03:28:33 +02:00
|
|
|
orientIdx :: Range -> Expr -> Expr
|
|
|
|
|
orientIdx r e =
|
|
|
|
|
endianCondExpr r e eSwapped
|
|
|
|
|
where
|
|
|
|
|
eSwapped = BinOp Sub (snd r) (BinOp Sub e (fst r))
|
2019-02-28 23:12:37 +01:00
|
|
|
|
2019-04-18 02:05:55 +02:00
|
|
|
-- Converted idents are prefixed with an invalid character to ensure
|
|
|
|
|
-- that are not converted twice when the traversal steps downward. When
|
|
|
|
|
-- the prefixed identifier is encountered at the lowest level, it is
|
|
|
|
|
-- removed.
|
|
|
|
|
|
|
|
|
|
tag = ':'
|
|
|
|
|
|
2019-02-28 23:12:37 +01:00
|
|
|
rewriteExpr :: Expr -> Expr
|
2019-04-09 03:28:33 +02:00
|
|
|
rewriteExpr (Ident x) =
|
2019-04-18 02:05:55 +02:00
|
|
|
if head x == tag
|
2019-04-09 03:28:33 +02:00
|
|
|
then Ident $ tail x
|
|
|
|
|
else Ident x
|
2019-09-27 04:47:36 +02:00
|
|
|
rewriteExpr (orig @ (Bit (Bit expr idxInner) idxOuter)) =
|
2020-02-17 19:57:48 +01:00
|
|
|
if isJust maybeDims && expr == rewriteExpr expr
|
2019-09-27 04:47:36 +02:00
|
|
|
then Bit expr' idx'
|
2019-04-09 03:28:33 +02:00
|
|
|
else orig
|
2019-03-31 22:43:19 +02:00
|
|
|
where
|
2020-02-17 19:57:48 +01:00
|
|
|
maybeDims = dims expr
|
2019-09-27 04:47:36 +02:00
|
|
|
Just (dimInner, dimOuter, expr') = maybeDims
|
2019-04-09 03:28:33 +02:00
|
|
|
idxInner' = orientIdx dimInner idxInner
|
|
|
|
|
idxOuter' = orientIdx dimOuter idxOuter
|
|
|
|
|
base = BinOp Mul idxInner' (rangeSize dimOuter)
|
|
|
|
|
idx' = simplify $ BinOp Add base idxOuter'
|
2019-09-27 04:47:36 +02:00
|
|
|
rewriteExpr (orig @ (Bit expr idx)) =
|
2020-02-17 19:57:48 +01:00
|
|
|
if isJust maybeDims && expr == rewriteExpr expr
|
2019-09-27 04:47:36 +02:00
|
|
|
then Range expr' mode' range'
|
2019-04-09 03:28:33 +02:00
|
|
|
else orig
|
2019-03-01 01:48:58 +01:00
|
|
|
where
|
2020-02-17 19:57:48 +01:00
|
|
|
maybeDims = dims expr
|
2019-09-27 04:47:36 +02:00
|
|
|
Just (dimInner, dimOuter, expr') = maybeDims
|
2019-04-09 03:28:33 +02:00
|
|
|
mode' = IndexedPlus
|
|
|
|
|
idx' = orientIdx dimInner idx
|
|
|
|
|
len = rangeSize dimOuter
|
|
|
|
|
base = BinOp Add (endianCondExpr dimOuter (snd dimOuter) (fst dimOuter)) (BinOp Mul idx' len)
|
|
|
|
|
range' = (simplify base, simplify len)
|
2020-02-17 19:57:48 +01:00
|
|
|
rewriteExpr (orig @ (Range (Bit expr idxInner) NonIndexed rangeOuter)) =
|
|
|
|
|
if isJust maybeDims && expr == rewriteExpr expr
|
|
|
|
|
then endianCondExpr rangeOuter
|
|
|
|
|
(rewriteExpr $ Range exprOuter IndexedMinus range)
|
|
|
|
|
(rewriteExpr $ Range exprOuter IndexedPlus range)
|
|
|
|
|
else orig
|
|
|
|
|
where
|
|
|
|
|
maybeDims = dims expr
|
|
|
|
|
exprOuter = Bit expr idxInner
|
|
|
|
|
base = fst rangeOuter
|
|
|
|
|
len = rangeSize rangeOuter
|
|
|
|
|
range = (base, len)
|
2019-09-27 04:47:36 +02:00
|
|
|
rewriteExpr (orig @ (Range (Bit expr idxInner) modeOuter rangeOuter)) =
|
2020-02-17 19:57:48 +01:00
|
|
|
if isJust maybeDims && expr == rewriteExpr expr
|
|
|
|
|
then endianCondExpr dimOuter
|
|
|
|
|
(Range expr' modeDec range')
|
|
|
|
|
(Range expr' modeInc range')
|
2019-04-09 03:28:33 +02:00
|
|
|
else orig
|
|
|
|
|
where
|
2020-02-17 19:57:48 +01:00
|
|
|
maybeDims = dims expr
|
2019-09-27 04:47:36 +02:00
|
|
|
Just (dimInner, dimOuter, expr') = maybeDims
|
2019-04-12 00:29:30 +02:00
|
|
|
idxInner' = orientIdx dimInner idxInner
|
2020-02-17 19:57:48 +01:00
|
|
|
(modeDec, modeInc) =
|
2019-04-12 00:29:30 +02:00
|
|
|
case modeOuter of
|
2020-02-17 19:57:48 +01:00
|
|
|
IndexedPlus -> (IndexedPlus , IndexedMinus)
|
|
|
|
|
IndexedMinus -> (IndexedMinus, IndexedPlus )
|
|
|
|
|
NonIndexed -> error "invariant violated"
|
|
|
|
|
(baseOuter, lenOuter) = rangeOuter
|
|
|
|
|
baseOuter' = orientIdx dimOuter baseOuter
|
2019-04-12 00:29:30 +02:00
|
|
|
start = BinOp Mul idxInner' (rangeSize dimOuter)
|
2020-02-17 19:57:48 +01:00
|
|
|
base = simplify $ BinOp Add start baseOuter'
|
2019-04-12 00:29:30 +02:00
|
|
|
len = lenOuter
|
|
|
|
|
range' = (base, len)
|
2020-02-17 19:57:48 +01:00
|
|
|
rewriteExpr (orig @ (Range expr NonIndexed range)) =
|
|
|
|
|
if isJust maybeDims && expr == rewriteExpr expr
|
|
|
|
|
then endianCondExpr range
|
|
|
|
|
(rewriteExpr $ Range expr IndexedMinus range')
|
|
|
|
|
(rewriteExpr $ Range expr IndexedPlus range')
|
|
|
|
|
else orig
|
|
|
|
|
where
|
|
|
|
|
maybeDims = dims expr
|
|
|
|
|
base = fst range
|
|
|
|
|
len = rangeSize range
|
|
|
|
|
range' = (base, len)
|
2019-09-27 04:47:36 +02:00
|
|
|
rewriteExpr (orig @ (Range expr mode range)) =
|
2020-02-17 19:57:48 +01:00
|
|
|
if isJust maybeDims && expr == rewriteExpr expr
|
|
|
|
|
then Range expr' mode range'
|
2019-04-09 03:28:33 +02:00
|
|
|
else orig
|
2019-09-27 04:47:36 +02:00
|
|
|
where
|
2020-02-17 19:57:48 +01:00
|
|
|
maybeDims = dims expr
|
2019-09-27 04:47:36 +02:00
|
|
|
Just (_, dimOuter, expr') = maybeDims
|
2020-02-17 19:57:48 +01:00
|
|
|
sizeOuter = rangeSize dimOuter
|
|
|
|
|
base = BinOp Add (BinOp Mul sizeOuter (fst range)) start
|
|
|
|
|
len = BinOp Mul sizeOuter (snd range)
|
|
|
|
|
range' = (base, len)
|
|
|
|
|
start =
|
2019-09-27 04:47:36 +02:00
|
|
|
case mode of
|
2020-02-17 19:57:48 +01:00
|
|
|
IndexedPlus -> endianCondExpr dimOuter (snd dimOuter) (fst dimOuter)
|
|
|
|
|
IndexedMinus -> endianCondExpr dimOuter (fst dimOuter) (snd dimOuter)
|
|
|
|
|
NonIndexed -> error "invariant violated"
|
2019-09-27 04:47:36 +02:00
|
|
|
rewriteExpr other = other
|