From 843ad9331b6eaefc772d59b52ac0a3e2c04930d7 Mon Sep 17 00:00:00 2001 From: Charlotte Date: Wed, 28 Jun 2023 11:51:30 +1000 Subject: [PATCH] cxxrtl: WIP: adjust comb display cells to only fire on change Naming and use of statics to be possibly revised. --- backends/cxxrtl/cxxrtl.h | 2 +- backends/cxxrtl/cxxrtl_backend.cc | 33 ++++++++++++++++++++++++++++++- docs/source/CHAPTER_CellLib.rst | 4 ++-- tests/fmt/always_comb.v | 24 ++++++++++++++++++++++ tests/fmt/always_comb_tb.cc | 14 +++++++++++++ tests/fmt/always_comb_tb.v | 8 ++++++++ tests/fmt/always_full.v | 7 +------ tests/fmt/run-test.sh | 19 ++++++++++++------ 8 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 tests/fmt/always_comb.v create mode 100644 tests/fmt/always_comb_tb.cc create mode 100644 tests/fmt/always_comb_tb.v diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 45ec256af..8f5e4035a 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -850,7 +850,7 @@ std::ostream &operator<<(std::ostream &os, const value_formatted &vf) while (!val.is_zero()) { value quotient; val.divideWithRemainder(value{10u}, quotient); - buf += '0' + val.template slice<3, 0>().val().template get(); + buf += '0' + val.template trunc<(Bits > 4 ? 4 : Bits)>().val().template get(); val = quotient; } if (negative || vf.plus) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 8f06dda66..82babe72b 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -1217,8 +1217,18 @@ struct CxxrtlWorker { // $print cell } else if (cell->type == ID($print)) { log_assert(!for_debug); + + auto trg_enable = cell->getParam(ID::TRG_ENABLE).as_bool(); + static int cell_counter = 0; + if (!trg_enable) { + ++cell_counter; + f << indent << "static bool last_print_" << cell_counter << "_known = false;\n"; + f << indent << "static value<1> last_print_" << cell_counter << "_en;\n"; + f << indent << "static value<" << cell->getPort(ID::ARGS).size() << "> last_print_" << cell_counter << "_args;\n"; + } + f << indent << "if ("; - if (cell->getParam(ID::TRG_ENABLE).as_bool()) { + if (trg_enable) { f << '('; for (size_t i = 0; i < (size_t)cell->getParam(ID::TRG_WIDTH).as_int(); i++) { RTLIL::SigBit trg_bit = cell->getPort(ID::TRG)[i]; @@ -1235,6 +1245,17 @@ struct CxxrtlWorker { f << mangle(trg_bit); } f << ") && "; + } else { + f << '('; + f << "!last_print_" << cell_counter << "_known || "; + f << '('; + f << "last_print_" << cell_counter << "_en != "; + dump_sigspec_rhs(cell->getPort(ID::EN)); + + f << " || last_print_" << cell_counter << "_args != "; + dump_sigspec_rhs(cell->getPort(ID::ARGS)); + f << ')'; + f << ") && "; } dump_sigspec_rhs(cell->getPort(ID::EN)); f << " == value<1>{1u}) {\n"; @@ -1242,6 +1263,16 @@ struct CxxrtlWorker { dump_print(cell); dec_indent(); f << indent << "}\n"; + + if (!trg_enable) { + f << indent << "last_print_" << cell_counter << "_known = true;\n"; + f << indent << "last_print_" << cell_counter << "_en = "; + dump_sigspec_rhs(cell->getPort(ID::EN)); + f << ";\n"; + f << indent << "last_print_" << cell_counter << "_args = "; + dump_sigspec_rhs(cell->getPort(ID::ARGS)); + f << ";\n"; + } // Flip-flops } else if (is_ff_cell(cell->type)) { log_assert(!for_debug); diff --git a/docs/source/CHAPTER_CellLib.rst b/docs/source/CHAPTER_CellLib.rst index dc2ad3e57..4bbbe0ea8 100644 --- a/docs/source/CHAPTER_CellLib.rst +++ b/docs/source/CHAPTER_CellLib.rst @@ -641,8 +641,8 @@ has the following parameters: The width (in bits) of the signal on the ``\ARGS`` port. ``\TRG_ENABLE`` - True if only triggered on specific signals defined in ``\TRG``; false if - executed on every step. + True if triggered on specific signals defined in ``\TRG``; false if + triggered whenever ``\ARGS`` or ``\EN`` change and ``\EN`` is 1. If ``\TRG_ENABLE`` is true, the following parameters are also set: diff --git a/tests/fmt/always_comb.v b/tests/fmt/always_comb.v new file mode 100644 index 000000000..7147786be --- /dev/null +++ b/tests/fmt/always_comb.v @@ -0,0 +1,24 @@ +module top(input clk); + reg a = 0; + reg b = 0; + wire y; + + sub s (.a(a), .b(b), .y(y)); + + always @(posedge clk) begin + a <= (!a && !b) || (a && !b); + b <= (a && !b) || (a && b); + end +endmodule + +module sub(input a, input b, output wire y); + assign y = a & b; + + // Not fit for our purposes: always @* if (a) $display(a, b, y); + // + // We compare output against iverilog, but async iverilog $display fires + // even before values have propagated -- i.e. combinations of a/b/y will be + // shown where a & b are both 1, but y has not yet taken the value 1. We + // don't, so we specify it in the conditional. + always @* if (y & (y == (a & b))) $display(a, b, y); +endmodule diff --git a/tests/fmt/always_comb_tb.cc b/tests/fmt/always_comb_tb.cc new file mode 100644 index 000000000..c949af4e3 --- /dev/null +++ b/tests/fmt/always_comb_tb.cc @@ -0,0 +1,14 @@ +#include +#include "yosys-always_comb.cc" + +int main() +{ + cxxrtl_design::p_top uut; + + for (int i = 0; i < 20; ++i) { + uut.p_clk.set(!uut.p_clk); + uut.step(); + } + + return 0; +} diff --git a/tests/fmt/always_comb_tb.v b/tests/fmt/always_comb_tb.v new file mode 100644 index 000000000..447897433 --- /dev/null +++ b/tests/fmt/always_comb_tb.v @@ -0,0 +1,8 @@ +module tb; + reg clk = 0; + + top uut (.clk(clk)); + + always #1 clk <= ~clk; + initial #20 $finish; +endmodule diff --git a/tests/fmt/always_full.v b/tests/fmt/always_full.v index 372781354..d573bed31 100644 --- a/tests/fmt/always_full.v +++ b/tests/fmt/always_full.v @@ -8,8 +8,6 @@ module always_full(input clk, output reg fin); if (counter == 0) fin <= 0; - if (counter == 1) $display("<<>>"); - if (counter == 2) $display("==> small unsigned %%d"); if (counter == 3) $display(":%d:", 16'haa); if (counter == 4) $display(":%-d:", 16'haa); @@ -239,10 +237,7 @@ module always_full(input clk, output reg fin); if (counter == 207) $display("==> write/format"); if (counter == 208) $display("%d", 1, "%d", 1); - if (counter == 209) begin - $display("<<>>"); - fin <= 1; - end + if (counter == 209) fin <= 1; end diff --git a/tests/fmt/run-test.sh b/tests/fmt/run-test.sh index d793c37dd..44759dbc1 100644 --- a/tests/fmt/run-test.sh +++ b/tests/fmt/run-test.sh @@ -47,12 +47,19 @@ test_roundtrip oct_signed -DBASE_HEX -DSIGN="signed" test_roundtrip bin_unsigned -DBASE_HEX -DSIGN="" test_roundtrip bin_signed -DBASE_HEX -DSIGN="signed" -../../yosys -p "read_verilog always_full.v; write_cxxrtl -print-output std::cerr yosys-always_full.cc" -${CC:-gcc} -std=c++11 -o yosys-always_full -I../.. always_full_tb.cc -lstdc++ -./yosys-always_full 2>yosys-always_full.log -iverilog -o iverilog-always_full always_full.v always_full_tb.v -./iverilog-always_full | awk '/<<>>/,/<<>>/ {print $0}' >iverilog-always_full.log -diff iverilog-always_full.log yosys-always_full.log +test_cxxrtl () { + local subtest=$1; shift + + ../../yosys -p "read_verilog ${subtest}.v; write_cxxrtl -print-output std::cerr yosys-${subtest}.cc" + ${CC:-gcc} -std=c++11 -o yosys-${subtest} -I../.. ${subtest}_tb.cc -lstdc++ + ./yosys-${subtest} 2>yosys-${subtest}.log + iverilog -o iverilog-${subtest} ${subtest}.v ${subtest}_tb.v + ./iverilog-${subtest} |grep -v '\$finish called' >iverilog-${subtest}.log + diff iverilog-${subtest}.log yosys-${subtest}.log +} + +test_cxxrtl always_full +test_cxxrtl always_comb ../../yosys -p "read_verilog display_lm.v" >yosys-display_lm.log ../../yosys -p "read_verilog display_lm.v; write_cxxrtl yosys-display_lm.cc"