Commit a8f2cbbe by Zachary Snow

struct conversion supports complex shadowing

parent 05b7bdb9
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for `packed struct`
- Conversion for `struct packed`
-}
module Convert.Struct (convert) where
......@@ -10,6 +10,7 @@ import Data.Hashable (hash)
import Data.Maybe (fromJust, isJust)
import Data.List (elemIndex, sortOn)
import Data.Tuple (swap)
import Control.Monad.State
import Control.Monad.Writer
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
......@@ -28,21 +29,15 @@ convert = traverseDescriptions convertDescription
convertDescription :: Description -> Description
convertDescription (description @ (Part _ _ _ _ _ _)) =
traverseModuleItems (traverseTypes $ convertType structs) $
Part extern kw lifetime name ports (items ++ funcs)
where
description' @ (Part extern kw lifetime name ports items) =
traverseModuleItems (traverseExprs $ traverseNestedExprs $ convertOnlyExpr structs types) $
traverseModuleItems (traverseTypes $ convertType structs) $
traverseModuleItems (traverseAsgns $ convertAsgn structs types) $
description
scopedConversion traverseDeclM traverseModuleItemM traverseStmtM
Map.empty description
-- collect information about this description
structs = execWriter $ collectModuleItemsM
(collectTypesM collectType) description
typesA = execWriter $ collectModuleItemsM
(collectDeclsM collectDecl) description
typesB = execWriter $ collectModuleItemsM
collectFunction description
types = Map.union typesA typesB
-- determine which of the packer functions we actually need
calledFuncs = execWriter $ collectModuleItemsM
(collectExprsM $ collectNestedExprsM collectCalls) description'
......@@ -51,6 +46,17 @@ convertDescription (description @ (Part _ _ _ _ _ _)) =
funcs = map packerFn usedStructs
usedStructs = filter (isNeeded . fst) $ Map.toList structs
isNeeded tf = Set.member (packerFnName tf) calledPackedFuncs
-- helpers for the scoped traversal
traverseModuleItemM :: ModuleItem -> State Types ModuleItem
traverseModuleItemM item =
traverseExprsM traverseExprM item >>=
traverseAsgnsM traverseAsgnM
traverseStmtM :: Stmt -> State Types Stmt
traverseStmtM stmt =
traverseStmtExprsM traverseExprM stmt >>=
traverseStmtAsgnsM traverseAsgnM
traverseExprM = traverseNestedExprsM $ stately $ convertOnlyExpr structs
traverseAsgnM = stately $ convertAsgn structs
convertDescription other = other
-- writes down the names of called functions
......@@ -137,22 +143,14 @@ convertType structs t1 =
where (tf1, rs1) = typeRanges t1
-- write down the type a declarations
collectDecl :: Decl -> Writer Types ()
collectDecl (Variable _ (Implicit _ []) _ _ _) = return ()
collectDecl (Variable _ t x a _) =
-- We add the unpacked dimensions to the type so that our type traversal can
-- correctly match-off the dimensions whenever we see a `Bit` or `Range`
-- expression.
tell $ Map.singleton x (tf $ rs ++ a)
where (tf, rs) = typeRanges t
collectDecl (Parameter t x _) = tell $ Map.singleton x t
collectDecl (Localparam t x _) = tell $ Map.singleton x t
-- write down the return type of a function
collectFunction :: ModuleItem -> Writer Types ()
collectFunction (MIPackageItem (Function _ t f _ _)) = tell $ Map.singleton f t
collectFunction _ = return ()
-- write down the types of declarations
traverseDeclM :: Decl -> State Types Decl
traverseDeclM origDecl = do
case origDecl of
Variable _ t x _ _ -> modify $ Map.insert x t
Parameter t x _ -> modify $ Map.insert x t
Localparam t x _ -> modify $ Map.insert x t
return origDecl
-- returns a "unique" name for the packer for a given struct type
packerFnName :: TypeFunc -> Identifier
......
......@@ -59,6 +59,9 @@ module Convert.Traverse
, traverseAsgnsM'
, traverseAsgns'
, collectAsgnsM'
, traverseStmtAsgnsM
, traverseStmtAsgns
, collectStmtAsgnsM
, traverseNestedModuleItemsM
, traverseNestedModuleItems
, collectNestedModuleItemsM
......@@ -824,13 +827,7 @@ traverseAsgnsM' strat mapper = moduleItemMapper
miMapperA other = return other
miMapperB = traverseStmtsM' strat stmtMapper
stmtMapper (AsgnBlk op lhs expr) = do
(lhs', expr') <- mapper (lhs, expr)
return $ AsgnBlk op lhs' expr'
stmtMapper (Asgn mt lhs expr) = do
(lhs', expr') <- mapper (lhs, expr)
return $ Asgn mt lhs' expr'
stmtMapper other = return other
stmtMapper = traverseStmtAsgnsM mapper
traverseAsgns' :: TFStrategy -> Mapper (LHS, Expr) -> Mapper ModuleItem
traverseAsgns' strat = unmonad $ traverseAsgnsM' strat
......@@ -844,6 +841,22 @@ traverseAsgns = traverseAsgns' IncludeTFs
collectAsgnsM :: Monad m => CollectorM m (LHS, Expr) -> CollectorM m ModuleItem
collectAsgnsM = collectAsgnsM' IncludeTFs
traverseStmtAsgnsM :: Monad m => MapperM m (LHS, Expr) -> MapperM m Stmt
traverseStmtAsgnsM mapper = stmtMapper
where
stmtMapper (AsgnBlk op lhs expr) = do
(lhs', expr') <- mapper (lhs, expr)
return $ AsgnBlk op lhs' expr'
stmtMapper (Asgn mt lhs expr) = do
(lhs', expr') <- mapper (lhs, expr)
return $ Asgn mt lhs' expr'
stmtMapper other = return other
traverseStmtAsgns :: Mapper (LHS, Expr) -> Mapper Stmt
traverseStmtAsgns = unmonad traverseStmtAsgnsM
collectStmtAsgnsM :: Monad m => CollectorM m (LHS, Expr) -> CollectorM m Stmt
collectStmtAsgnsM = collectify traverseStmtAsgnsM
traverseNestedModuleItemsM :: Monad m => MapperM m ModuleItem -> MapperM m ModuleItem
traverseNestedModuleItemsM mapper item = do
converted <-
......@@ -888,14 +901,15 @@ traverseScopesM declMapper moduleItemMapper stmtMapper =
fullModuleItemMapper
where
fullStmtMapper stmt = stmtMapper stmt >>= traverseSinglyNestedStmtsM cs
cs (Block name decls stmts) = do
nestedStmtMapper stmt =
stmtMapper stmt >>= traverseSinglyNestedStmtsM fullStmtMapper
fullStmtMapper (Block name decls stmts) = do
prevState <- get
decls' <- mapM declMapper decls
block <- fullStmtMapper $ Block name decls' stmts
block <- nestedStmtMapper $ Block name decls' stmts
put prevState
return block
cs other = fullStmtMapper other
fullStmtMapper other = nestedStmtMapper other
redirectModuleItem (MIPackageItem (Function ml t x decls stmts)) = do
prevState <- get
......
typedef struct packed { logic w, x, y; } StructA;
typedef struct packed { logic w, y, x; } StructB;
typedef struct packed { logic x, w, y; } StructC;
typedef struct packed { logic y, w, x; } StructD;
typedef struct packed { logic x, y, w; } StructE;
typedef struct packed { logic y, x, w; } StructF;
module top;
integer i, j, k;
StructA a;
StructB b;
StructC c;
StructD d;
StructE e;
StructF f;
initial begin
for (i = 0; i < 2; i++) begin
for (j = 0; j < 2; j++) begin
for (k = 0; k < 2; k++) begin
a = '{ w:i, x:j, y:k };
b = '{ w:i, x:j, y:k };
c = '{ w:i, x:j, y:k };
d = '{ w:i, x:j, y:k };
e = '{ w:i, x:j, y:k };
f = '{ w:i, x:j, y:k };
$display("A: %1d%1d%1d -> ", i,j,k, a,b,c,d,e,f);
end
end
end
end
initial begin
integer i, j, k;
StructB a;
StructC b;
StructD c;
StructE d;
StructF e;
StructA f;
for (i = 0; i < 2; i++) begin
for (j = 0; j < 2; j++) begin
for (k = 0; k < 2; k++) begin
a = '{ w:i, x:j, y:k };
b = '{ w:i, x:j, y:k };
c = '{ w:i, x:j, y:k };
d = '{ w:i, x:j, y:k };
e = '{ w:i, x:j, y:k };
f = '{ w:i, x:j, y:k };
$display("B: %1d%1d%1d -> ", i,j,k, a,b,c,d,e,f);
end
end
end
begin
integer i, j, k;
StructC a;
StructD b;
StructE c;
StructF d;
StructA e;
StructB f;
for (i = 0; i < 2; i++) begin
for (j = 0; j < 2; j++) begin
for (k = 0; k < 2; k++) begin
a = '{ w:i, x:j, y:k };
b = '{ w:i, x:j, y:k };
c = '{ w:i, x:j, y:k };
d = '{ w:i, x:j, y:k };
e = '{ w:i, x:j, y:k };
f = '{ w:i, x:j, y:k };
$display("C: %1d%1d%1d -> ", i,j,k, a,b,c,d,e,f);
end
end
end
end
end
task foo;
integer i, j, k;
StructD a;
StructE b;
StructF c;
StructA d;
StructB e;
StructC f;
for (i = 0; i < 2; i++) begin
for (j = 0; j < 2; j++) begin
for (k = 0; k < 2; k++) begin
a = '{ w:i, x:j, y:k };
b = '{ w:i, x:j, y:k };
c = '{ w:i, x:j, y:k };
d = '{ w:i, x:j, y:k };
e = '{ w:i, x:j, y:k };
f = '{ w:i, x:j, y:k };
$display("D: %1d%1d%1d -> ", i,j,k, a,b,c,d,e,f);
end
end
end
endtask
initial foo();
endmodule
// While this might look silly, you'll notice that the sections are actually
// different. We are ensuring that the correct struct definitions are being used
// in each scope.
module top;
reg [2:0] a = 3'b111;
reg [2:0] b = 3'b111;
reg [2:0] c = 3'b111;
reg [2:0] d = 3'b111;
reg [2:0] e = 3'b111;
reg [2:0] f = 3'b111;
integer i = 2;
integer j = 2;
integer k = 2;
initial begin
$display("A: 000 -> 000000");
$display("A: 001 -> 121424");
$display("A: 010 -> 214142");
$display("A: 011 -> 335566");
$display("A: 100 -> 442211");
$display("A: 101 -> 563635");
$display("A: 110 -> 656353");
$display("A: 111 -> 777777");
$display("B: 000 -> 000000");
$display("B: 001 -> 214241");
$display("B: 010 -> 141422");
$display("B: 011 -> 355663");
$display("B: 100 -> 422114");
$display("B: 101 -> 636355");
$display("B: 110 -> 563536");
$display("B: 111 -> 777777");
$display("C: 000 -> 000000");
$display("C: 001 -> 142412");
$display("C: 010 -> 414221");
$display("C: 011 -> 556633");
$display("C: 100 -> 221144");
$display("C: 101 -> 363556");
$display("C: 110 -> 635365");
$display("C: 111 -> 777777");
$display("D: 000 -> 000000");
$display("D: 001 -> 424121");
$display("D: 010 -> 142214");
$display("D: 011 -> 566335");
$display("D: 100 -> 211442");
$display("D: 101 -> 635563");
$display("D: 110 -> 353656");
$display("D: 111 -> 777777");
end
endmodule
// intentionally empty
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