Commit 9a38225b by Zachary Snow

several major fixes surrounding packed arrays

- entirely new PackedArray conversion (always flattens)
- typedef and struct correctly order packed ranges when combining types
- Stmt LHS traversal no longer traverses nested statements to avoid double conversion
- Logic conversion applies to `initial` blocks`
- new and modified tests to cover these cases
parent fb3d68e3
...@@ -57,7 +57,7 @@ convertDescription orig = ...@@ -57,7 +57,7 @@ convertDescription orig =
regIdents :: ModuleItem -> Writer RegIdents () regIdents :: ModuleItem -> Writer RegIdents ()
regIdents (AlwaysC _ stmt) = regIdents (AlwaysC _ stmt) =
collectStmtLHSsM (collectNestedLHSsM idents) $ collectNestedStmtsM (collectStmtLHSsM (collectNestedLHSsM idents)) $
traverseNestedStmts removeTimings stmt traverseNestedStmts removeTimings stmt
where where
idents :: LHS -> Writer RegIdents () idents :: LHS -> Writer RegIdents ()
...@@ -66,4 +66,6 @@ regIdents (AlwaysC _ stmt) = ...@@ -66,4 +66,6 @@ regIdents (AlwaysC _ stmt) =
removeTimings :: Stmt -> Stmt removeTimings :: Stmt -> Stmt
removeTimings (Timing _ s) = s removeTimings (Timing _ s) = s
removeTimings other = other removeTimings other = other
regIdents (Initial stmt) =
regIdents $ AlwaysC Always stmt
regIdents _ = return () regIdents _ = return ()
...@@ -6,83 +6,57 @@ ...@@ -6,83 +6,57 @@
- This removes one dimension per identifier at a time. This works fine because - This removes one dimension per identifier at a time. This works fine because
- the conversions are repeatedly applied. - the conversions are repeatedly applied.
- -
- Packed arrays can be used in any of the following ways: A) as a whole, - We previously had a very complex conversion which used `generate` to make
- including as a port; B) with an index (`foo[0]`); or C) with a range - flattened and unflattened versions of the array as necessary. This has now
- (`foo[10:0]`). The rules for this conversion are: - been "simplified" to always flatten the array, and then rewrite all usages of
- 1. If used with an index, then we must have an unflattened/unpacked - the array as appropriate.
- version of that array after the conversion, so that we may get at the
- packed sub-arrays.
- 2. If used as a whole or with a range, then we must have a flattened
- version of that array after the conversion, so that we may get at a
- contiguous sequence of elements.
- 3. If both 1 and 2 apply, then we will make a fancy generate block to
- derive one from the other. The derivation direction is decided based on
- which version, if any, is exposed directly as a port.
- -
- Note: We don't count usages with an index in expressions as such, as those - Note that the ranges being combined may not be of the form [hi:lo], and need
- usages could be equivalently converted to range accesses with some added in - not even be the same direction! Because of this, we have to flip arround
- multiplication. - the indices of certain accesses.
-
- TODO: Name conflicts between functions/tasks and the description that
- contains them likely breaks this conversion.
-} -}
module Convert.PackedArray (convert) where module Convert.PackedArray (convert) where
import Control.Monad.State import Control.Monad.State
import Data.List (partition)
import Data.Tuple (swap) import Data.Tuple (swap)
import qualified Data.Set as Set
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import Convert.Traverse import Convert.Traverse
import Language.SystemVerilog.AST import Language.SystemVerilog.AST
type DirMap = Map.Map Identifier Direction
type DimMap = Map.Map Identifier (Type, Range) type DimMap = Map.Map Identifier (Type, Range)
type IdentSet = Set.Set Identifier
data Info = Info data Info = Info
{ sTypeDims :: DimMap { sTypeDims :: DimMap
, sPortDirs :: DirMap } deriving Show
, sIdxUses :: IdentSet
, sSeqUses :: IdentSet }
deriving Show
convert :: AST -> AST convert :: AST -> AST
convert = traverseDescriptions convertDescription convert = traverseDescriptions convertDescription
convertDescription :: Description -> Description convertDescription :: Description -> Description
convertDescription (description @ (Part _ _ _ _ _ _)) = convertDescription (description @ (Part _ _ _ _ _ _)) =
hoistPortDecls $
traverseModuleItems (flattenModuleItem info . rewriteModuleItem info) description traverseModuleItems (flattenModuleItem info . rewriteModuleItem info) description
where where
-- collect all possible information info our Info structure -- collect all possible information info our Info structure
rawInfo = info =
execState (collectModuleItemsM (collectLHSsM collectLHS) description) $
execState (collectModuleItemsM (collectExprsM collectExpr) description) $
execState (collectModuleItemsM collectDecl description) $ execState (collectModuleItemsM collectDecl description) $
execState (collectModuleItemsM collectTF description) $ execState (collectModuleItemsM collectTF description) $
(Info Map.empty Map.empty Set.empty Set.empty) (Info Map.empty)
relevantIdents = Map.keysSet $ sTypeDims rawInfo
-- restrict the sets/maps to only contain keys which need transformation
info = rawInfo
{ sPortDirs = Map.restrictKeys (sPortDirs rawInfo) relevantIdents
, sIdxUses = Set.intersection (sIdxUses rawInfo) relevantIdents
, sSeqUses = Set.intersection (sSeqUses rawInfo) relevantIdents }
convertDescription description = description convertDescription description = description
-- collects port direction and packed-array dimension info into the state -- collects port direction and packed-array dimension info into the state
collectDecl :: ModuleItem -> State Info () collectDecl :: ModuleItem -> State Info ()
collectDecl (MIDecl (Variable dir t ident _ _)) = do collectDecl (MIDecl (Variable _ t ident _ _)) = do
let (tf, rs) = typeRanges t let (tf, rs) = typeRanges t
if not (typeIsImplicit t) && length rs > 1 if not (typeIsImplicit t) && length rs > 1
then then
let dets = (tf $ tail rs, head rs) in let dets = (tf $ tail rs, head rs) in
modify $ \s -> s { sTypeDims = Map.insert ident dets (sTypeDims s) } modify $ \s -> s { sTypeDims = Map.insert ident dets (sTypeDims s) }
else return () else return ()
if dir /= Local
then do
() <- recordSeqUsage ident
modify $ \s -> s { sPortDirs = Map.insert ident dir (sPortDirs s) }
else return ()
collectDecl _ = return () collectDecl _ = return ()
-- collects task and function info into the state -- collects task and function info into the state
...@@ -96,47 +70,6 @@ collectTF (MIPackageItem (Task _ _ decls _)) = do ...@@ -96,47 +70,6 @@ collectTF (MIPackageItem (Task _ _ decls _)) = do
return () return ()
collectTF _ = return () collectTF _ = return ()
-- collectors for identifier usage information
recordSeqUsage :: Identifier -> State Info ()
recordSeqUsage i = modify $ \s -> s { sSeqUses = Set.insert i $ sSeqUses s }
recordIdxUsage :: Identifier -> State Info ()
recordIdxUsage i = modify $ \s -> s { sIdxUses = Set.insert i $ sIdxUses s }
collectExpr :: Expr -> State Info ()
collectExpr (Ident i) = recordSeqUsage i
collectExpr other = collectNestedExprsM collectNestedExpr other
collectNestedExpr :: Expr -> State Info ()
collectNestedExpr (Range (Ident i) _ _) = recordSeqUsage i
collectNestedExpr _ = return ()
collectLHS :: LHS -> State Info ()
collectLHS (LHSIdent i) = recordSeqUsage i
collectLHS other = collectNestedLHSsM collectNestedLHS other
collectNestedLHS :: LHS -> State Info ()
collectNestedLHS (LHSRange (LHSIdent i) _ _) = recordSeqUsage i
collectNestedLHS (LHSBit (LHSIdent i) _) = recordIdxUsage i
collectNestedLHS _ = return ()
-- VCS doesn't like port declarations inside of `generate` blocks, so we hoist
-- them out with this function. This obviously isn't ideal, but it's a
-- relatively straightforward transformation, and testing in VCS is important.
hoistPortDecls :: Description -> Description
hoistPortDecls (Part extern kw lifetime name ports items) =
Part extern kw lifetime name ports (concat $ map explode items)
where
explode :: ModuleItem -> [ModuleItem]
explode (Generate genItems) =
if null rest
then portDecls
else portDecls ++ [Generate rest]
where
(wrappedPortDecls, rest) = partition isPortDecl genItems
portDecls = map (\(GenModuleItem item) -> item) wrappedPortDecls
isPortDecl :: GenItem -> Bool
isPortDecl (GenModuleItem (MIDecl (Variable dir _ _ _ _))) =
dir /= Local
isPortDecl _ = False
explode other = [other]
hoistPortDecls other = other
-- rewrite a module item if it contains a declaration to flatten -- rewrite a module item if it contains a declaration to flatten
flattenModuleItem :: Info -> ModuleItem -> ModuleItem flattenModuleItem :: Info -> ModuleItem -> ModuleItem
flattenModuleItem info (MIPackageItem (Function ml t x decls stmts)) = flattenModuleItem info (MIPackageItem (Function ml t x decls stmts)) =
...@@ -154,77 +87,19 @@ flattenModuleItem info (MIPackageItem (Task ml x decls stmts)) = ...@@ -154,77 +87,19 @@ flattenModuleItem info (MIPackageItem (Task ml x decls stmts)) =
mapDecl decl = decl' mapDecl decl = decl'
where MIDecl decl' = flattenModuleItem info $ MIDecl decl where MIDecl decl' = flattenModuleItem info $ MIDecl decl
flattenModuleItem info (origDecl @ (MIDecl (Variable dir t ident a me))) = flattenModuleItem info (origDecl @ (MIDecl (Variable dir t ident a me))) =
-- if it doesn't need any mapping, then skip it if Map.notMember ident typeDims
if Map.notMember ident typeDims then origDecl then origDecl
-- if it is never used as a sequence (whole or range), then move the packed else flatDecl
-- dimension to the unpacked side
else if Set.notMember ident seqUses then flipDecl
-- if it is used as a sequence, but never indexed-into (sub-array), then
-- flatten (combine) the ranges, leaving them packed
else if Set.notMember ident duoUses then flatDecl
-- if it is both used as a sequence and is indexed-into
else
-- if this is not the fully-typed declaration of this item, then flatten
-- it, but don't make the `generate` block this time to avoid duplicates
if typeIsImplicit t then flatDecl
-- otherwise, flatten it, and also create an unflattened copy
else Generate $ (GenModuleItem flatDecl) : genItems
where where
Info typeDims portDirs idxUses seqUses = info Info typeDims = info
duoUses = Set.intersection idxUses seqUses
portDir = Map.lookup ident portDirs
writeToFlatVariant = portDir == Just Output || portDir == Nothing
genItems = unflattener writeToFlatVariant ident (typeDims Map.! ident)
(tf, rs) = typeRanges t (tf, rs) = typeRanges t
flipDecl = MIDecl $ Variable dir (tf $ tail rs) ident (a ++ [head rs]) me
flatDecl = MIDecl $ Variable dir (tf $ flattenRanges rs) ident a me flatDecl = MIDecl $ Variable dir (tf $ flattenRanges rs) ident a me
flattenModuleItem _ other = other flattenModuleItem _ other = other
-- produces `generate` items for creating an unflattened copy of the given
-- flattened, packed array
unflattener :: Bool -> Identifier -> (Type, Range) -> [GenItem]
unflattener writeToFlatVariant arr (t, major @ (majorHi, majorLo)) =
[ GenModuleItem $ MIPackageItem $ Comment $ "sv2v packed-array-flatten unflattener for " ++ arr
, GenModuleItem $ MIDecl $ Variable Local t arrUnflat [(majorHi, majorLo)] Nothing
, GenModuleItem $ Genvar index
, GenModuleItem $ MIDecl $ Variable Local (IntegerAtom TInteger Unspecified) (arrUnflat ++ "_repeater_index") [] Nothing
, GenFor
(index, majorLo)
(endianCondExpr major
(BinOp Le (Ident index) majorHi)
(BinOp Ge (Ident index) majorHi))
(index, AsgnOp Add, endianCondExpr major (Number "1") (Number "-1"))
(Just $ prefix "unflatten_" ++ arr)
[ localparam startBit
(simplify $ BinOp Add (endianCondExpr major majorLo majorHi)
(BinOp Mul (Ident index) size))
, GenModuleItem $ (uncurry $ Assign Nothing) $
if not writeToFlatVariant
then (LHSBit (LHSIdent arrUnflat) $ Ident index, Range (Ident arr) NonIndexed origRange)
else (LHSRange (LHSIdent arr) NonIndexed origRange, Bit (Ident arrUnflat) (Ident index))
]
]
where
startBit = prefix "_tmp_start_" ++ arr
arrUnflat = prefix arr
index = prefix "_tmp_index_" ++ arr
minor = head $ snd $ typeRanges t
size = rangeSize $ endianCondRange minor minor (swap minor)
localparam :: Identifier -> Expr -> GenItem
localparam x v = GenModuleItem $ MIDecl $ Localparam (Implicit Unspecified []) x v
origRangeAg = ( (BinOp Add (Ident startBit)
(BinOp Sub size (Number "1")))
, Ident startBit )
origRange = endianCondRange major origRangeAg (swap origRangeAg)
typeIsImplicit :: Type -> Bool typeIsImplicit :: Type -> Bool
typeIsImplicit (Implicit _ _) = True typeIsImplicit (Implicit _ _) = True
typeIsImplicit _ = False typeIsImplicit _ = False
-- prefix a string with a namespace of sorts
prefix :: Identifier -> Identifier
prefix ident = "_sv2v_" ++ ident
-- combines (flattens) the bottom two ranges in the given list of ranges -- combines (flattens) the bottom two ranges in the given list of ranges
flattenRanges :: [Range] -> [Range] flattenRanges :: [Range] -> [Range]
flattenRanges rs = flattenRanges rs =
...@@ -240,8 +115,7 @@ flattenRanges rs = ...@@ -240,8 +115,7 @@ flattenRanges rs =
rNN = flattenRangesHelp (swap r1) (swap r2) rNN = flattenRangesHelp (swap r1) (swap r2)
rY = endianCondRange r2 rYY rYN rY = endianCondRange r2 rYY rYN
rN = endianCondRange r2 rNY rNN rN = endianCondRange r2 rNY rNN
rAg = endianCondRange r1 rY rN r = endianCondRange r1 rY rN
r = endianCondRange r1 rAg (swap rAg)
rs' = (tail $ tail rs) ++ [r] rs' = (tail $ tail rs) ++ [r]
flattenRangesHelp :: Range -> Range -> Range flattenRangesHelp :: Range -> Range -> Range
...@@ -250,79 +124,119 @@ flattenRangesHelp (s1, e1) (s2, e2) = ...@@ -250,79 +124,119 @@ flattenRangesHelp (s1, e1) (s2, e2) =
where where
size1 = rangeSize (s1, e1) size1 = rangeSize (s1, e1)
size2 = rangeSize (s2, e2) size2 = rangeSize (s2, e2)
lower = BinOp Add e1 (BinOp Mul e2 size2) lower = BinOp Add e2 (BinOp Mul e1 size2)
upper = BinOp Add (BinOp Mul size1 size2) (BinOp Sub lower (Number "1")) upper = BinOp Add (BinOp Mul size1 size2) (BinOp Sub lower (Number "1"))
rewriteModuleItem :: Info -> ModuleItem -> ModuleItem rewriteModuleItem :: Info -> ModuleItem -> ModuleItem
rewriteModuleItem info = rewriteModuleItem info =
traverseStmts rewriteStmt . traverseLHSs (traverseNestedLHSs rewriteLHS ) .
traverseExprs (traverseNestedExprs rewriteExpr) traverseExprs (traverseNestedExprs rewriteExpr)
where where
Info typeDims _ idxUses seqUses = info Info typeDims = info
duoUses = Set.intersection idxUses seqUses
rewriteIdent :: Bool -> Identifier -> Identifier dims :: Identifier -> (Range, Range)
rewriteIdent isSeqUsage x = dims x =
if Set.member x duoUses (dimInner, dimOuter)
then where
-- if an array is used both ways, then the original name is (t, r) = typeDims Map.! x
-- the flattened version dimInner = r
if isSeqUsage dimOuter = head $ snd $ typeRanges t
then x
else prefix x orientIdx :: Range -> Expr -> Expr
else x orientIdx r e =
rewriteSeqIdent = rewriteIdent True endianCondExpr r e eSwapped
rewriteIdxIdent = rewriteIdent False where
eSwapped = BinOp Sub (snd r) (BinOp Sub e (fst r))
rewriteExpr :: Expr -> Expr rewriteExpr :: Expr -> Expr
rewriteExpr (Ident i) = Ident $ rewriteSeqIdent i rewriteExpr (Ident x) =
rewriteExpr (Bit (Ident i) e) = if head x == ':'
if Map.member i typeDims && Set.member i seqUses && Set.notMember i idxUses then Ident $ tail x
then Range (Ident $ rewriteSeqIdent i) NonIndexed (hi, lo) else Ident x
else Bit (Ident $ rewriteIdxIdent i) e rewriteExpr (orig @ (Bit (Bit (Ident x) idxInner) idxOuter)) =
if Map.member x typeDims
then Bit (Ident x') idx'
else orig
where where
r = head $ snd $ typeRanges $ fst $ typeDims Map.! i (dimInner, dimOuter) = dims x
size = rangeSize r x' = ':' : x
lo = simplify $ BinOp Mul e size idxInner' = orientIdx dimInner idxInner
hi = simplify $ BinOp Add lo (BinOp Sub size (Number "1")) idxOuter' = orientIdx dimOuter idxOuter
rewriteExpr (Range (Ident i) m (r @ (s, e))) = base = BinOp Mul idxInner' (rangeSize dimOuter)
if Map.member i typeDims idx' = simplify $ BinOp Add base idxOuter'
then Range (Ident i) m r' rewriteExpr (orig @ (Bit (Ident x) idx)) =
else Range (Ident i) m r if Map.member x typeDims
then Range (Ident x') mode' range'
else orig
where where
(a, b) = head $ snd $ typeRanges $ fst $ typeDims Map.! i (dimInner, dimOuter) = dims x
size = rangeSize (a, b) x' = ':' : x
s' = BinOp Sub (BinOp Mul size (BinOp Add s (Number "1"))) (Number "1") mode' = IndexedPlus
e' = BinOp Mul size e idx' = orientIdx dimInner idx
r' = (simplify s', simplify e') len = rangeSize dimOuter
base = BinOp Add (endianCondExpr dimOuter (snd dimOuter) (fst dimOuter)) (BinOp Mul idx' len)
range' = (simplify base, simplify len)
rewriteExpr (orig @ (Range (Ident x) mode range)) =
if Map.member x typeDims
then Range (Ident x') mode' range'
else orig
where
(_, dimOuter) = dims x
x' = ':' : x
mode' = mode
size = rangeSize dimOuter
range' =
case mode of
NonIndexed ->
(simplify hi, simplify lo)
where
lo = BinOp Mul size (snd range)
hi = BinOp Sub (BinOp Add lo (BinOp Mul (rangeSize range) size)) (Number "1")
IndexedPlus -> (BinOp Mul size (fst range), BinOp Mul size (snd range))
IndexedMinus -> (BinOp Mul size (fst range), BinOp Mul size (snd range))
---- TODO: I'm not sure how these should be handled yet.
----rewriteExpr (orig @ (Range (Bit (Ident x) idxInner) modeOuter rangeOuter)) =
---- if Map.member x typeDims
---- then Range (Ident x') mode' range'
---- else orig
---- where
---- (dimInner, dimOuter) = dims x
---- x' = ':' : x
---- mode' =
---- range' =
rewriteExpr other = other rewriteExpr other = other
rewriteLHS :: LHS -> LHS rewriteLHS :: LHS -> LHS
rewriteLHS (LHSIdent x ) = LHSIdent (rewriteSeqIdent x) rewriteLHS (LHSIdent x) =
rewriteLHS (LHSBit (LHSIdent x) e) = LHSIdent x'
LHSBit (LHSIdent $ rewriteIdxIdent x) e where Ident x' = rewriteExpr (Ident x)
rewriteLHS (LHSBit l e ) = LHSBit (rewriteLHS l) e rewriteLHS (orig @ (LHSBit (LHSBit (LHSIdent x) idxInner) idxOuter)) =
rewriteLHS (LHSRange l m r) = LHSRange (rewriteLHS l) m r if Map.member x typeDims
rewriteLHS (LHSDot l x ) = LHSDot (rewriteLHS l) x then LHSBit (LHSIdent x') idx'
rewriteLHS (LHSConcat ls ) = LHSConcat $ map rewriteLHS ls else orig
where Bit (Ident x') idx' =
rewriteStmt :: Stmt -> Stmt rewriteExpr (Bit (Bit (Ident x) idxInner) idxOuter)
rewriteStmt (AsgnBlk op lhs expr) = convertAssignment (AsgnBlk op) lhs expr rewriteLHS (orig @ (LHSBit (LHSRange (LHSIdent x) modeInner rangeInner) idxOuter)) =
rewriteStmt (Asgn mt lhs expr) = convertAssignment (Asgn mt) lhs expr if Map.member x typeDims
rewriteStmt other = other then LHSRange (LHSIdent x') mode' range'
convertAssignment :: (LHS -> Expr -> Stmt) -> LHS -> Expr -> Stmt else orig
convertAssignment constructor (lhs @ (LHSIdent ident)) (expr @ (Repeat _ exprs)) = where Range (Ident x') mode' range' =
if Map.member ident typeDims rewriteExpr (Bit (Range (Ident x) modeInner rangeInner) idxOuter)
then For inir chkr incr assign rewriteLHS (orig @ (LHSBit (LHSIdent x) idx)) =
else constructor (rewriteLHS lhs) expr if Map.member x typeDims
where then LHSRange (LHSIdent x') mode' range'
(_, (a, b)) = typeDims Map.! ident else orig
index = prefix $ ident ++ "_repeater_index" where Range (Ident x') mode' range' = rewriteExpr (Bit (Ident x) idx)
assign = constructor rewriteLHS (orig @ (LHSRange (LHSIdent x) mode range)) =
(LHSBit (LHSIdent $ prefix ident) (Ident index)) if Map.member x typeDims
(Concat exprs) then LHSRange (LHSIdent x') mode' range'
inir = [Right (LHSIdent index, b)] else orig
chkr = Just $ BinOp Le (Ident index) a where Range (Ident x') mode' range' =
incr = [(LHSIdent index, AsgnOp Add, Number "1")] rewriteExpr (Range (Ident x) mode range)
convertAssignment constructor lhs expr = rewriteLHS (orig @ (LHSRange (LHSBit (LHSIdent x) idxInner) modeOuter rangeOuter)) =
constructor (rewriteLHS lhs) expr if Map.member x typeDims
then LHSRange (LHSIdent x') mode' range'
else orig
where Range (Ident x') mode' range' =
rewriteExpr (Range (Bit (Ident x) idxInner) modeOuter rangeOuter)
rewriteLHS other = other
...@@ -101,7 +101,7 @@ convertType :: Structs -> Type -> Type ...@@ -101,7 +101,7 @@ convertType :: Structs -> Type -> Type
convertType structs t1 = convertType structs t1 =
case Map.lookup tf1 structs of case Map.lookup tf1 structs of
Nothing -> t1 Nothing -> t1
Just (t2, _) -> tf2 (rs2 ++ rs1) Just (t2, _) -> tf2 (rs1 ++ rs2)
where (tf2, rs2) = typeRanges t2 where (tf2, rs2) = typeRanges t2
where (tf1, rs1) = typeRanges t1 where (tf1, rs1) = typeRanges t1
...@@ -141,30 +141,46 @@ convertAsgn structs types (lhs, expr) = ...@@ -141,30 +141,46 @@ convertAsgn structs types (lhs, expr) =
Nothing -> (Implicit Unspecified [], LHSIdent x) Nothing -> (Implicit Unspecified [], LHSIdent x)
Just t -> (t, LHSIdent x) Just t -> (t, LHSIdent x)
convertLHS (LHSBit l e) = convertLHS (LHSBit l e) =
if null rs case l' of
then (Implicit Unspecified [], LHSBit l' e') LHSRange lInner NonIndexed (_, loI) ->
else (tf $ tail rs, LHSBit l' e') (t', LHSBit lInner (simplify $ BinOp Add loI e'))
LHSRange lInner IndexedPlus (baseI, _) ->
(t', LHSBit lInner (simplify $ BinOp Add baseI e'))
_ -> (t', LHSBit l' e')
where where
(t, l') = convertLHS l (t, l') = convertLHS l
(tf, rs) = typeRanges t t' = case typeRanges t of
(_, []) -> Implicit Unspecified []
(tf, rs) -> tf $ tail rs
e' = snd $ convertSubExpr e e' = snd $ convertSubExpr e
convertLHS (LHSRange l m rOuterOrig) = convertLHS (LHSRange lOuter NonIndexed rOuterOrig) =
case l' of case lOuter' of
LHSRange lInner NonIndexed (_, loI) -> LHSRange lInner NonIndexed (_, loI) ->
(t, LHSRange lInner m (simplify hi, simplify lo)) (t, LHSRange lInner NonIndexed (simplify hi, simplify lo))
where where
lo = BinOp Add loI loO lo = BinOp Add loI loO
hi = BinOp Add loI hiO hi = BinOp Add loI hiO
_ -> if null rs LHSRange lInner IndexedPlus (baseI, _) ->
then (Implicit Unspecified [], LHSRange l' m rOuter) (t, LHSRange lInner IndexedPlus (simplify base, simplify len))
else (tf rs', LHSRange l' m rOuter) where
base = BinOp Add baseI loO
len = rangeSize rOuter
_ -> (t, LHSRange lOuter' NonIndexed rOuter)
where where
(t, l') = convertLHS l
(tf, rs) = typeRanges t
hiO = snd $ convertSubExpr $ fst rOuterOrig hiO = snd $ convertSubExpr $ fst rOuterOrig
loO = snd $ convertSubExpr $ snd rOuterOrig loO = snd $ convertSubExpr $ snd rOuterOrig
rOuter = (hiO, loO) rOuter = (hiO, loO)
rs' = rOuter : tail rs (t, lOuter') = convertLHS lOuter
convertLHS (LHSRange l m r) =
(t', LHSRange l' m r')
where
hi = snd $ convertSubExpr $ fst r
lo = snd $ convertSubExpr $ snd r
r' = (hi, lo)
(t, l') = convertLHS l
t' = case typeRanges t of
(_, []) -> Implicit Unspecified []
(tf, rs) -> tf $ tail rs
convertLHS (LHSDot l x ) = convertLHS (LHSDot l x ) =
case t of case t of
InterfaceT _ _ _ -> (Implicit Unspecified [], LHSDot l' x) InterfaceT _ _ _ -> (Implicit Unspecified [], LHSDot l' x)
...@@ -236,18 +252,30 @@ convertAsgn structs types (lhs, expr) = ...@@ -236,18 +252,30 @@ convertAsgn structs types (lhs, expr) =
structTf = Struct p fields structTf = Struct p fields
fieldType = lookupFieldType fields x fieldType = lookupFieldType fields x
r = lookupUnstructRange structTf x r = lookupUnstructRange structTf x
convertSubExpr (Range eOuter m (rOuter @ (hiO, loO))) = convertSubExpr (Range eOuter NonIndexed (rOuter @ (hiO, loO))) =
-- VCS doesn't allow ranges to be cascaded, so we need to combine -- VCS doesn't allow ranges to be cascaded, so we need to combine
-- nested Ranges into a single range. My understanding of the -- nested Ranges into a single range. My understanding of the
-- semantics are that a range returns a new, zero-indexed sub-range. -- semantics are that a range returns a new, zero-indexed sub-range.
case eOuter' of case eOuter' of
Range eInner NonIndexed (_, loI) -> Range eInner NonIndexed (_, loI) ->
(t, Range eInner m (simplify hi, simplify lo)) (t, Range eInner NonIndexed (simplify hi, simplify lo))
where where
lo = BinOp Add loI loO lo = BinOp Add loI loO
hi = BinOp Add loI hiO hi = BinOp Add loI hiO
_ -> (t, Range eOuter' m rOuter) Range eInner IndexedPlus (baseI, _) ->
(t, Range eInner IndexedPlus (simplify base, simplify len))
where
base = BinOp Add baseI loO
len = rangeSize rOuter
_ -> (t, Range eOuter' NonIndexed rOuter)
where (t, eOuter') = convertSubExpr eOuter where (t, eOuter') = convertSubExpr eOuter
convertSubExpr (Range e m r) =
(t', Range e' m r)
where
(t, e') = convertSubExpr e
t' = case typeRanges t of
(_, []) -> Implicit Unspecified []
(tf, rs) -> tf $ tail rs
convertSubExpr (Concat exprs) = convertSubExpr (Concat exprs) =
(Implicit Unspecified [], Concat $ map (snd . convertSubExpr) exprs) (Implicit Unspecified [], Concat $ map (snd . convertSubExpr) exprs)
convertSubExpr (BinOp op e1 e2) = convertSubExpr (BinOp op e1 e2) =
...@@ -259,6 +287,8 @@ convertAsgn structs types (lhs, expr) = ...@@ -259,6 +287,8 @@ convertAsgn structs types (lhs, expr) =
case e' of case e' of
Range eInner NonIndexed (_, loI) -> Range eInner NonIndexed (_, loI) ->
(t', Bit eInner (simplify $ BinOp Add loI i')) (t', Bit eInner (simplify $ BinOp Add loI i'))
Range eInner IndexedPlus (baseI, _) ->
(t', Bit eInner (simplify $ BinOp Add baseI i'))
_ -> (t', Bit e' i') _ -> (t', Bit e' i')
where where
(t, e') = convertSubExpr e (t, e') = convertSubExpr e
......
...@@ -60,6 +60,7 @@ module Convert.Traverse ...@@ -60,6 +60,7 @@ module Convert.Traverse
, traverseNestedModuleItems , traverseNestedModuleItems
, collectNestedModuleItemsM , collectNestedModuleItemsM
, traverseNestedStmts , traverseNestedStmts
, collectNestedStmtsM
, traverseNestedExprs , traverseNestedExprs
, collectNestedExprsM , collectNestedExprsM
, traverseNestedLHSsM , traverseNestedLHSsM
...@@ -303,7 +304,7 @@ traverseAssertionExprsM mapper = assertionMapper ...@@ -303,7 +304,7 @@ traverseAssertionExprsM mapper = assertionMapper
return $ Cover e' stmt return $ Cover e' stmt
traverseStmtLHSsM :: Monad m => MapperM m LHS -> MapperM m Stmt traverseStmtLHSsM :: Monad m => MapperM m LHS -> MapperM m Stmt
traverseStmtLHSsM mapper = traverseNestedStmtsM stmtMapper traverseStmtLHSsM mapper = stmtMapper
where where
fullMapper = mapper fullMapper = mapper
stmtMapper (Timing (Event sense) stmt) = do stmtMapper (Timing (Event sense) stmt) = do
...@@ -591,7 +592,7 @@ traverseLHSsM' strat mapper item = ...@@ -591,7 +592,7 @@ traverseLHSsM' strat mapper item =
lhs' <- mapper lhs lhs' <- mapper lhs
return $ NInputGate kw x lhs' exprs return $ NInputGate kw x lhs' exprs
traverseModuleItemLHSsM (AssertionItem (mx, a)) = do traverseModuleItemLHSsM (AssertionItem (mx, a)) = do
Assertion a' <- traverseStmtLHSsM mapper (Assertion a) Assertion a' <- traverseNestedStmtsM (traverseStmtLHSsM mapper) (Assertion a)
return $ AssertionItem (mx, a') return $ AssertionItem (mx, a')
traverseModuleItemLHSsM other = return other traverseModuleItemLHSsM other = return other
...@@ -610,7 +611,7 @@ collectLHSsM = collectLHSsM' IncludeTFs ...@@ -610,7 +611,7 @@ collectLHSsM = collectLHSsM' IncludeTFs
traverseNestedLHSsM :: Monad m => MapperM m LHS -> MapperM m LHS traverseNestedLHSsM :: Monad m => MapperM m LHS -> MapperM m LHS
traverseNestedLHSsM mapper = fullMapper traverseNestedLHSsM mapper = fullMapper
where where
fullMapper lhs = tl lhs >>= mapper fullMapper lhs = mapper lhs >>= tl
tl (LHSIdent x ) = return $ LHSIdent x tl (LHSIdent x ) = return $ LHSIdent x
tl (LHSBit l e ) = fullMapper l >>= \l' -> return $ LHSBit l' e tl (LHSBit l e ) = fullMapper l >>= \l' -> return $ LHSBit l' e
tl (LHSRange l m r) = fullMapper l >>= \l' -> return $ LHSRange l' m r tl (LHSRange l m r) = fullMapper l >>= \l' -> return $ LHSRange l' m r
...@@ -792,6 +793,8 @@ collectNestedModuleItemsM = collectify traverseNestedModuleItemsM ...@@ -792,6 +793,8 @@ collectNestedModuleItemsM = collectify traverseNestedModuleItemsM
traverseNestedStmts :: Mapper Stmt -> Mapper Stmt traverseNestedStmts :: Mapper Stmt -> Mapper Stmt
traverseNestedStmts = unmonad traverseNestedStmtsM traverseNestedStmts = unmonad traverseNestedStmtsM
collectNestedStmtsM :: Monad m => CollectorM m Stmt -> CollectorM m Stmt
collectNestedStmtsM = collectify traverseNestedStmtsM
traverseNestedExprs :: Mapper Expr -> Mapper Expr traverseNestedExprs :: Mapper Expr -> Mapper Expr
traverseNestedExprs = unmonad traverseNestedExprsM traverseNestedExprs = unmonad traverseNestedExprsM
......
...@@ -72,12 +72,12 @@ resolveType types (Alias st rs1) = ...@@ -72,12 +72,12 @@ resolveType types (Alias st rs1) =
if Map.notMember st types if Map.notMember st types
then InterfaceT st Nothing rs1 then InterfaceT st Nothing rs1
else case resolveType types $ types Map.! st of else case resolveType types $ types Map.! st of
(Net kw rs2) -> Net kw $ rs2 ++ rs1 (Net kw rs2) -> Net kw $ rs1 ++ rs2
(Implicit sg rs2) -> Implicit sg $ rs2 ++ rs1 (Implicit sg rs2) -> Implicit sg $ rs1 ++ rs2
(IntegerVector kw sg rs2) -> IntegerVector kw sg $ rs2 ++ rs1 (IntegerVector kw sg rs2) -> IntegerVector kw sg $ rs1 ++ rs2
(Enum t v rs2) -> Enum t v $ rs2 ++ rs1 (Enum t v rs2) -> Enum t v $ rs1 ++ rs2
(Struct p l rs2) -> Struct p l $ rs2 ++ rs1 (Struct p l rs2) -> Struct p l $ rs1 ++ rs2
(InterfaceT x my rs2) -> InterfaceT x my $ rs2 ++ rs1 (InterfaceT x my rs2) -> InterfaceT x my $ rs1 ++ rs2
(IntegerAtom kw _ ) -> error $ "resolveType encountered packed `" ++ (show kw) ++ "` on " ++ st (IntegerAtom kw _ ) -> error $ "resolveType encountered packed `" ++ (show kw) ++ "` on " ++ st
(NonInteger kw ) -> error $ "resolveType encountered packed `" ++ (show kw) ++ "` on " ++ st (NonInteger kw ) -> error $ "resolveType encountered packed `" ++ (show kw) ++ "` on " ++ st
(Alias _ _) -> error $ "resolveType invariant failed on " ++ st (Alias _ _) -> error $ "resolveType invariant failed on " ++ st
...@@ -145,7 +145,10 @@ simplify other = other ...@@ -145,7 +145,10 @@ simplify other = other
rangeSize :: Range -> Expr rangeSize :: Range -> Expr
rangeSize (s, e) = rangeSize (s, e) =
simplify $ BinOp Add (BinOp Sub s e) (Number "1") 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")
-- chooses one or the other expression based on the endianness of the given -- chooses one or the other expression based on the endianness of the given
-- range; [hi:lo] chooses the first expression -- range; [hi:lo] chooses the first expression
......
`define CASE_A(name, dims) \ `define CASE(name, dims, a, b) \
module name(clock, in, out); \ module name(clock, in, out); \
input wire clock, in; \ input wire clock, in; \
output logic dims out; \ output logic dims out; \
initial out[0] = 0; \ initial out[0+a] = 0; \
initial out[1] = 0; \ initial out[1+a] = 0; \
initial out[2] = 0; \ initial out[2+a] = 0; \
always @(posedge clock) begin \ always @(posedge clock) begin \
\ /*$display($time, `" name ", out[0+a][1+b+:1]);*/ \
out[2][4] = out[2][3]; \ /*$display($time, `" name ", out[0+a][1+b+:1]);*/ \
out[2][3] = out[2][2]; \ /*$display($time, `" name ", out[1+a][1+b+:1]);*/ \
out[2][2] = out[2][1]; \ /*$display($time, `" name ", out[1+a][1+b+:1]);*/ \
out[2][1] = out[2][0]; \ /*$display($time, `" name ", out[2+a][1+b+:1]);*/ \
out[2][0] = out[1][4]; \ /*$display($time, `" name ", out[2+a][1+b+:1]);*/ \
\ \
out[1][4] = out[1][3]; \ out[2+a][4+b] = out[2+a][3+b]; \
out[1][3] = out[1][2]; \ out[2+a][3+b] = out[2+a][2+b]; \
out[1][2] = out[1][1]; \ out[2+a][2+b] = out[2+a][1+b]; \
out[1][1] = out[1][0]; \ out[2+a][1+b] = out[2+a][0+b]; \
out[1][0] = out[0][4]; \ out[2+a][0+b] = out[1+a][4+b]; \
\ \
out[0][4] = out[0][3]; \ out[1+a][4+b] = out[1+a][3+b]; \
out[0][3] = out[0][2]; \ out[1+a][3+b] = out[1+a][2+b]; \
out[0][2] = out[0][1]; \ out[1+a][2+b] = out[1+a][1+b]; \
out[0][1] = out[0][0]; \ out[1+a][1+b] = out[1+a][0+b]; \
out[0][0] = in; \ out[1+a][0+b] = out[0+a][4+b]; \
\
out[0+a][4+b] = out[0+a][3+b]; \
out[0+a][3+b] = out[0+a][2+b]; \
out[0+a][2+b] = out[0+a][1+b]; \
out[0+a][1+b] = out[0+a][0+b]; \
out[0+a][0+b] = in; \
\ \
end \ end \
endmodule endmodule
`CASE_A(A1, [2:0][4:0]) `CASE(A1, [2:0][4:0], 0, 0)
`CASE_A(A2, [0:2][0:4]) `CASE(A2, [0:2][0:4], 0, 0)
`CASE_A(A3, [0:2][4:0]) `CASE(A3, [0:2][4:0], 0, 0)
`CASE_A(A4, [2:0][0:4]) `CASE(A4, [2:0][0:4], 0, 0)
`define CASE_B(name, dims) \
module name(clock, in, out); \
input wire clock, in; \
output logic dims out; \
initial out[1] = 0; \
initial out[2] = 0; \
initial out[3] = 0; \
always @(posedge clock) begin \
\
out[3][5] = out[3][4]; \
out[3][4] = out[3][3]; \
out[3][3] = out[3][2]; \
out[3][2] = out[3][1]; \
out[3][1] = out[2][5]; \
\
out[2][5] = out[2][4]; \
out[2][4] = out[2][3]; \
out[2][3] = out[2][2]; \
out[2][2] = out[2][1]; \
out[2][1] = out[1][5]; \
\
out[1][5] = out[1][4]; \
out[1][4] = out[1][3]; \
out[1][3] = out[1][2]; \
out[1][2] = out[1][1]; \
out[1][1] = in; \
\
end \
endmodule
`CASE_B(B1, [3:1][5:1]) `CASE(B1, [3:1][5:1], 1, 1)
`CASE_B(B2, [1:3][1:5]) `CASE(B2, [1:3][1:5], 1, 1)
`CASE_B(B3, [1:3][5:1]) `CASE(B3, [1:3][5:1], 1, 1)
`CASE_B(B4, [3:1][1:5]) `CASE(B4, [3:1][1:5], 1, 1)
`define CASE_C(name, dims) \ `CASE(C1, [4:2][6:2], 2, 2)
module name(clock, in, out); \ `CASE(C2, [2:4][2:6], 2, 2)
input wire clock, in; \ `CASE(C3, [2:4][6:2], 2, 2)
output logic dims out; \ `CASE(C4, [4:2][2:6], 2, 2)
initial out[2] = 0; \
initial out[3] = 0; \
initial out[4] = 0; \
always @(posedge clock) begin \
\
out[4][6] = out[4][5]; \
out[4][5] = out[4][4]; \
out[4][4] = out[4][3]; \
out[4][3] = out[4][2]; \
out[4][2] = out[3][6]; \
\
out[3][6] = out[3][5]; \
out[3][5] = out[3][4]; \
out[3][4] = out[3][3]; \
out[3][3] = out[3][2]; \
out[3][2] = out[2][6]; \
\
out[2][6] = out[2][5]; \
out[2][5] = out[2][4]; \
out[2][4] = out[2][3]; \
out[2][3] = out[2][2]; \
out[2][2] = in; \
\
end \
endmodule
`CASE_C(C1, [4:2][6:2]) `CASE(D1, [5:3][6:2], 3, 2)
`CASE_C(C2, [2:4][2:6]) `CASE(D2, [3:5][2:6], 3, 2)
`CASE_C(C3, [2:4][6:2]) `CASE(D3, [3:5][6:2], 3, 2)
`CASE_C(C4, [4:2][2:6]) `CASE(D4, [5:3][2:6], 3, 2)
...@@ -4,9 +4,13 @@ ...@@ -4,9 +4,13 @@
tag``2 tag``two(.clock(clock), .in(in), .out(tag``two_out)); \ tag``2 tag``two(.clock(clock), .in(in), .out(tag``two_out)); \
tag``3 tag``thr(.clock(clock), .in(in), .out(tag``thr_out)); \ tag``3 tag``thr(.clock(clock), .in(in), .out(tag``thr_out)); \
tag``4 tag``fou(.clock(clock), .in(in), .out(tag``fou_out)); \ tag``4 tag``fou(.clock(clock), .in(in), .out(tag``fou_out)); \
integer tag``i; \
initial begin \ initial begin \
$monitor(`"tag", $time, ": %h %15b %15b %15b %15b", in, \ for (tag``i = 0; tag``i < 20; tag``i++) begin \
#2; \
$display(`"tag", $time, ": %h %15b %15b %15b %15b", in, \
tag``one_out, tag``two_out, tag``thr_out, tag``fou_out); \ tag``one_out, tag``two_out, tag``thr_out, tag``fou_out); \
end \
end end
module top; module top;
...@@ -30,5 +34,6 @@ module top; ...@@ -30,5 +34,6 @@ module top;
`FOO(A) `FOO(A)
`FOO(B) `FOO(B)
`FOO(C) `FOO(C)
`FOO(D)
endmodule endmodule
`define PRINT(arr, a, b) \
$display(arr[0+a][0+b]); \
$display(arr[0+a][1+b]); \
$display(arr[0+a][2+b]); \
$display(arr[1+a][0+b]); \
$display(arr[1+a][1+b]); \
$display(arr[1+a][2+b]); \
$display(arr[2+a][0+b]); \
$display(arr[2+a][1+b]); \
$display(arr[2+a][2+b]); \
$display(arr[3+a][0+b]); \
$display(arr[3+a][1+b]); \
$display(arr[3+a][2+b]); \
$display(arr[4+a][0+b]); \
$display(arr[4+a][1+b]); \
$display(arr[4+a][2+b]);
module Example;
typedef logic [2:0] Pack;
Pack [4:0] arr1;
Pack [4:0] arr2;
Pack [4:0] arr3;
initial begin
arr1 = 'b100101010100100;
arr1[0][1] = ~arr1[0][1];
arr1[4][2] = ~arr1[4][2];
`PRINT(arr1, 0, 0)
arr2 = 'b100101000110101;
`PRINT(arr2, 0, 0)
arr3 = 'b100100111101010;
arr3[1] = arr3[2];
`PRINT(arr3, 0, 0)
end
Pack [5:1] arr4;
Pack [5:1] arr5;
Pack [5:1] arr6;
initial begin
arr4 = 'b100101010100100;
arr4[1][1] = ~arr4[1][1];
arr4[5][2] = ~arr4[5][2];
`PRINT(arr4, 1, 0)
arr5 = 'b100101000110101;
`PRINT(arr5, 1, 0)
arr6 = 'b100100111101010;
arr6[2] = arr6[3];
`PRINT(arr6, 1, 0)
end
Pack [1:5] arr7;
Pack [1:5] arr8;
Pack [1:5] arr9;
initial begin
arr7 = 'b100101010100100;
arr7[1][1] = ~arr7[1][1];
arr7[5][2] = ~arr7[5][2];
`PRINT(arr7, 1, 0)
arr8 = 'b100101000110101;
`PRINT(arr8, 1, 0)
arr9 = 'b100100111101010;
arr9[2] = arr9[3];
`PRINT(arr9, 1, 0)
end
endmodule
`define PRINT(arr, a, b) \
$display(arr[0+a][0+b]); \
$display(arr[0+a][1+b]); \
$display(arr[0+a][2+b]); \
$display(arr[1+a][0+b]); \
$display(arr[1+a][1+b]); \
$display(arr[1+a][2+b]); \
$display(arr[2+a][0+b]); \
$display(arr[2+a][1+b]); \
$display(arr[2+a][2+b]); \
$display(arr[3+a][0+b]); \
$display(arr[3+a][1+b]); \
$display(arr[3+a][2+b]); \
$display(arr[4+a][0+b]); \
$display(arr[4+a][1+b]); \
$display(arr[4+a][2+b]);
module Example;
reg [4:0][2:0] arr1;
reg [4:0][2:0] arr2;
reg [4:0][2:0] arr3;
initial begin
arr1 = 'b100101010100100;
arr1[0][1] = ~arr1[0][1];
arr1[4][2] = ~arr1[4][2];
`PRINT(arr1, 0, 0)
arr2 = 'b100101000110101;
`PRINT(arr2, 0, 0)
arr3 = 'b100100111101010;
arr3[1] = arr3[2];
`PRINT(arr3, 0, 0)
end
reg [5:1][2:0] arr4;
reg [5:1][2:0] arr5;
reg [5:1][2:0] arr6;
initial begin
arr4 = 'b100101010100100;
arr4[1][1] = ~arr4[1][1];
arr4[5][2] = ~arr4[5][2];
`PRINT(arr4, 1, 0)
arr5 = 'b100101000110101;
`PRINT(arr5, 1, 0)
arr6 = 'b100100111101010;
arr6[2] = arr6[3];
`PRINT(arr6, 1, 0)
end
reg [1:5][2:0] arr7;
reg [1:5][2:0] arr8;
reg [1:5][2:0] arr9;
initial begin
arr7 = 'b100101010100100;
arr7[1][1] = ~arr7[1][1];
arr7[5][2] = ~arr7[5][2];
`PRINT(arr7, 1, 0)
arr8 = 'b100101000110101;
`PRINT(arr8, 1, 0)
arr9 = 'b100100111101010;
arr9[2] = arr9[3];
`PRINT(arr9, 1, 0)
end
endmodule
module top;
Example example();
endmodule
typedef struct packed {
logic x;
logic [3:0] y;
logic [1:0] z;
} Struct_t;
module Unpacker(in, select, a, b, c);
parameter WIDTH = 8;
input Struct_t [WIDTH-1:0] in;
input logic [$clog2(WIDTH)-1:0] select;
output logic a;
output logic [3:0] b;
output logic [1:0] c;
assign a = in[select].x;
assign b = in[select].y;
assign c = in[select].z;
endmodule
module Unpacker(in, select, a, b, c);
parameter WIDTH = 8;
input wire [WIDTH-1:0][6:0] in;
input wire [$clog2(WIDTH)-1:0] select;
output wire a;
output wire [3:0] b;
output wire [1:0] c;
wire [6:0] p;
assign p = in[select];
assign a = p[6:6];
assign b = p[5:2];
assign c = p[1:0];
endmodule
module top;
reg [56-1:0] in;
reg [2:0] select;
wire a;
wire [3:0] b;
wire [1:0] c;
Unpacker unpacker(in, select, a, b, c);
initial begin
$monitor("%d: %01b %04b %02b", select, a, b, c);
in = 'b01111011011011101111100111110111001010001011100110101000;
select = 0; #1;
select = 1; #1;
select = 2; #1;
select = 3; #1;
select = 4; #1;
select = 5; #1;
select = 6; #1;
select = 7; #1;
$finish;
end
// 0 1010 00
// 1 1100 11
// 0 1000 10
// 0 1110 01
// 0 0111 11
// 1 0111 11
// 1 0110 11
// 0 1111 01
endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment