From ea3884fa1eb39f6b6258101a2f8ba44da0a29c6c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 12 Dec 2021 11:40:05 +0100 Subject: [PATCH 1/2] Support continue/break in constant functions Add support for `continue` and `break` in constant functions. This is done in a similar way to how `disable` is implemented for constant functions. Two new global flags are introduced `loop_break` and `loop_continue` that get set when evaluating the corresponding statement. If either of these flags are set all other statements are ignored until the end of a loop is reached. At the end of the loop both `loop_break` and `loop_continue` get cleared. If `loop_break` was set before clearing it the loop is exited. Signed-off-by: Lars-Peter Clausen --- net_func_eval.cc | 63 +++++++++++++++++++++++++++++++++++++++++++++++- netlist.h | 4 +++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/net_func_eval.cc b/net_func_eval.cc index c7924273a..efbba9ccf 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -32,6 +32,8 @@ using namespace std; * to the target block. */ static const NetScope*disable = 0; +static bool loop_break; +static bool loop_continue; static NetExpr* fix_assign_value(const NetNet*lhs, NetExpr*rhs) { @@ -534,7 +536,7 @@ bool NetBlock::evaluate_function(const LineInfo&loc, bool cur_flag = cur->evaluate_function(loc, use_context_map); flag = flag && cur_flag; - } while (cur != last_ && !disable); + } while (cur != last_ && !disable && !loop_break && !loop_continue); if (debug_eval_tree) { cerr << get_fileline() << ": NetBlock::evaluate_function: " @@ -710,6 +712,30 @@ bool NetDisable::evaluate_function(const LineInfo&, return true; } +bool NetBreak::evaluate_function(const LineInfo&, + map&) const +{ + loop_break = true; + + if (debug_eval_tree) { + cerr << get_fileline() << ": NetBreak::evaluate_function" << endl; + } + + return true; +} + +bool NetContinue::evaluate_function(const LineInfo&, + map&) const +{ + loop_continue = true; + + if (debug_eval_tree) { + cerr << get_fileline() << ": NetContinue::evaluate_function" << endl; + } + + return true; +} + bool NetDoWhile::evaluate_function(const LineInfo&loc, map&context_map) const { @@ -726,6 +752,13 @@ bool NetDoWhile::evaluate_function(const LineInfo&loc, if (! flag) break; + if (loop_break) { + loop_break = false; + break; + } + + loop_continue = false; + // Evaluate the condition expression to try and get the // condition for the loop. NetExpr*cond = cond_->evaluate_function(loc, context_map); @@ -765,6 +798,13 @@ bool NetForever::evaluate_function(const LineInfo&loc, while (flag && !disable) { flag = flag && statement_->evaluate_function(loc, context_map); + + if (loop_break) { + loop_break = false; + break; + } + + loop_continue = false; } if (debug_eval_tree) { @@ -818,6 +858,13 @@ bool NetForLoop::evaluate_function(const LineInfo&loc, if (disable) break; + if (loop_break) { + loop_break = false; + break; + } + + loop_continue = false; + tmp_flag = step_statement_->evaluate_function(loc, context_map); flag &= tmp_flag; } @@ -854,6 +901,13 @@ bool NetRepeat::evaluate_function(const LineInfo&loc, while ((count > 0) && flag && !disable) { flag = flag && statement_->evaluate_function(loc, context_map); count -= 1; + + if (loop_break) { + loop_break = false; + break; + } + + loop_continue = false; } if (debug_eval_tree) { @@ -905,6 +959,13 @@ bool NetWhile::evaluate_function(const LineInfo&loc, bool tmp_flag = proc_->evaluate_function(loc, context_map); if (! tmp_flag) flag = false; + + if (loop_break) { + loop_break = false; + break; + } + + loop_continue = false; } if (debug_eval_tree) { diff --git a/netlist.h b/netlist.h index 811604355..c479bcbac 100644 --- a/netlist.h +++ b/netlist.h @@ -3068,6 +3068,8 @@ class NetBreak : public NetProc { public: virtual void dump(std::ostream&, unsigned ind) const; virtual bool emit_proc(struct target_t*) const; + bool evaluate_function(const LineInfo &loc, + std::map &ctx) const final; }; /* @@ -3222,6 +3224,8 @@ class NetContinue : public NetProc { public: virtual void dump(std::ostream&, unsigned ind) const; virtual bool emit_proc(struct target_t*) const; + bool evaluate_function(const LineInfo &loc, + std::map &ctx) const final; }; /* From 946ded13c7ca77ddbacee58227bb477ff7d4045d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Apr 2023 14:16:27 -0700 Subject: [PATCH 2/2] Add regression tests for continue/break in constant functions Check that continue and break are supported in constant functions. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/constfunc16.v | 39 ++++++++++++++++++++++++++++ ivtest/ivltests/constfunc17.v | 43 +++++++++++++++++++++++++++++++ ivtest/ivltests/constfunc18.v | 41 +++++++++++++++++++++++++++++ ivtest/ivltests/constfunc19.v | 43 +++++++++++++++++++++++++++++++ ivtest/ivltests/constfunc20.v | 32 +++++++++++++++++++++++ ivtest/regress-vvp.list | 5 ++++ ivtest/vvp_tests/constfunc16.json | 5 ++++ ivtest/vvp_tests/constfunc17.json | 5 ++++ ivtest/vvp_tests/constfunc18.json | 5 ++++ ivtest/vvp_tests/constfunc19.json | 5 ++++ ivtest/vvp_tests/constfunc20.json | 5 ++++ 11 files changed, 228 insertions(+) create mode 100644 ivtest/ivltests/constfunc16.v create mode 100644 ivtest/ivltests/constfunc17.v create mode 100644 ivtest/ivltests/constfunc18.v create mode 100644 ivtest/ivltests/constfunc19.v create mode 100644 ivtest/ivltests/constfunc20.v create mode 100644 ivtest/vvp_tests/constfunc16.json create mode 100644 ivtest/vvp_tests/constfunc17.json create mode 100644 ivtest/vvp_tests/constfunc18.json create mode 100644 ivtest/vvp_tests/constfunc19.json create mode 100644 ivtest/vvp_tests/constfunc20.json diff --git a/ivtest/ivltests/constfunc16.v b/ivtest/ivltests/constfunc16.v new file mode 100644 index 000000000..9341562ae --- /dev/null +++ b/ivtest/ivltests/constfunc16.v @@ -0,0 +1,39 @@ +// Check that break and continue are supported in constant functions in for +// loops + +module test; + + function automatic integer f1(integer x); + integer j = 0; + for (integer i = 0; i < 10; i++) begin + if (i >= x) begin + break; + end + j++; + end + return j; + endfunction + + function automatic integer f2(integer x); + integer j = 0; + for (integer i = 0; i < x; i++) begin + if (i % 2 == 0) begin + continue; + end + j++; + end + return j; + endfunction + + reg [f1(3):0] x; + reg [f2(6):0] y; + + initial begin + if ($bits(x) === 4 && $bits(y) === 4) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/constfunc17.v b/ivtest/ivltests/constfunc17.v new file mode 100644 index 000000000..9bb9cb771 --- /dev/null +++ b/ivtest/ivltests/constfunc17.v @@ -0,0 +1,43 @@ +// Check that break and continue are supported in constant functions in while +// loops + +module test; + + function automatic integer f1(integer x); + integer j = 0; + integer i = 0; + while (i < 10) begin + if (i >= x) begin + break; + end + j++; + i++; + end + return j; + endfunction + + function automatic integer f2(integer x); + integer j = 0; + integer i = 0; + while (i < x) begin + i++; + if (i % 2 == 0) begin + continue; + end + j++; + end + return j; + endfunction + + reg [f1(3):0] x; + reg [f2(6):0] y; + + initial begin + if ($bits(x) === 4 && $bits(y) === 4) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/constfunc18.v b/ivtest/ivltests/constfunc18.v new file mode 100644 index 000000000..77523a20d --- /dev/null +++ b/ivtest/ivltests/constfunc18.v @@ -0,0 +1,41 @@ +// Check that break and continue are supported in constant functions in repeat +// loops + +module test; + + function automatic integer f1(integer x); + integer j = 0; + repeat(10) begin + if (j >= x) begin + break; + end + j++; + end + return j; + endfunction + + function automatic integer f2(integer x); + integer j = 0; + integer i = 0; + repeat(x) begin + i++; + if (i % 2 == 0) begin + continue; + end + j++; + end + return j; + endfunction + + reg [f1(3):0] x; + reg [f2(6):0] y; + + initial begin + if ($bits(x) === 4 && $bits(y) === 4) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/constfunc19.v b/ivtest/ivltests/constfunc19.v new file mode 100644 index 000000000..53eca9ddc --- /dev/null +++ b/ivtest/ivltests/constfunc19.v @@ -0,0 +1,43 @@ +// Check that break and continue are supported in constant functions in do-while +// loops + +module test; + + function automatic integer f1(integer x); + integer j = 0; + integer i = 0; + do begin + if (i >= x) begin + break; + end + j++; + i++; + end while (i < 10); + return j; + endfunction + + function automatic integer f2(integer x); + integer j = 0; + integer i = 0; + do begin + i++; + if (i % 2 == 0) begin + continue; + end + j++; + end while (i < x); + return j; + endfunction + + reg [f1(3):0] x; + reg [f2(6):0] y; + + initial begin + if ($bits(x) === 4 && $bits(y) === 4) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/constfunc20.v b/ivtest/ivltests/constfunc20.v new file mode 100644 index 000000000..5728abbb2 --- /dev/null +++ b/ivtest/ivltests/constfunc20.v @@ -0,0 +1,32 @@ +// Check that break and continue are supported in constant functions in forever +// loops + +module test; + + function automatic integer f(integer x); + integer j = 0; + integer i = 0; + forever begin + i++; + if (i == x) begin + break; + end + if (i % 2 == 0) begin + continue; + end + j++; + end + return j; + endfunction + + reg [f(10):0] x; + + initial begin + if ($bits(x) === 6) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 681dd1a81..83de902bb 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -10,6 +10,11 @@ case2 vvp_tests/case2.json case2-S vvp_tests/case2-S.json case3 vvp_tests/case3.json casex_synth vvp_tests/casex_synth.json +constfunc16 vvp_tests/constfunc16.json +constfunc17 vvp_tests/constfunc17.json +constfunc18 vvp_tests/constfunc18.json +constfunc19 vvp_tests/constfunc19.json +constfunc20 vvp_tests/constfunc20.json dffsynth vvp_tests/dffsynth.json dffsynth-S vvp_tests/dffsynth-S.json dffsynth2 vvp_tests/dffsynth2.json diff --git a/ivtest/vvp_tests/constfunc16.json b/ivtest/vvp_tests/constfunc16.json new file mode 100644 index 000000000..d53a23cf8 --- /dev/null +++ b/ivtest/vvp_tests/constfunc16.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "constfunc16.v", + "iverilog-args" : [ "-g2009" ] +} diff --git a/ivtest/vvp_tests/constfunc17.json b/ivtest/vvp_tests/constfunc17.json new file mode 100644 index 000000000..9f2b60abf --- /dev/null +++ b/ivtest/vvp_tests/constfunc17.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "constfunc17.v", + "iverilog-args" : [ "-g2009" ] +} diff --git a/ivtest/vvp_tests/constfunc18.json b/ivtest/vvp_tests/constfunc18.json new file mode 100644 index 000000000..1c666c46d --- /dev/null +++ b/ivtest/vvp_tests/constfunc18.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "constfunc18.v", + "iverilog-args" : [ "-g2009" ] +} diff --git a/ivtest/vvp_tests/constfunc19.json b/ivtest/vvp_tests/constfunc19.json new file mode 100644 index 000000000..e6a023554 --- /dev/null +++ b/ivtest/vvp_tests/constfunc19.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "constfunc19.v", + "iverilog-args" : [ "-g2009" ] +} diff --git a/ivtest/vvp_tests/constfunc20.json b/ivtest/vvp_tests/constfunc20.json new file mode 100644 index 000000000..6c33a2b10 --- /dev/null +++ b/ivtest/vvp_tests/constfunc20.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "constfunc20.v", + "iverilog-args" : [ "-g2009" ] +}