mirror of https://github.com/zachjs/sv2v.git
execute always_comb/latch at time zero
This commit is contained in:
parent
756dbbb84f
commit
f9917d94da
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
### Other Enhancements
|
### Other Enhancements
|
||||||
|
|
||||||
|
* `always_comb` and `always_latch` now reliably execute at time zero
|
||||||
* Added error checking for unresolved typenames
|
* Added error checking for unresolved typenames
|
||||||
* Added constant folding for `||` and `&&`
|
* Added constant folding for `||` and `&&`
|
||||||
* `input reg` module ports are now converted to `input wire`
|
* `input reg` module ports are now converted to `input wire`
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
-
|
-
|
||||||
- `always_comb` and `always_latch` become `always @*`, or produce an explicit
|
- `always_comb` and `always_latch` become `always @*`, or produce an explicit
|
||||||
- sensitivity list if they need to pick up sensitivities from the functions
|
- sensitivity list if they need to pick up sensitivities from the functions
|
||||||
- they call. `always_ff` simply becomes `always`.
|
- they call. These blocks are triggered at time zero by adding a no-op
|
||||||
-
|
- statement reading from `_sv2v_0`, which is injected and updated in an
|
||||||
- TODO: `always_comb` blocks do not run at time zero
|
- `initial` block. `always_ff` simply becomes `always`.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
module Convert.AlwaysKW (convert) where
|
module Convert.AlwaysKW (convert) where
|
||||||
|
|
@ -24,9 +24,15 @@ convert :: [AST] -> [AST]
|
||||||
convert = map $ traverseDescriptions traverseDescription
|
convert = map $ traverseDescriptions traverseDescription
|
||||||
|
|
||||||
traverseDescription :: Description -> Description
|
traverseDescription :: Description -> Description
|
||||||
traverseDescription description@Part{} =
|
traverseDescription (Part att ext kw lif name pts items) =
|
||||||
evalState (evalScoperT $ scopePart op description) mempty
|
Part att ext kw lif name pts $
|
||||||
where op = traverseModuleItem >=> scoper
|
if getAny anys && not (elem triggerDecl items')
|
||||||
|
then triggerDecl : items' ++ [triggerFire]
|
||||||
|
else items'
|
||||||
|
where
|
||||||
|
op = traverseModuleItem >=> scoper
|
||||||
|
(items', (anys, _)) = flip runState mempty $ evalScoperT $
|
||||||
|
insertElem triggerIdent Var >> scopeModuleItems op name items
|
||||||
traverseDescription description = description
|
traverseDescription description = description
|
||||||
|
|
||||||
type SC = ScoperT Kind (State (Any, [Expr]))
|
type SC = ScoperT Kind (State (Any, [Expr]))
|
||||||
|
|
@ -182,12 +188,13 @@ push x = lift $ modify' (x <>)
|
||||||
-- custom traversal which converts SystemVerilog `always` keywords and tracks
|
-- custom traversal which converts SystemVerilog `always` keywords and tracks
|
||||||
-- information about task and functions
|
-- information about task and functions
|
||||||
traverseModuleItem :: ModuleItem -> SC ModuleItem
|
traverseModuleItem :: ModuleItem -> SC ModuleItem
|
||||||
traverseModuleItem (AlwaysC AlwaysLatch stmt) = do
|
traverseModuleItem (AlwaysC AlwaysLatch stmt) =
|
||||||
e <- fmap toEvent $ findNonLocals $ Initial stmt
|
traverseModuleItem $ AlwaysC AlwaysComb stmt
|
||||||
return $ AlwaysC Always $ Timing (Event e) stmt
|
|
||||||
traverseModuleItem (AlwaysC AlwaysComb stmt) = do
|
traverseModuleItem (AlwaysC AlwaysComb stmt) = do
|
||||||
e <- fmap toEvent $ findNonLocals $ Initial stmt
|
push (Any True, [])
|
||||||
return $ AlwaysC Always $ Timing (Event e) stmt
|
e <- fmap toEvent $ findNonLocals $ Initial stmt'
|
||||||
|
return $ AlwaysC Always $ Timing (Event e) stmt'
|
||||||
|
where stmt' = addTriggerStmt stmt
|
||||||
traverseModuleItem (AlwaysC AlwaysFF stmt) =
|
traverseModuleItem (AlwaysC AlwaysFF stmt) =
|
||||||
return $ AlwaysC Always stmt
|
return $ AlwaysC Always stmt
|
||||||
traverseModuleItem item@(MIPackageItem (Function _ _ x decls _)) = do
|
traverseModuleItem item@(MIPackageItem (Function _ _ x decls _)) = do
|
||||||
|
|
@ -220,8 +227,28 @@ port _ = ("", Local)
|
||||||
findNonLocals :: ModuleItem -> SC (Bool, [Expr])
|
findNonLocals :: ModuleItem -> SC (Bool, [Expr])
|
||||||
findNonLocals item = do
|
findNonLocals item = do
|
||||||
scopes <- get
|
scopes <- get
|
||||||
|
prev <- lift get
|
||||||
lift $ put mempty
|
lift $ put mempty
|
||||||
_ <- scoper item
|
_ <- scoper item
|
||||||
(anys, exprs) <- lift get
|
(anys, exprs) <- lift get
|
||||||
|
lift $ put prev
|
||||||
let nonLocals = mapMaybe (longestStaticPrefix scopes) exprs
|
let nonLocals = mapMaybe (longestStaticPrefix scopes) exprs
|
||||||
return (getAny anys, nonLocals)
|
return (getAny anys, nonLocals)
|
||||||
|
|
||||||
|
triggerIdent :: Identifier
|
||||||
|
triggerIdent = "_sv2v_0"
|
||||||
|
|
||||||
|
triggerDecl :: ModuleItem
|
||||||
|
triggerDecl = MIPackageItem $ Decl $ Variable Local t triggerIdent [] Nil
|
||||||
|
where t = IntegerVector TReg Unspecified []
|
||||||
|
|
||||||
|
triggerFire :: ModuleItem
|
||||||
|
triggerFire = Initial $ Asgn AsgnOpEq Nothing (LHSIdent triggerIdent) (RawNum 0)
|
||||||
|
|
||||||
|
triggerStmt :: Stmt
|
||||||
|
triggerStmt = If NoCheck (Ident triggerIdent) Null Null
|
||||||
|
|
||||||
|
addTriggerStmt :: Stmt -> Stmt
|
||||||
|
addTriggerStmt (Block Seq name decls stmts) =
|
||||||
|
Block Seq name decls $ triggerStmt : stmts
|
||||||
|
addTriggerStmt stmt = Block Seq "" [] [triggerStmt, stmt]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
module top;
|
||||||
|
logic x;
|
||||||
|
always_comb
|
||||||
|
x = 0;
|
||||||
|
|
||||||
|
`include "always_comb.vh"
|
||||||
|
`TEST(_comb, 1)
|
||||||
|
`TEST(_comb, 2)
|
||||||
|
`TEST(@*, 3)
|
||||||
|
`TEST(@*, 4)
|
||||||
|
|
||||||
|
initial x1 = 0;
|
||||||
|
initial x3 = 0;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
module top;
|
||||||
|
reg x;
|
||||||
|
initial
|
||||||
|
x = 0;
|
||||||
|
|
||||||
|
`include "always_comb.vh"
|
||||||
|
`TEST(@(x1), 1)
|
||||||
|
`TEST(@(x1), 2)
|
||||||
|
`TEST(@*, 3)
|
||||||
|
`TEST(@*, 4)
|
||||||
|
|
||||||
|
initial x1 = 0;
|
||||||
|
initial x3 = 0;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
reg never;
|
||||||
|
`define TEST(sense, num) \
|
||||||
|
reg x``num, y``num, z``num; \
|
||||||
|
function automatic t``num; \
|
||||||
|
input inp; \
|
||||||
|
t``num = x``num; \
|
||||||
|
endfunction \
|
||||||
|
always``sense begin \
|
||||||
|
y``num = 0; \
|
||||||
|
z``num = t``num(0); \
|
||||||
|
if (never) ; \
|
||||||
|
end
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
`define ALWAYS(trigger) always @(trigger)
|
`define ALWAYS(trigger) always @(trigger, start)
|
||||||
`include "always_prefix.vh"
|
`include "always_prefix.vh"
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ module mod(
|
||||||
);
|
);
|
||||||
localparam Y = 2;
|
localparam Y = 2;
|
||||||
localparam X = 10000;
|
localparam X = 10000;
|
||||||
|
reg start;
|
||||||
|
|
||||||
`define TEST(expr, trigger, extra) \
|
`define TEST(expr, trigger, extra) \
|
||||||
if (1) begin \
|
if (1) begin \
|
||||||
|
|
@ -40,4 +41,6 @@ parameter FOUR = 4;
|
||||||
`TEST(data[THREE], data[3], )
|
`TEST(data[THREE], data[3], )
|
||||||
`TEST(data[ignored], data, )
|
`TEST(data[ignored], data, )
|
||||||
`TEST(data[THREE], data[0] or data[3], & data[0])
|
`TEST(data[THREE], data[0] or data[3], & data[0])
|
||||||
|
|
||||||
|
initial start = 0;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ module mod(
|
||||||
o = i;
|
o = i;
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
|
logic start;
|
||||||
|
|
||||||
always_comb
|
always_comb
|
||||||
t(out1);
|
t(out1);
|
||||||
always_comb
|
always_comb
|
||||||
|
|
@ -82,4 +84,6 @@ module mod(
|
||||||
endfunction
|
endfunction
|
||||||
always_comb
|
always_comb
|
||||||
asgn(.i(i(ZERO)), .o(outC));
|
asgn(.i(i(ZERO)), .o(outC));
|
||||||
|
|
||||||
|
initial start = 0;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -39,17 +39,19 @@ module mod(
|
||||||
o = i;
|
o = i;
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
|
reg start;
|
||||||
|
|
||||||
always @*
|
always @*
|
||||||
t(out1);
|
t(out1);
|
||||||
always @(inp2)
|
always @(inp2)
|
||||||
out2 = f(ZERO);
|
out2 = f(ZERO);
|
||||||
always @(inp1, inp2)
|
always @(start, inp1, inp2)
|
||||||
out3 = f(ZERO) & inp1;
|
out3 = f(ZERO) & inp1;
|
||||||
always @(inp1, inp2)
|
always @(start, inp1, inp2)
|
||||||
out4 = g(ZERO);
|
out4 = g(ZERO);
|
||||||
always @*
|
always @*
|
||||||
out5 = flip(inp1);
|
out5 = flip(inp1);
|
||||||
always @(inp1, inp2) begin : blk
|
always @(start, inp1, inp2) begin : blk
|
||||||
reg x;
|
reg x;
|
||||||
x = g(ZERO);
|
x = g(ZERO);
|
||||||
out6 = x;
|
out6 = x;
|
||||||
|
|
@ -58,11 +60,11 @@ module mod(
|
||||||
u(out7);
|
u(out7);
|
||||||
parameter ONE = 1;
|
parameter ONE = 1;
|
||||||
if (ONE)
|
if (ONE)
|
||||||
always @(inp1, inp2) begin
|
always @(start, inp1, inp2) begin
|
||||||
asgn(out8, flip(inp1));
|
asgn(out8, flip(inp1));
|
||||||
out9 = f(ZERO);
|
out9 = f(ZERO);
|
||||||
end
|
end
|
||||||
always @(inp1, inp2)
|
always @(start, inp1, inp2)
|
||||||
if (inp1)
|
if (inp1)
|
||||||
outA = f(ZERO);
|
outA = f(ZERO);
|
||||||
|
|
||||||
|
|
@ -80,4 +82,6 @@ module mod(
|
||||||
endfunction
|
endfunction
|
||||||
always @(s[1])
|
always @(s[1])
|
||||||
asgn(outC, i(ZERO));
|
asgn(outC, i(ZERO));
|
||||||
|
|
||||||
|
initial start = 0;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,11 @@ module Example(inp, out);
|
||||||
input wire inp;
|
input wire inp;
|
||||||
output reg out;
|
output reg out;
|
||||||
generate
|
generate
|
||||||
if (ENABLED)
|
if (ENABLED) begin
|
||||||
always @* out = inp;
|
reg start;
|
||||||
|
always @(inp, start) out = inp;
|
||||||
|
initial start = 0;
|
||||||
|
end
|
||||||
else
|
else
|
||||||
initial out = DEFAULT;
|
initial out = DEFAULT;
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ if __name__ == "__main__":
|
||||||
# Find and drop dumped parameters.
|
# Find and drop dumped parameters.
|
||||||
if line.startswith("$var "):
|
if line.startswith("$var "):
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
should_drop = parts[1] == "parameter"
|
should_drop = parts[1] == "parameter" or parts[4] == "_sv2v_0"
|
||||||
if not should_drop and not pending:
|
if not should_drop and not pending:
|
||||||
print(line, end="")
|
print(line, end="")
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ simulate() {
|
||||||
$sim_prog -no-date > $sim_log
|
$sim_prog -no-date > $sim_log
|
||||||
assertTrue "simulating $1 failed" $?
|
assertTrue "simulating $1 failed" $?
|
||||||
# remove parameters from the VCD if present
|
# remove parameters from the VCD if present
|
||||||
if grep "var parameter" $sim_vcd_tmp > /dev/null; then
|
if grep -E "var parameter| _sv2v_0 " $sim_vcd_tmp > /dev/null; then
|
||||||
$SCRIPT_DIR/clean_vcd.py < $sim_vcd_tmp > $sim_vcd
|
$SCRIPT_DIR/clean_vcd.py < $sim_vcd_tmp > $sim_vcd
|
||||||
elif [ $sim_vcd != "/dev/null" ]; then
|
elif [ $sim_vcd != "/dev/null" ]; then
|
||||||
mv -f $sim_vcd_tmp $sim_vcd
|
mv -f $sim_vcd_tmp $sim_vcd
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue