Commit 96e0aff7 by Zachary Snow

handle TF decl shadowing within packed array conversion

parent 8d77856b
...@@ -12,11 +12,8 @@ ...@@ -12,11 +12,8 @@
- the array as appropriate. - the array as appropriate.
- -
- Note that the ranges being combined may not be of the form [hi:lo], and need - 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 - not even be the same direction! Because of this, we have to flip around the
- the indices of certain accesses. - 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
...@@ -24,133 +21,163 @@ module Convert.PackedArray (convert) where ...@@ -24,133 +21,163 @@ module Convert.PackedArray (convert) where
import Control.Monad.State import Control.Monad.State
import Data.Tuple (swap) import Data.Tuple (swap)
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Convert.Traverse import Convert.Traverse
import Language.SystemVerilog.AST 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 data Info = Info
{ sTypeDims :: DimMap { sTypeDims :: DimMap
, sIdents :: IdentSet
} deriving Show } deriving Show
defaultInfo :: Info
defaultInfo = Info Map.empty Set.empty
convert :: AST -> AST convert :: AST -> AST
convert = traverseDescriptions convertDescription convert = traverseDescriptions convertDescription
convertDescription :: Description -> Description convertDescription :: Description -> Description
convertDescription (description @ (Part _ _ _ _ _ _)) = convertDescription (description @ (Part _ _ _ _ _ _)) =
traverseModuleItems (flattenModuleItem info . rewriteModuleItem info) description traverseModuleItems (convertModuleItem info) description
where where
-- collect all possible information info our Info structure collector = collectModuleItemsM $ collectDeclsM' ExcludeTFs collectDecl
info = info = execState (collector description) defaultInfo
execState (collectModuleItemsM collectDecl description) $
execState (collectModuleItemsM collectTF description) $
(Info Map.empty)
convertDescription description = description convertDescription description = description
-- collects port direction and packed-array dimension info into the state -- collects packed-array dimension and variable existing info into the state
collectDecl :: ModuleItem -> State Info () collectDecl :: Decl -> State Info ()
collectDecl (MIDecl (Variable _ t ident _ _)) = do collectDecl (Variable _ t ident _ _) = do
let (tf, rs) = typeRanges t Info typeDims idents <- get
if not (typeIsImplicit t) && length rs > 1 let (_, rs) = typeRanges t
then let typeDims' =
let dets = (tf $ tail rs, head rs) in if not (isImplicit t) && length rs > 1
modify $ \s -> s { sTypeDims = Map.insert ident dets (sTypeDims s) } then Map.insert ident rs typeDims
else return () 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 () collectDecl _ = return ()
-- collects task and function info into the state -- shadows the latter info with the former
collectTF :: ModuleItem -> State Info () combineInfo :: Info -> Info -> Info
collectTF (MIPackageItem (Function _ t x decls _)) = do combineInfo local global =
collectDecl (MIDecl $ Variable Local t x [] Nothing) Info typeDims idents
_ <- mapM collectDecl $ map MIDecl decls where
return () Info globalTypeDims globalIdents = global
collectTF (MIPackageItem (Task _ _ decls _)) = do Info localTypeDims localIdents = local
_ <- mapM collectDecl $ map MIDecl decls idents = Set.union globalIdents localIdents
return () typeDims = Map.union localTypeDims $
collectTF _ = return () Map.withoutKeys globalTypeDims localIdents
-- rewrite a module item if it contains a declaration to flatten -- Convert the multi-dimensional packed arrays within the given module item.
flattenModuleItem :: Info -> ModuleItem -> ModuleItem -- This function must ensure that function/task level shadowing is respected.
flattenModuleItem info (MIPackageItem (Function ml t x decls stmts)) = convertModuleItem :: Info -> ModuleItem -> ModuleItem
MIPackageItem $ Function ml t' x decls' stmts convertModuleItem globalInfo (orig @ (MIPackageItem (Function ml t x decls stmts))) =
rewrite info $
MIPackageItem $ Function ml t' x decls stmts
where where
MIPackageItem (Task _ _ decls' _) = localInfo =
flattenModuleItem info $ MIPackageItem $ Task ml x decls stmts execState (collectDecl $ Variable Local t x [] Nothing) $
MIDecl (Variable Local t' _ [] Nothing) = execState (collectDeclsM collectDecl orig) $
flattenModuleItem info $ MIDecl (Variable Local t x [] Nothing) defaultInfo
flattenModuleItem info (MIPackageItem (Task ml x decls stmts)) = info = combineInfo localInfo globalInfo
MIPackageItem $ Task ml x decls' stmts -- 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 where
decls' = map mapDecl decls localInfo =
mapDecl :: Decl -> Decl execState (collectDeclsM collectDecl orig) $
mapDecl decl = decl' defaultInfo
where MIDecl decl' = flattenModuleItem info $ MIDecl decl info = combineInfo localInfo globalInfo
flattenModuleItem info (origDecl @ (MIDecl (Variable dir t ident a me))) = 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 if Map.notMember ident typeDims
then origDecl then origDecl
else flatDecl else flatDecl
where where
Info typeDims = info typeDims = sTypeDims info
(tf, rs) = typeRanges t (tf, rs) = typeRanges t
flatDecl = MIDecl $ Variable dir (tf $ flattenRanges rs) ident a me r1 : r2 : rest = rs
flattenModuleItem _ other = other rs' = (combineRanges r1 r2) : rest
flatDecl = Variable dir (tf rs') ident a me
flattenDecl _ other = other
typeIsImplicit :: Type -> Bool -- combines two ranges into one flattened range
typeIsImplicit (Implicit _ _) = True combineRanges :: Range -> Range -> Range
typeIsImplicit _ = False combineRanges r1 r2 = r
-- 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)
where where
r1 = head rs rYY = combine r1 r2
r2 = head $ tail rs rYN = combine r1 (swap r2)
rYY = flattenRangesHelp r1 r2 rNY = combine (swap r1) r2
rYN = flattenRangesHelp r1 (swap r2) rNN = combine (swap r1) (swap r2)
rNY = flattenRangesHelp (swap r1) 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
r = endianCondRange r1 rY rN r = endianCondRange r1 rY rN
rs' = r : (tail $ tail rs)
flattenRangesHelp :: Range -> Range -> Range combine :: Range -> Range -> Range
flattenRangesHelp (s1, e1) (s2, e2) = combine (s1, e1) (s2, e2) =
(simplify upper, simplify lower) (simplify upper, simplify lower)
where where
size1 = rangeSize (s1, e1) size1 = rangeSize (s1, e1)
size2 = rangeSize (s2, e2) size2 = rangeSize (s2, e2)
lower = BinOp Add e2 (BinOp Mul e1 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 -- rewrite the declarations, expressions, and lvals in a module item to remove
rewriteModuleItem info = -- the packed array dimensions captured in the given info
rewrite :: Info -> ModuleItem -> ModuleItem
rewrite info =
traverseDecls (flattenDecl info) .
traverseLHSs (traverseNestedLHSs rewriteLHS ) . traverseLHSs (traverseNestedLHSs rewriteLHS ) .
traverseExprs (traverseNestedExprs rewriteExpr) traverseExprs (traverseNestedExprs rewriteExpr)
where where
Info typeDims = info typeDims = sTypeDims info
dims :: Identifier -> (Range, Range) dims :: Identifier -> (Range, Range)
dims x = dims x =
(dimInner, dimOuter) (dimInner, dimOuter)
where where
(t, r) = typeDims Map.! x dimInner : dimOuter : _ = typeDims Map.! x
dimInner = r
dimOuter = head $ snd $ typeRanges t
-- if the given range is flipped, the result will flip around the given
-- indexing expression
orientIdx :: Range -> Expr -> Expr orientIdx :: Range -> Expr -> Expr
orientIdx r e = orientIdx r e =
endianCondExpr r e eSwapped endianCondExpr r e eSwapped
where where
eSwapped = BinOp Sub (snd r) (BinOp Sub e (fst r)) 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 :: Expr -> Expr
rewriteExpr (Ident x) = rewriteExpr (Ident x) =
if head x == ':' if head x == tag
then Ident $ tail x then Ident $ tail x
else Ident x else Ident x
rewriteExpr (orig @ (Bit (Bit (Ident x) idxInner) idxOuter)) = rewriteExpr (orig @ (Bit (Bit (Ident x) idxInner) idxOuter)) =
...@@ -159,7 +186,7 @@ rewriteModuleItem info = ...@@ -159,7 +186,7 @@ rewriteModuleItem info =
else orig else orig
where where
(dimInner, dimOuter) = dims x (dimInner, dimOuter) = dims x
x' = ':' : x x' = tag : x
idxInner' = orientIdx dimInner idxInner idxInner' = orientIdx dimInner idxInner
idxOuter' = orientIdx dimOuter idxOuter idxOuter' = orientIdx dimOuter idxOuter
base = BinOp Mul idxInner' (rangeSize dimOuter) base = BinOp Mul idxInner' (rangeSize dimOuter)
...@@ -170,7 +197,7 @@ rewriteModuleItem info = ...@@ -170,7 +197,7 @@ rewriteModuleItem info =
else orig else orig
where where
(dimInner, dimOuter) = dims x (dimInner, dimOuter) = dims x
x' = ':' : x x' = tag : x
mode' = IndexedPlus mode' = IndexedPlus
idx' = orientIdx dimInner idx idx' = orientIdx dimInner idx
len = rangeSize dimOuter len = rangeSize dimOuter
...@@ -182,7 +209,7 @@ rewriteModuleItem info = ...@@ -182,7 +209,7 @@ rewriteModuleItem info =
else orig else orig
where where
(_, dimOuter) = dims x (_, dimOuter) = dims x
x' = ':' : x x' = tag : x
mode' = mode mode' = mode
size = rangeSize dimOuter size = rangeSize dimOuter
base = endianCondExpr dimOuter (snd dimOuter) (fst dimOuter) base = endianCondExpr dimOuter (snd dimOuter) (fst dimOuter)
...@@ -201,7 +228,7 @@ rewriteModuleItem info = ...@@ -201,7 +228,7 @@ rewriteModuleItem info =
else orig else orig
where where
(dimInner, dimOuter) = dims x (dimInner, dimOuter) = dims x
x' = ':' : x x' = tag : x
mode' = IndexedPlus mode' = IndexedPlus
idxInner' = orientIdx dimInner idxInner idxInner' = orientIdx dimInner idxInner
rangeOuterReverseIndexed = rangeOuterReverseIndexed =
...@@ -222,6 +249,9 @@ rewriteModuleItem info = ...@@ -222,6 +249,9 @@ rewriteModuleItem info =
range' = (base, len) range' = (base, len)
rewriteExpr other = other 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 :: LHS -> LHS
rewriteLHS (LHSIdent x) = rewriteLHS (LHSIdent x) =
LHSIdent x' LHSIdent x'
......
...@@ -656,28 +656,28 @@ collectNestedLHSsM = collectify traverseNestedLHSsM ...@@ -656,28 +656,28 @@ collectNestedLHSsM = collectify traverseNestedLHSsM
traverseDeclsM' :: Monad m => TFStrategy -> MapperM m Decl -> MapperM m ModuleItem traverseDeclsM' :: Monad m => TFStrategy -> MapperM m Decl -> MapperM m ModuleItem
traverseDeclsM' strat mapper item = do traverseDeclsM' strat mapper item = do
item' <- miMapperA item item' <- miMapper item
traverseStmtsM' strat miMapperB item' traverseStmtsM' strat stmtMapper item'
where where
miMapperA (MIDecl decl) = miMapper (MIDecl decl) =
mapper decl >>= return . MIDecl mapper decl >>= return . MIDecl
miMapperA (MIPackageItem (Function l t x decls s)) = do miMapper (MIPackageItem (Function l t x decls stmts)) = do
decls' <- decls' <-
if strat == IncludeTFs if strat == IncludeTFs
then mapM mapper decls then mapM mapper decls
else return decls else return decls
return $ MIPackageItem $ Function l t x decls' s return $ MIPackageItem $ Function l t x decls' stmts
miMapperA (MIPackageItem (Task l x decls s)) = do miMapper (MIPackageItem (Task l x decls stmts)) = do
decls' <- decls' <-
if strat == IncludeTFs if strat == IncludeTFs
then mapM mapper decls then mapM mapper decls
else return decls else return decls
return $ MIPackageItem $ Task l x decls' s return $ MIPackageItem $ Task l x decls' stmts
miMapperA other = return other miMapper other = return other
miMapperB (Block name decls stmts) = do stmtMapper (Block name decls stmts) = do
decls' <- mapM mapper decls decls' <- mapM mapper decls
return $ Block name decls' stmts return $ Block name decls' stmts
miMapperB other = return other stmtMapper other = return other
traverseDecls' :: TFStrategy -> Mapper Decl -> Mapper ModuleItem traverseDecls' :: TFStrategy -> Mapper Decl -> Mapper ModuleItem
traverseDecls' strat = unmonad $ traverseDeclsM' strat traverseDecls' strat = unmonad $ traverseDeclsM' strat
......
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
// iverilog has support for packed arrays and functions
`include "packed_array_shadow.sv"
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