diff --git a/src/Convert/Logic.hs b/src/Convert/Logic.hs index b378845..9c2b79f 100644 --- a/src/Convert/Logic.hs +++ b/src/Convert/Logic.hs @@ -57,7 +57,7 @@ convertDescription orig = regIdents :: ModuleItem -> Writer RegIdents () regIdents (AlwaysC _ stmt) = - collectStmtLHSsM (collectNestedLHSsM idents) $ + collectNestedStmtsM (collectStmtLHSsM (collectNestedLHSsM idents)) $ traverseNestedStmts removeTimings stmt where idents :: LHS -> Writer RegIdents () @@ -66,4 +66,6 @@ regIdents (AlwaysC _ stmt) = removeTimings :: Stmt -> Stmt removeTimings (Timing _ s) = s removeTimings other = other +regIdents (Initial stmt) = + regIdents $ AlwaysC Always stmt regIdents _ = return () diff --git a/src/Convert/PackedArray.hs b/src/Convert/PackedArray.hs index 3cce69e..a5cf855 100644 --- a/src/Convert/PackedArray.hs +++ b/src/Convert/PackedArray.hs @@ -6,83 +6,57 @@ - This removes one dimension per identifier at a time. This works fine because - the conversions are repeatedly applied. - - - Packed arrays can be used in any of the following ways: A) as a whole, - - including as a port; B) with an index (`foo[0]`); or C) with a range - - (`foo[10:0]`). The rules for this conversion are: - - 1. If used with an index, then we must have an unflattened/unpacked - - 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. + - 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. - - - Note: We don't count usages with an index in expressions as such, as those - - usages could be equivalently converted to range accesses with some added in - - multiplication. + - Note that the ranges being combined may not be of the form [hi:lo], and need + - not even be the same direction! Because of this, we have to flip arround + - 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 import Control.Monad.State -import Data.List (partition) import Data.Tuple (swap) -import qualified Data.Set as Set import qualified Data.Map.Strict as Map import Convert.Traverse import Language.SystemVerilog.AST -type DirMap = Map.Map Identifier Direction type DimMap = Map.Map Identifier (Type, Range) -type IdentSet = Set.Set Identifier data Info = Info { sTypeDims :: DimMap - , sPortDirs :: DirMap - , sIdxUses :: IdentSet - , sSeqUses :: IdentSet } - deriving Show + } deriving Show convert :: AST -> AST convert = traverseDescriptions convertDescription convertDescription :: Description -> Description convertDescription (description @ (Part _ _ _ _ _ _)) = - hoistPortDecls $ traverseModuleItems (flattenModuleItem info . rewriteModuleItem info) description where -- collect all possible information info our Info structure - rawInfo = - execState (collectModuleItemsM (collectLHSsM collectLHS) description) $ - execState (collectModuleItemsM (collectExprsM collectExpr) description) $ + info = execState (collectModuleItemsM collectDecl description) $ execState (collectModuleItemsM collectTF description) $ - (Info Map.empty Map.empty Set.empty Set.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 } + (Info Map.empty) convertDescription description = description -- collects port direction and packed-array dimension info into the state collectDecl :: ModuleItem -> State Info () -collectDecl (MIDecl (Variable dir t ident _ _)) = do +collectDecl (MIDecl (Variable _ t ident _ _)) = do let (tf, rs) = typeRanges t if not (typeIsImplicit t) && length rs > 1 then let dets = (tf $ tail rs, head rs) in modify $ \s -> s { sTypeDims = Map.insert ident dets (sTypeDims s) } else return () - if dir /= Local - then do - () <- recordSeqUsage ident - modify $ \s -> s { sPortDirs = Map.insert ident dir (sPortDirs s) } - else return () collectDecl _ = return () -- collects task and function info into the state @@ -96,47 +70,6 @@ collectTF (MIPackageItem (Task _ _ decls _)) = do 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 flattenModuleItem :: Info -> ModuleItem -> ModuleItem flattenModuleItem info (MIPackageItem (Function ml t x decls stmts)) = @@ -154,77 +87,19 @@ flattenModuleItem info (MIPackageItem (Task ml x decls stmts)) = mapDecl decl = decl' where MIDecl decl' = flattenModuleItem info $ MIDecl decl 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 then origDecl - -- if it is never used as a sequence (whole or range), then move the packed - -- 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 + if Map.notMember ident typeDims + then origDecl + else flatDecl where - Info typeDims portDirs idxUses seqUses = info - duoUses = Set.intersection idxUses seqUses - portDir = Map.lookup ident portDirs - writeToFlatVariant = portDir == Just Output || portDir == Nothing - genItems = unflattener writeToFlatVariant ident (typeDims Map.! ident) + Info typeDims = info (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 --- 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 (Implicit _ _) = True 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 flattenRanges :: [Range] -> [Range] flattenRanges rs = @@ -240,8 +115,7 @@ flattenRanges rs = rNN = flattenRangesHelp (swap r1) (swap r2) rY = endianCondRange r2 rYY rYN rN = endianCondRange r2 rNY rNN - rAg = endianCondRange r1 rY rN - r = endianCondRange r1 rAg (swap rAg) + r = endianCondRange r1 rY rN rs' = (tail $ tail rs) ++ [r] flattenRangesHelp :: Range -> Range -> Range @@ -250,79 +124,119 @@ flattenRangesHelp (s1, e1) (s2, e2) = where size1 = rangeSize (s1, e1) 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")) rewriteModuleItem :: Info -> ModuleItem -> ModuleItem rewriteModuleItem info = - traverseStmts rewriteStmt . + traverseLHSs (traverseNestedLHSs rewriteLHS ) . traverseExprs (traverseNestedExprs rewriteExpr) where - Info typeDims _ idxUses seqUses = info - duoUses = Set.intersection idxUses seqUses + Info typeDims = info - rewriteIdent :: Bool -> Identifier -> Identifier - rewriteIdent isSeqUsage x = - if Set.member x duoUses - then - -- if an array is used both ways, then the original name is - -- the flattened version - if isSeqUsage - then x - else prefix x - else x - rewriteSeqIdent = rewriteIdent True - rewriteIdxIdent = rewriteIdent False + dims :: Identifier -> (Range, Range) + dims x = + (dimInner, dimOuter) + where + (t, r) = typeDims Map.! x + dimInner = r + dimOuter = head $ snd $ typeRanges t + + orientIdx :: Range -> Expr -> Expr + orientIdx r e = + endianCondExpr r e eSwapped + where + eSwapped = BinOp Sub (snd r) (BinOp Sub e (fst r)) rewriteExpr :: Expr -> Expr - rewriteExpr (Ident i) = Ident $ rewriteSeqIdent i - rewriteExpr (Bit (Ident i) e) = - if Map.member i typeDims && Set.member i seqUses && Set.notMember i idxUses - then Range (Ident $ rewriteSeqIdent i) NonIndexed (hi, lo) - else Bit (Ident $ rewriteIdxIdent i) e + rewriteExpr (Ident x) = + if head x == ':' + then Ident $ tail x + else Ident x + rewriteExpr (orig @ (Bit (Bit (Ident x) idxInner) idxOuter)) = + if Map.member x typeDims + then Bit (Ident x') idx' + else orig where - r = head $ snd $ typeRanges $ fst $ typeDims Map.! i - size = rangeSize r - lo = simplify $ BinOp Mul e size - hi = simplify $ BinOp Add lo (BinOp Sub size (Number "1")) - rewriteExpr (Range (Ident i) m (r @ (s, e))) = - if Map.member i typeDims - then Range (Ident i) m r' - else Range (Ident i) m r + (dimInner, dimOuter) = dims x + x' = ':' : x + idxInner' = orientIdx dimInner idxInner + idxOuter' = orientIdx dimOuter idxOuter + base = BinOp Mul idxInner' (rangeSize dimOuter) + idx' = simplify $ BinOp Add base idxOuter' + rewriteExpr (orig @ (Bit (Ident x) idx)) = + if Map.member x typeDims + then Range (Ident x') mode' range' + else orig where - (a, b) = head $ snd $ typeRanges $ fst $ typeDims Map.! i - size = rangeSize (a, b) - s' = BinOp Sub (BinOp Mul size (BinOp Add s (Number "1"))) (Number "1") - e' = BinOp Mul size e - r' = (simplify s', simplify e') + (dimInner, dimOuter) = dims x + x' = ':' : x + 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) + 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 rewriteLHS :: LHS -> LHS - rewriteLHS (LHSIdent x ) = LHSIdent (rewriteSeqIdent x) - rewriteLHS (LHSBit (LHSIdent x) e) = - LHSBit (LHSIdent $ rewriteIdxIdent x) e - rewriteLHS (LHSBit l e ) = LHSBit (rewriteLHS l) e - rewriteLHS (LHSRange l m r) = LHSRange (rewriteLHS l) m r - rewriteLHS (LHSDot l x ) = LHSDot (rewriteLHS l) x - rewriteLHS (LHSConcat ls ) = LHSConcat $ map rewriteLHS ls - - rewriteStmt :: Stmt -> Stmt - rewriteStmt (AsgnBlk op lhs expr) = convertAssignment (AsgnBlk op) lhs expr - rewriteStmt (Asgn mt lhs expr) = convertAssignment (Asgn mt) lhs expr - rewriteStmt other = other - convertAssignment :: (LHS -> Expr -> Stmt) -> LHS -> Expr -> Stmt - convertAssignment constructor (lhs @ (LHSIdent ident)) (expr @ (Repeat _ exprs)) = - if Map.member ident typeDims - then For inir chkr incr assign - else constructor (rewriteLHS lhs) expr - where - (_, (a, b)) = typeDims Map.! ident - index = prefix $ ident ++ "_repeater_index" - assign = constructor - (LHSBit (LHSIdent $ prefix ident) (Ident index)) - (Concat exprs) - inir = [Right (LHSIdent index, b)] - chkr = Just $ BinOp Le (Ident index) a - incr = [(LHSIdent index, AsgnOp Add, Number "1")] - convertAssignment constructor lhs expr = - constructor (rewriteLHS lhs) expr + rewriteLHS (LHSIdent x) = + LHSIdent x' + where Ident x' = rewriteExpr (Ident x) + rewriteLHS (orig @ (LHSBit (LHSBit (LHSIdent x) idxInner) idxOuter)) = + if Map.member x typeDims + then LHSBit (LHSIdent x') idx' + else orig + where Bit (Ident x') idx' = + rewriteExpr (Bit (Bit (Ident x) idxInner) idxOuter) + rewriteLHS (orig @ (LHSBit (LHSRange (LHSIdent x) modeInner rangeInner) idxOuter)) = + if Map.member x typeDims + then LHSRange (LHSIdent x') mode' range' + else orig + where Range (Ident x') mode' range' = + rewriteExpr (Bit (Range (Ident x) modeInner rangeInner) idxOuter) + rewriteLHS (orig @ (LHSBit (LHSIdent x) idx)) = + if Map.member x typeDims + then LHSRange (LHSIdent x') mode' range' + else orig + where Range (Ident x') mode' range' = rewriteExpr (Bit (Ident x) idx) + rewriteLHS (orig @ (LHSRange (LHSIdent x) mode range)) = + if Map.member x typeDims + then LHSRange (LHSIdent x') mode' range' + else orig + where Range (Ident x') mode' range' = + rewriteExpr (Range (Ident x) mode range) + rewriteLHS (orig @ (LHSRange (LHSBit (LHSIdent x) idxInner) modeOuter rangeOuter)) = + 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 diff --git a/src/Convert/Struct.hs b/src/Convert/Struct.hs index 2fed5a6..8445b95 100644 --- a/src/Convert/Struct.hs +++ b/src/Convert/Struct.hs @@ -101,7 +101,7 @@ convertType :: Structs -> Type -> Type convertType structs t1 = case Map.lookup tf1 structs of Nothing -> t1 - Just (t2, _) -> tf2 (rs2 ++ rs1) + Just (t2, _) -> tf2 (rs1 ++ rs2) where (tf2, rs2) = typeRanges t2 where (tf1, rs1) = typeRanges t1 @@ -141,30 +141,46 @@ convertAsgn structs types (lhs, expr) = Nothing -> (Implicit Unspecified [], LHSIdent x) Just t -> (t, LHSIdent x) convertLHS (LHSBit l e) = - if null rs - then (Implicit Unspecified [], LHSBit l' e') - else (tf $ tail rs, LHSBit l' e') - where - (t, l') = convertLHS l - (tf, rs) = typeRanges t - e' = snd $ convertSubExpr e - convertLHS (LHSRange l m rOuterOrig) = case l' of LHSRange lInner NonIndexed (_, loI) -> - (t, LHSRange lInner m (simplify hi, simplify lo)) + (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 + (t, l') = convertLHS l + t' = case typeRanges t of + (_, []) -> Implicit Unspecified [] + (tf, rs) -> tf $ tail rs + e' = snd $ convertSubExpr e + convertLHS (LHSRange lOuter NonIndexed rOuterOrig) = + case lOuter' of + LHSRange lInner NonIndexed (_, loI) -> + (t, LHSRange lInner NonIndexed (simplify hi, simplify lo)) where lo = BinOp Add loI loO hi = BinOp Add loI hiO - _ -> if null rs - then (Implicit Unspecified [], LHSRange l' m rOuter) - else (tf rs', LHSRange l' m rOuter) + LHSRange lInner IndexedPlus (baseI, _) -> + (t, LHSRange lInner IndexedPlus (simplify base, simplify len)) + where + base = BinOp Add baseI loO + len = rangeSize rOuter + _ -> (t, LHSRange lOuter' NonIndexed rOuter) where - (t, l') = convertLHS l - (tf, rs) = typeRanges t hiO = snd $ convertSubExpr $ fst rOuterOrig loO = snd $ convertSubExpr $ snd rOuterOrig 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 ) = case t of InterfaceT _ _ _ -> (Implicit Unspecified [], LHSDot l' x) @@ -236,18 +252,30 @@ convertAsgn structs types (lhs, expr) = structTf = Struct p fields fieldType = lookupFieldType fields 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 -- nested Ranges into a single range. My understanding of the -- semantics are that a range returns a new, zero-indexed sub-range. case eOuter' of Range eInner NonIndexed (_, loI) -> - (t, Range eInner m (simplify hi, simplify lo)) + (t, Range eInner NonIndexed (simplify hi, simplify lo)) where lo = BinOp Add loI loO 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 + 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) = (Implicit Unspecified [], Concat $ map (snd . convertSubExpr) exprs) convertSubExpr (BinOp op e1 e2) = @@ -259,6 +287,8 @@ convertAsgn structs types (lhs, expr) = case e' of Range eInner NonIndexed (_, loI) -> (t', Bit eInner (simplify $ BinOp Add loI i')) + Range eInner IndexedPlus (baseI, _) -> + (t', Bit eInner (simplify $ BinOp Add baseI i')) _ -> (t', Bit e' i') where (t, e') = convertSubExpr e diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index 868073b..7a79463 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -60,6 +60,7 @@ module Convert.Traverse , traverseNestedModuleItems , collectNestedModuleItemsM , traverseNestedStmts +, collectNestedStmtsM , traverseNestedExprs , collectNestedExprsM , traverseNestedLHSsM @@ -303,7 +304,7 @@ traverseAssertionExprsM mapper = assertionMapper return $ Cover e' stmt traverseStmtLHSsM :: Monad m => MapperM m LHS -> MapperM m Stmt -traverseStmtLHSsM mapper = traverseNestedStmtsM stmtMapper +traverseStmtLHSsM mapper = stmtMapper where fullMapper = mapper stmtMapper (Timing (Event sense) stmt) = do @@ -591,7 +592,7 @@ traverseLHSsM' strat mapper item = lhs' <- mapper lhs return $ NInputGate kw x lhs' exprs traverseModuleItemLHSsM (AssertionItem (mx, a)) = do - Assertion a' <- traverseStmtLHSsM mapper (Assertion a) + Assertion a' <- traverseNestedStmtsM (traverseStmtLHSsM mapper) (Assertion a) return $ AssertionItem (mx, a') traverseModuleItemLHSsM other = return other @@ -610,7 +611,7 @@ collectLHSsM = collectLHSsM' IncludeTFs traverseNestedLHSsM :: Monad m => MapperM m LHS -> MapperM m LHS traverseNestedLHSsM mapper = fullMapper where - fullMapper lhs = tl lhs >>= mapper + fullMapper lhs = mapper lhs >>= tl tl (LHSIdent x ) = return $ LHSIdent x tl (LHSBit l e ) = fullMapper l >>= \l' -> return $ LHSBit l' e tl (LHSRange l m r) = fullMapper l >>= \l' -> return $ LHSRange l' m r @@ -792,6 +793,8 @@ collectNestedModuleItemsM = collectify traverseNestedModuleItemsM traverseNestedStmts :: Mapper Stmt -> Mapper Stmt traverseNestedStmts = unmonad traverseNestedStmtsM +collectNestedStmtsM :: Monad m => CollectorM m Stmt -> CollectorM m Stmt +collectNestedStmtsM = collectify traverseNestedStmtsM traverseNestedExprs :: Mapper Expr -> Mapper Expr traverseNestedExprs = unmonad traverseNestedExprsM diff --git a/src/Convert/Typedef.hs b/src/Convert/Typedef.hs index b97980e..aadad1a 100644 --- a/src/Convert/Typedef.hs +++ b/src/Convert/Typedef.hs @@ -72,12 +72,12 @@ resolveType types (Alias st rs1) = if Map.notMember st types then InterfaceT st Nothing rs1 else case resolveType types $ types Map.! st of - (Net kw rs2) -> Net kw $ rs2 ++ rs1 - (Implicit sg rs2) -> Implicit sg $ rs2 ++ rs1 - (IntegerVector kw sg rs2) -> IntegerVector kw sg $ rs2 ++ rs1 - (Enum t v rs2) -> Enum t v $ rs2 ++ rs1 - (Struct p l rs2) -> Struct p l $ rs2 ++ rs1 - (InterfaceT x my rs2) -> InterfaceT x my $ rs2 ++ rs1 + (Net kw rs2) -> Net kw $ rs1 ++ rs2 + (Implicit sg rs2) -> Implicit sg $ rs1 ++ rs2 + (IntegerVector kw sg rs2) -> IntegerVector kw sg $ rs1 ++ rs2 + (Enum t v rs2) -> Enum t v $ rs1 ++ rs2 + (Struct p l rs2) -> Struct p l $ rs1 ++ rs2 + (InterfaceT x my rs2) -> InterfaceT x my $ rs1 ++ rs2 (IntegerAtom 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 diff --git a/src/Language/SystemVerilog/AST/Expr.hs b/src/Language/SystemVerilog/AST/Expr.hs index f5d81db..5a5c2f0 100644 --- a/src/Language/SystemVerilog/AST/Expr.hs +++ b/src/Language/SystemVerilog/AST/Expr.hs @@ -145,7 +145,10 @@ simplify other = other rangeSize :: Range -> Expr 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 -- range; [hi:lo] chooses the first expression diff --git a/test/basic/flatten.sv b/test/basic/flatten.sv index 4b52b8a..4c5875d 100644 --- a/test/basic/flatten.sv +++ b/test/basic/flatten.sv @@ -1,104 +1,55 @@ -`define CASE_A(name, dims) \ +`define CASE(name, dims, a, b) \ module name(clock, in, out); \ input wire clock, in; \ output logic dims out; \ - initial out[0] = 0; \ - initial out[1] = 0; \ - initial out[2] = 0; \ + initial out[0+a] = 0; \ + initial out[1+a] = 0; \ + initial out[2+a] = 0; \ always @(posedge clock) begin \ + /*$display($time, `" name ", out[0+a][1+b+:1]);*/ \ + /*$display($time, `" name ", out[0+a][1+b+:1]);*/ \ + /*$display($time, `" name ", out[1+a][1+b+:1]);*/ \ + /*$display($time, `" name ", out[1+a][1+b+:1]);*/ \ + /*$display($time, `" name ", out[2+a][1+b+:1]);*/ \ + /*$display($time, `" name ", out[2+a][1+b+:1]);*/ \ \ - out[2][4] = out[2][3]; \ - out[2][3] = out[2][2]; \ - out[2][2] = out[2][1]; \ - out[2][1] = out[2][0]; \ - out[2][0] = out[1][4]; \ + out[2+a][4+b] = out[2+a][3+b]; \ + out[2+a][3+b] = out[2+a][2+b]; \ + out[2+a][2+b] = out[2+a][1+b]; \ + out[2+a][1+b] = out[2+a][0+b]; \ + out[2+a][0+b] = out[1+a][4+b]; \ \ - out[1][4] = out[1][3]; \ - out[1][3] = out[1][2]; \ - out[1][2] = out[1][1]; \ - out[1][1] = out[1][0]; \ - out[1][0] = out[0][4]; \ + out[1+a][4+b] = out[1+a][3+b]; \ + out[1+a][3+b] = out[1+a][2+b]; \ + out[1+a][2+b] = out[1+a][1+b]; \ + out[1+a][1+b] = out[1+a][0+b]; \ + out[1+a][0+b] = out[0+a][4+b]; \ \ - out[0][4] = out[0][3]; \ - out[0][3] = out[0][2]; \ - out[0][2] = out[0][1]; \ - out[0][1] = out[0][0]; \ - out[0][0] = in; \ + 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 \ endmodule -`CASE_A(A1, [2:0][4:0]) -`CASE_A(A2, [0:2][0:4]) -`CASE_A(A3, [0:2][4:0]) -`CASE_A(A4, [2:0][0:4]) +`CASE(A1, [2:0][4:0], 0, 0) +`CASE(A2, [0:2][0:4], 0, 0) +`CASE(A3, [0:2][4:0], 0, 0) +`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(B1, [3:1][5:1], 1, 1) +`CASE(B2, [1:3][1:5], 1, 1) +`CASE(B3, [1:3][5:1], 1, 1) +`CASE(B4, [3:1][1:5], 1, 1) -`CASE_B(B1, [3:1][5:1]) -`CASE_B(B2, [1:3][1:5]) -`CASE_B(B3, [1:3][5:1]) -`CASE_B(B4, [3:1][1:5]) +`CASE(C1, [4:2][6:2], 2, 2) +`CASE(C2, [2:4][2:6], 2, 2) +`CASE(C3, [2:4][6:2], 2, 2) +`CASE(C4, [4:2][2:6], 2, 2) -`define CASE_C(name, dims) \ -module name(clock, in, out); \ - input wire clock, in; \ - output logic dims out; \ - 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_C(C2, [2:4][2:6]) -`CASE_C(C3, [2:4][6:2]) -`CASE_C(C4, [4:2][2:6]) +`CASE(D1, [5:3][6:2], 3, 2) +`CASE(D2, [3:5][2:6], 3, 2) +`CASE(D3, [3:5][6:2], 3, 2) +`CASE(D4, [5:3][2:6], 3, 2) diff --git a/test/basic/flatten_tb.v b/test/basic/flatten_tb.v index a9da44f..04fd71c 100644 --- a/test/basic/flatten_tb.v +++ b/test/basic/flatten_tb.v @@ -4,9 +4,13 @@ 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``4 tag``fou(.clock(clock), .in(in), .out(tag``fou_out)); \ + integer tag``i; \ initial begin \ - $monitor(`"tag", $time, ": %h %15b %15b %15b %15b", in, \ - tag``one_out, tag``two_out, tag``thr_out, tag``fou_out); \ + 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); \ + end \ end module top; @@ -30,5 +34,6 @@ module top; `FOO(A) `FOO(B) `FOO(C) + `FOO(D) endmodule diff --git a/test/basic/multipack.sv b/test/basic/multipack.sv new file mode 100644 index 0000000..cd327a2 --- /dev/null +++ b/test/basic/multipack.sv @@ -0,0 +1,66 @@ +`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 diff --git a/test/basic/multipack.v b/test/basic/multipack.v new file mode 100644 index 0000000..ce211c9 --- /dev/null +++ b/test/basic/multipack.v @@ -0,0 +1,65 @@ +`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 diff --git a/test/basic/multipack_tb.v b/test/basic/multipack_tb.v new file mode 100644 index 0000000..27306d4 --- /dev/null +++ b/test/basic/multipack_tb.v @@ -0,0 +1,3 @@ +module top; + Example example(); +endmodule diff --git a/test/basic/struct_array.sv b/test/basic/struct_array.sv new file mode 100644 index 0000000..c87814d --- /dev/null +++ b/test/basic/struct_array.sv @@ -0,0 +1,17 @@ +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 diff --git a/test/basic/struct_array.v b/test/basic/struct_array.v new file mode 100644 index 0000000..5101a7a --- /dev/null +++ b/test/basic/struct_array.v @@ -0,0 +1,13 @@ +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 diff --git a/test/basic/struct_array_tb.v b/test/basic/struct_array_tb.v new file mode 100644 index 0000000..747b80d --- /dev/null +++ b/test/basic/struct_array_tb.v @@ -0,0 +1,34 @@ +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