From 96e0aff7f47f5ebf7ab5d7fac36920add15917b5 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Wed, 17 Apr 2019 20:05:55 -0400 Subject: [PATCH] handle TF decl shadowing within packed array conversion --- src/Convert/PackedArray.hs | 200 ++++++++++++++++------------ src/Convert/Traverse.hs | 20 +-- test/basic/packed_array_shadow.sv | 114 ++++++++++++++++ test/basic/packed_array_shadow.v | 2 + test/basic/packed_array_shadow_tb.v | 1 + 5 files changed, 242 insertions(+), 95 deletions(-) create mode 100644 test/basic/packed_array_shadow.sv create mode 100644 test/basic/packed_array_shadow.v create mode 100644 test/basic/packed_array_shadow_tb.v diff --git a/src/Convert/PackedArray.hs b/src/Convert/PackedArray.hs index ede5b6d..a0b189b 100644 --- a/src/Convert/PackedArray.hs +++ b/src/Convert/PackedArray.hs @@ -12,11 +12,8 @@ - the array as appropriate. - - 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. + - not even be the same direction! Because of this, we have to flip around the + - indices of certain accesses. -} module Convert.PackedArray (convert) where @@ -24,133 +21,163 @@ module Convert.PackedArray (convert) where import Control.Monad.State import Data.Tuple (swap) import qualified Data.Map.Strict as Map +import qualified Data.Set as Set import Convert.Traverse import Language.SystemVerilog.AST -type DimMap = Map.Map Identifier (Type, Range) +type DimMap = Map.Map Identifier [Range] +type IdentSet = Set.Set Identifier data Info = Info { sTypeDims :: DimMap + , sIdents :: IdentSet } deriving Show +defaultInfo :: Info +defaultInfo = Info Map.empty Set.empty + convert :: AST -> AST convert = traverseDescriptions convertDescription convertDescription :: Description -> Description convertDescription (description @ (Part _ _ _ _ _ _)) = - traverseModuleItems (flattenModuleItem info . rewriteModuleItem info) description + traverseModuleItems (convertModuleItem info) description where - -- collect all possible information info our Info structure - info = - execState (collectModuleItemsM collectDecl description) $ - execState (collectModuleItemsM collectTF description) $ - (Info Map.empty) + collector = collectModuleItemsM $ collectDeclsM' ExcludeTFs collectDecl + info = execState (collector description) defaultInfo convertDescription description = description --- collects port direction and packed-array dimension info into the state -collectDecl :: ModuleItem -> State Info () -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 () +-- collects packed-array dimension and variable existing info into the state +collectDecl :: Decl -> State Info () +collectDecl (Variable _ t ident _ _) = do + Info typeDims idents <- get + let (_, rs) = typeRanges t + let typeDims' = + if not (isImplicit t) && length rs > 1 + then Map.insert ident rs typeDims + else typeDims + let idents' = + if not (isImplicit t) + then + if Set.member ident idents + then error $ "unsupported complex shadowing of " ++ show ident + else Set.insert ident idents + else idents + put $ Info typeDims' idents' + where + isImplicit :: Type -> Bool + isImplicit (Implicit _ _) = True + isImplicit _ = False collectDecl _ = return () --- collects task and function info into the state -collectTF :: ModuleItem -> State Info () -collectTF (MIPackageItem (Function _ t x decls _)) = do - collectDecl (MIDecl $ Variable Local t x [] Nothing) - _ <- mapM collectDecl $ map MIDecl decls - return () -collectTF (MIPackageItem (Task _ _ decls _)) = do - _ <- mapM collectDecl $ map MIDecl decls - return () -collectTF _ = return () +-- shadows the latter info with the former +combineInfo :: Info -> Info -> Info +combineInfo local global = + Info typeDims idents + where + Info globalTypeDims globalIdents = global + Info localTypeDims localIdents = local + idents = Set.union globalIdents localIdents + typeDims = Map.union localTypeDims $ + Map.withoutKeys globalTypeDims localIdents --- rewrite a module item if it contains a declaration to flatten -flattenModuleItem :: Info -> ModuleItem -> ModuleItem -flattenModuleItem info (MIPackageItem (Function ml t x decls stmts)) = - MIPackageItem $ Function ml t' x decls' stmts +-- Convert the multi-dimensional packed arrays within the given module item. +-- This function must ensure that function/task level shadowing is respected. +convertModuleItem :: Info -> ModuleItem -> ModuleItem +convertModuleItem globalInfo (orig @ (MIPackageItem (Function ml t x decls stmts))) = + rewrite info $ + MIPackageItem $ Function ml t' x decls stmts where - MIPackageItem (Task _ _ decls' _) = - flattenModuleItem info $ MIPackageItem $ Task ml x decls stmts - MIDecl (Variable Local t' _ [] Nothing) = - flattenModuleItem info $ MIDecl (Variable Local t x [] Nothing) -flattenModuleItem info (MIPackageItem (Task ml x decls stmts)) = - MIPackageItem $ Task ml x decls' stmts + localInfo = + execState (collectDecl $ Variable Local t x [] Nothing) $ + execState (collectDeclsM collectDecl orig) $ + defaultInfo + info = combineInfo localInfo globalInfo + -- rewrite the return type of this function + Variable Local t' _ [] Nothing = + flattenDecl info $ Variable Local t x [] Nothing +convertModuleItem globalInfo (orig @ (MIPackageItem (Task ml x decls stmts))) = + rewrite info $ + MIPackageItem $ Task ml x decls stmts where - decls' = map mapDecl decls - mapDecl :: Decl -> Decl - mapDecl decl = decl' - where MIDecl decl' = flattenModuleItem info $ MIDecl decl -flattenModuleItem info (origDecl @ (MIDecl (Variable dir t ident a me))) = + localInfo = + execState (collectDeclsM collectDecl orig) $ + defaultInfo + info = combineInfo localInfo globalInfo +convertModuleItem info other = + rewrite info other + +-- combine the leading two packed ranges of a declaration +flattenDecl :: Info -> Decl -> Decl +flattenDecl info (origDecl @ (Variable dir t ident a me)) = if Map.notMember ident typeDims then origDecl else flatDecl where - Info typeDims = info + typeDims = sTypeDims info (tf, rs) = typeRanges t - flatDecl = MIDecl $ Variable dir (tf $ flattenRanges rs) ident a me -flattenModuleItem _ other = other + r1 : r2 : rest = rs + rs' = (combineRanges r1 r2) : rest + flatDecl = Variable dir (tf rs') ident a me +flattenDecl _ other = other -typeIsImplicit :: Type -> Bool -typeIsImplicit (Implicit _ _) = True -typeIsImplicit _ = False - --- combines (flattens) the bottom two ranges in the given list of ranges -flattenRanges :: [Range] -> [Range] -flattenRanges rs = - if length rs >= 2 - then rs' - else error $ "flattenRanges on too small list: " ++ (show rs) +-- combines two ranges into one flattened range +combineRanges :: Range -> Range -> Range +combineRanges r1 r2 = r where - r1 = head rs - r2 = head $ tail rs - rYY = flattenRangesHelp r1 r2 - rYN = flattenRangesHelp r1 (swap r2) - rNY = flattenRangesHelp (swap r1) r2 - rNN = flattenRangesHelp (swap r1) (swap r2) + rYY = combine r1 r2 + rYN = combine r1 (swap r2) + rNY = combine (swap r1) r2 + rNN = combine (swap r1) (swap r2) rY = endianCondRange r2 rYY rYN rN = endianCondRange r2 rNY rNN r = endianCondRange r1 rY rN - rs' = r : (tail $ tail rs) -flattenRangesHelp :: Range -> Range -> Range -flattenRangesHelp (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")) + 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")) -rewriteModuleItem :: Info -> ModuleItem -> ModuleItem -rewriteModuleItem info = +-- rewrite the declarations, expressions, and lvals in a module item to remove +-- the packed array dimensions captured in the given info +rewrite :: Info -> ModuleItem -> ModuleItem +rewrite info = + traverseDecls (flattenDecl info) . traverseLHSs (traverseNestedLHSs rewriteLHS ) . traverseExprs (traverseNestedExprs rewriteExpr) where - Info typeDims = info + typeDims = sTypeDims info dims :: Identifier -> (Range, Range) dims x = (dimInner, dimOuter) where - (t, r) = typeDims Map.! x - dimInner = r - dimOuter = head $ snd $ typeRanges t + dimInner : dimOuter : _ = typeDims Map.! x + -- if the given range is flipped, the result will flip around the given + -- indexing expression orientIdx :: Range -> Expr -> Expr orientIdx r e = endianCondExpr r e eSwapped where eSwapped = BinOp Sub (snd r) (BinOp Sub e (fst r)) + -- 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 = ':' + rewriteExpr :: Expr -> Expr rewriteExpr (Ident x) = - if head x == ':' + if head x == tag then Ident $ tail x else Ident x rewriteExpr (orig @ (Bit (Bit (Ident x) idxInner) idxOuter)) = @@ -159,7 +186,7 @@ rewriteModuleItem info = else orig where (dimInner, dimOuter) = dims x - x' = ':' : x + x' = tag : x idxInner' = orientIdx dimInner idxInner idxOuter' = orientIdx dimOuter idxOuter base = BinOp Mul idxInner' (rangeSize dimOuter) @@ -170,7 +197,7 @@ rewriteModuleItem info = else orig where (dimInner, dimOuter) = dims x - x' = ':' : x + x' = tag : x mode' = IndexedPlus idx' = orientIdx dimInner idx len = rangeSize dimOuter @@ -182,7 +209,7 @@ rewriteModuleItem info = else orig where (_, dimOuter) = dims x - x' = ':' : x + x' = tag : x mode' = mode size = rangeSize dimOuter base = endianCondExpr dimOuter (snd dimOuter) (fst dimOuter) @@ -201,7 +228,7 @@ rewriteModuleItem info = else orig where (dimInner, dimOuter) = dims x - x' = ':' : x + x' = tag : x mode' = IndexedPlus idxInner' = orientIdx dimInner idxInner rangeOuterReverseIndexed = @@ -222,6 +249,9 @@ rewriteModuleItem info = range' = (base, len) rewriteExpr other = other + -- LHSs need to be converted too. Rather than duplicating the + -- procedures, we turn the relevant LHSs into expressions temporarily + -- and use the expression conversion written above. rewriteLHS :: LHS -> LHS rewriteLHS (LHSIdent x) = LHSIdent x' diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index c65f0de..84b85f7 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -656,28 +656,28 @@ collectNestedLHSsM = collectify traverseNestedLHSsM traverseDeclsM' :: Monad m => TFStrategy -> MapperM m Decl -> MapperM m ModuleItem traverseDeclsM' strat mapper item = do - item' <- miMapperA item - traverseStmtsM' strat miMapperB item' + item' <- miMapper item + traverseStmtsM' strat stmtMapper item' where - miMapperA (MIDecl decl) = + miMapper (MIDecl decl) = mapper decl >>= return . MIDecl - miMapperA (MIPackageItem (Function l t x decls s)) = do + miMapper (MIPackageItem (Function l t x decls stmts)) = do decls' <- if strat == IncludeTFs then mapM mapper decls else return decls - return $ MIPackageItem $ Function l t x decls' s - miMapperA (MIPackageItem (Task l x decls s)) = do + return $ MIPackageItem $ Function l t x decls' stmts + miMapper (MIPackageItem (Task l x decls stmts)) = do decls' <- if strat == IncludeTFs then mapM mapper decls else return decls - return $ MIPackageItem $ Task l x decls' s - miMapperA other = return other - miMapperB (Block name decls stmts) = do + return $ MIPackageItem $ Task l x decls' stmts + miMapper other = return other + stmtMapper (Block name decls stmts) = do decls' <- mapM mapper decls return $ Block name decls' stmts - miMapperB other = return other + stmtMapper other = return other traverseDecls' :: TFStrategy -> Mapper Decl -> Mapper ModuleItem traverseDecls' strat = unmonad $ traverseDeclsM' strat diff --git a/test/basic/packed_array_shadow.sv b/test/basic/packed_array_shadow.sv new file mode 100644 index 0000000..6f1b668 --- /dev/null +++ b/test/basic/packed_array_shadow.sv @@ -0,0 +1,114 @@ +module top; + + function parity; + input [3:0] arr; + parity = arr[2] ^ arr[2] ^ arr[1] ^ arr[0]; + endfunction + + task loop; + input [3:0] arr; + begin + arr = 4'b0000; + repeat (2**4) begin + $display("%04b -> %d", arr, parity(arr)); + arr += 1; + end + end + endtask + + task dump; + begin : dump_block + integer i; + for (i = 0; i < 7; i += 1) begin + $display("arr[%1d] = %04b", i, arr[i]); + end + end + endtask + + task reinterpret; + input [3:0][6:0] arr; + begin : reinterpret_block + integer i; + for (i = 0; i < 4; i += 1) begin + $display("arr'[%1d] = %07b", i, arr[i]); + end + end + endtask + + logic [6:0][3:0] arr; + initial arr = 28'h9fba7d; + + integer i; + initial begin + for (i = 0; i < 7; i += 1) begin + loop(arr[i]); + dump(); + reinterpret(arr); + end + end + + + logic [1:0] foolA; + initial begin + foolA = 2'b10; + foolAer(4'b1001); + $display("initalA: $bits(foolA): ", $bits(foolA )); + $display("initalA: $bits(foolA[0]): ", $bits(foolA[0])); + $display("initalA: foolA[0]: ", foolA[0]); + $display("initalA: foolA[1]: ", foolA[1]); + end + task foolAer; + input [1:0][1:0] foolA; + begin + $display("foolAer: $bits(foolA): ", $bits(foolA )); + $display("foolAer: $bits(foolA[0]): ", $bits(foolA[0] )); + $display("foolAer: $bits(foolA[0][0]): ", $bits(foolA[0][0])); + $display("foolAer: foolA[0][0]: ", foolA[0][0]); + $display("foolAer: foolA[0][1]: ", foolA[0][1]); + $display("foolAer: foolA[1][0]: ", foolA[1][0]); + $display("foolAer: foolA[1][1]: ", foolA[1][1]); + end + endtask + + + task foolBer; + input [1:0][1:0] foolB; + begin + $display("foolBer: $bits(foolB): ", $bits(foolB )); + $display("foolBer: $bits(foolB[0]): ", $bits(foolB[0] )); + $display("foolBer: $bits(foolB[0][0]): ", $bits(foolB[0][0])); + $display("foolBer: foolB[0][0]: ", foolB[0][0]); + $display("foolBer: foolB[0][1]: ", foolB[0][1]); + $display("foolBer: foolB[1][0]: ", foolB[1][0]); + $display("foolBer: foolB[1][1]: ", foolB[1][1]); + end + endtask + logic [1:0] foolB; + initial begin + foolB = 2'b10; + foolBer(4'b1001); + $display("initalB: $bits(foolB): ", $bits(foolB )); + $display("initalB: $bits(foolB[0]): ", $bits(foolB[0])); + $display("initalB: foolB[0]: ", foolB[0]); + $display("initalB: foolB[1]: ", foolB[1]); + end + + + task magic; + begin + begin : magic_block + logic [1:0][1:0] magic_arr; + magic_arr = 4'b1001; + $display("$bits(magic_arr): ", $bits(magic_arr )); + $display("$bits(magic_arr[0]): ", $bits(magic_arr[0] )); + $display("$bits(magic_arr[0][0]): ", $bits(magic_arr[0][0])); + $display("magic_arr[0][0]: ", magic_arr[0][0]); + $display("magic_arr[0][1]: ", magic_arr[0][1]); + $display("magic_arr[1][0]: ", magic_arr[1][0]); + $display("magic_arr[1][1]: ", magic_arr[1][1]); + end + end + endtask + initial magic(); + +endmodule diff --git a/test/basic/packed_array_shadow.v b/test/basic/packed_array_shadow.v new file mode 100644 index 0000000..81f94d1 --- /dev/null +++ b/test/basic/packed_array_shadow.v @@ -0,0 +1,2 @@ +// iverilog has support for packed arrays and functions +`include "packed_array_shadow.sv" diff --git a/test/basic/packed_array_shadow_tb.v b/test/basic/packed_array_shadow_tb.v new file mode 100644 index 0000000..d11c69f --- /dev/null +++ b/test/basic/packed_array_shadow_tb.v @@ -0,0 +1 @@ +// intentionally empty