UnpackedArray.hs 4.76 KB
Newer Older
1
{-# LANGUAGE FlexibleInstances #-}
2 3 4 5
{- sv2v
 - Author: Zachary Snow <zach@zachjs.com>
 -
 - Conversion for any unpacked array which must be packed because it is: A) a
6
 - port; B) is bound to a port; C) is assigned a value in a single assignment;
7 8 9
 - or D) is assigned to an unpacked array which itself must be packed. The
 - conversion allows for an array to be partially packed if all flat usages of
 - the array explicitly specify some of the unpacked dimensions.
10 11 12 13
 -}

module Convert.UnpackedArray (convert) where

Zachary Snow committed
14
import Control.Monad (when, (>=>))
15
import Control.Monad.State.Strict
16
import qualified Data.Map.Strict as Map
17

18
import Convert.Scoper
19 20 21
import Convert.Traverse
import Language.SystemVerilog.AST

22
type Location = [Identifier]
23
type Locations = Map.Map Location Int
24
type ST = ScoperT () (State Locations)
25 26 27 28 29

convert :: [AST] -> [AST]
convert = map $ traverseDescriptions convertDescription

convertDescription :: Description -> Description
30
convertDescription description@(Part _ _ Module _ _ ports _) =
31
    evalScoper $ scopePart conScoper description
32
    where
33 34 35
        locations = execState
            (evalScoperT $ scopePart locScoper description) Map.empty
        locScoper = scopeModuleItem
36
            (traverseDeclM ports) traverseModuleItemM return traverseStmtM
37 38
        conScoper = scopeModuleItem
            (rewriteDeclM locations) return return return
39
convertDescription other = other
40

41
-- tracks multi-dimensional unpacked array declarations
42
traverseDeclM :: [Identifier] -> Decl -> ST Decl
43
traverseDeclM _ decl@(Variable _ _ _ [] e) =
44
    traverseExprArgsM e >> return decl
45 46 47 48
traverseDeclM ports decl@(Variable dir _ x _ e) = do
    insertElem x ()
    when (dir /= Local || elem x ports || e /= Nil) $
        flatUsageM x
49
    traverseExprArgsM e >> return decl
50
traverseDeclM ports decl@Net{} =
51
    traverseNetAsVarM (traverseDeclM ports) decl
52
traverseDeclM _ other = return other
53

54
-- pack decls marked for packing
55 56 57 58
rewriteDeclM :: Locations -> Decl -> Scoper () Decl
rewriteDeclM _ decl@(Variable _ _ _ [] _) = return decl
rewriteDeclM locations decl@(Variable d t x a e) = do
    accesses <- localAccessesM x
59
    let location = map accessName accesses
60
    case Map.lookup location locations of
61
        Just depth -> do
62
            let (tf, rs) = typeRanges t
63 64 65
            let (unpacked, packed) = splitAt depth a
            let t' = tf $ packed ++ rs
            return $ Variable d t' x unpacked e
66
        Nothing -> return decl
67 68 69
rewriteDeclM locations decl@Net{} =
    traverseNetAsVarM (rewriteDeclM locations) decl
rewriteDeclM _ other = return other
70 71

traverseModuleItemM :: ModuleItem -> ST ModuleItem
72 73 74 75 76 77
traverseModuleItemM item@(Instance _ _ _ _ bindings) =
    mapM_ (flatUsageM . snd) bindings >> return item
traverseModuleItemM item =
    traverseLHSsM traverseLHSM item
    >>= traverseExprsM traverseExprM
    >>= traverseAsgnsM traverseAsgnM
78 79

traverseStmtM :: Stmt -> ST Stmt
80 81 82
traverseStmtM =
    traverseStmtLHSsM  traverseLHSM  >=>
    traverseStmtExprsM traverseExprM >=>
83 84 85 86
    traverseStmtAsgnsM traverseAsgnM >=>
    traverseStmtArgsM

traverseStmtArgsM :: Stmt -> ST Stmt
87
traverseStmtArgsM stmt@(Subroutine (Ident ('$' : _)) _) =
88
    return stmt
89
traverseStmtArgsM stmt@(Subroutine _ (Args args [])) =
90 91
    mapM_ flatUsageM args >> return stmt
traverseStmtArgsM stmt = return stmt
92 93

traverseExprM :: Expr -> ST Expr
94 95
traverseExprM (Range x mode i) =
    flatUsageM x >> return (Range x mode i)
96 97 98
traverseExprM expr = traverseExprArgsM expr

traverseExprArgsM :: Expr -> ST Expr
99 100
traverseExprArgsM expr@(Call _ (Args args [])) =
    mapM_ (traverseExprArgsM >=> flatUsageM) args >> return expr
101 102
traverseExprArgsM expr =
    traverseSinglyNestedExprsM traverseExprArgsM expr
103 104

traverseLHSM :: LHS -> ST LHS
105
traverseLHSM x = flatUsageM x >> return x
106

107
traverseAsgnM :: (LHS, Expr) -> ST (LHS, Expr)
108
traverseAsgnM (x, y) = do
109 110
    flatUsageM x
    flatUsageM y
111
    return (x, y)
112

113 114
class ScopeKey t => Key t where
    unbit :: t -> (t, Int)
115 116
    split :: t -> Maybe (t, t)
    split = const Nothing
117 118 119 120 121 122 123

instance Key Expr where
    unbit (Bit e _) = (e', n + 1)
        where (e', n) = unbit e
    unbit (Range e _ _) = (e', n)
        where (e', n) = unbit e
    unbit e = (e, 0)
124
    split (MuxA _ _ a b) = Just (a, b)
125
    split _ = Nothing
126 127 128 129 130 131 132 133 134 135 136 137

instance Key LHS where
    unbit (LHSBit e _) = (e', n + 1)
        where (e', n) = unbit e
    unbit (LHSRange e _ _) = (e', n)
        where (e', n) = unbit e
    unbit e = (e, 0)

instance Key Identifier where
    unbit x = (x, 0)

flatUsageM :: Key k => k -> ST ()
138 139
flatUsageM k | Just (a, b) <- split k =
    flatUsageM a >> flatUsageM b
140 141 142
flatUsageM k = do
    let (k', depth) = unbit k
    details <- lookupElemM k'
143
    case details of
144
        Just (accesses, _, ()) -> do
145
            let location = map accessName accesses
146
            lift $ modify $ Map.insertWith min location depth
147
        Nothing -> return ()