mirror of https://github.com/zachjs/sv2v.git
struct conversion supports complex shadowing
This commit is contained in:
parent
05b7bdb99c
commit
a8f2cbbe29
|
|
@ -1,7 +1,7 @@
|
|||
{- 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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// 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
|
||||
|
|
@ -0,0 +1 @@
|
|||
// intentionally empty
|
||||
Loading…
Reference in New Issue