UnpackedArray.hs 4.54 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

14
import Control.Monad.State.Strict
15
import qualified Data.Map.Strict as Map
16

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

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

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

convertDescription :: Description -> Description
29 30
convertDescription description@(Part _ _ Module _ _ ports _) =
    partScoper (rewriteDeclM locations) return return return description
31
    where
32
        locations = execState (operation description) Map.empty
33
        operation = partScoperT
34
            (traverseDeclM ports) traverseModuleItemM return traverseStmtM
35
convertDescription other = other
36

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

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

traverseModuleItemM :: ModuleItem -> ST ModuleItem
68 69 70 71 72 73
traverseModuleItemM item@(Instance _ _ _ _ bindings) =
    mapM_ (flatUsageM . snd) bindings >> return item
traverseModuleItemM item =
    traverseLHSsM traverseLHSM item
    >>= traverseExprsM traverseExprM
    >>= traverseAsgnsM traverseAsgnM
74 75

traverseStmtM :: Stmt -> ST Stmt
76 77 78
traverseStmtM =
    traverseStmtLHSsM  traverseLHSM  >=>
    traverseStmtExprsM traverseExprM >=>
79 80 81 82
    traverseStmtAsgnsM traverseAsgnM >=>
    traverseStmtArgsM

traverseStmtArgsM :: Stmt -> ST Stmt
83
traverseStmtArgsM stmt@(Subroutine (Ident ('$' : _)) _) =
84
    return stmt
85
traverseStmtArgsM stmt@(Subroutine _ (Args args [])) =
86 87
    mapM_ flatUsageM args >> return stmt
traverseStmtArgsM stmt = return stmt
88 89

traverseExprM :: Expr -> ST Expr
90 91
traverseExprM (Range x mode i) =
    flatUsageM x >> return (Range x mode i)
92 93 94
traverseExprM expr = traverseExprArgsM expr

traverseExprArgsM :: Expr -> ST Expr
95 96
traverseExprArgsM expr@(Call _ (Args args [])) =
    mapM_ (traverseExprArgsM >=> flatUsageM) args >> return expr
97 98
traverseExprArgsM expr =
    traverseSinglyNestedExprsM traverseExprArgsM expr
99 100

traverseLHSM :: LHS -> ST LHS
101
traverseLHSM x = flatUsageM x >> return x
102

103
traverseAsgnM :: (LHS, Expr) -> ST (LHS, Expr)
104
traverseAsgnM (x, Mux cond y z) = do
105 106 107
    flatUsageM x
    flatUsageM y
    flatUsageM z
108 109
    return (x, Mux cond y z)
traverseAsgnM (x, y) = do
110 111
    flatUsageM x
    flatUsageM y
112
    return (x, y)
113

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
class ScopeKey t => Key t where
    unbit :: t -> (t, Int)

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)

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 ()
flatUsageM k = do
    let (k', depth) = unbit k
    details <- lookupElemM k'
138
    case details of
139
        Just (accesses, _, ()) -> do
140
            let location = map accessName accesses
141
            lift $ modify $ Map.insertWith min location depth
142
        Nothing -> return ()