Commit f9917d94 by Zachary Snow

execute always_comb/latch at time zero

parent 756dbbb8
...@@ -31,6 +31,7 @@ ...@@ -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 @@ ...@@ -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] ...@@ -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 <>) ...@@ -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) ...@@ -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]
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
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
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
`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( ...@@ -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; ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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); ...@@ -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__": ...@@ -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() { ...@@ -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
......
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