From 03ae4c5c648ceea2ca696954474c33662ce36272 Mon Sep 17 00:00:00 2001 From: Roland Coeurjoly Date: Mon, 27 May 2024 22:15:00 +0200 Subject: [PATCH] Implement and test $mul. Use return, not exit in tests --- backends/functional/cxx.cc | 3 +- backends/functional/cxx_runtime/sim.h | 14 ++ backends/functional/smtlib.cc | 3 +- kernel/graphtools.h | 6 + tests/functional/{ => multi_bit}/run-test.sh | 7 +- tests/functional/multi_bit/vcd_harness.cpp | 133 ++++++++++++++++++ tests/functional/multi_bit/verilog/and.v | 9 ++ tests/functional/single_bit/run-test.sh | 69 +++++++++ .../{ => single_bit}/vcd_harness.cpp | 0 .../functional/{ => single_bit}/verilog/add.v | 0 .../functional/{ => single_bit}/verilog/and.v | 0 .../{ => single_bit}/verilog/my_module_div.v | 0 .../{ => single_bit}/verilog/my_module_eqx.v | 0 .../{ => single_bit}/verilog/my_module_ge.v | 0 .../{ => single_bit}/verilog/my_module_gt.v | 0 .../{ => single_bit}/verilog/my_module_le.v | 0 .../verilog/my_module_logic_and.v | 0 .../verilog/my_module_logic_or.v | 0 .../{ => single_bit}/verilog/my_module_lt.v | 0 .../{ => single_bit}/verilog/my_module_mod.v | 0 .../{ => single_bit}/verilog/my_module_mul.v | 0 .../{ => single_bit}/verilog/my_module_ne.v | 0 .../{ => single_bit}/verilog/my_module_nex.v | 0 .../{ => single_bit}/verilog/my_module_or.v | 0 .../{ => single_bit}/verilog/my_module_pow.v | 0 .../{ => single_bit}/verilog/my_module_shl.v | 0 .../{ => single_bit}/verilog/my_module_shr.v | 0 .../{ => single_bit}/verilog/my_module_sshl.v | 0 .../{ => single_bit}/verilog/my_module_sshr.v | 0 .../{ => single_bit}/verilog/my_module_sub.v | 0 .../{ => single_bit}/verilog/my_module_xnor.v | 0 .../{ => single_bit}/verilog/my_module_xor.v | 0 tests/verismith/yosys_all.toml | 33 +++++ 33 files changed, 273 insertions(+), 4 deletions(-) rename tests/functional/{ => multi_bit}/run-test.sh (84%) create mode 100644 tests/functional/multi_bit/vcd_harness.cpp create mode 100644 tests/functional/multi_bit/verilog/and.v create mode 100755 tests/functional/single_bit/run-test.sh rename tests/functional/{ => single_bit}/vcd_harness.cpp (100%) rename tests/functional/{ => single_bit}/verilog/add.v (100%) rename tests/functional/{ => single_bit}/verilog/and.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_div.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_eqx.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_ge.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_gt.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_le.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_logic_and.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_logic_or.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_lt.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_mod.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_mul.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_ne.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_nex.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_or.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_pow.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_shl.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_shr.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_sshl.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_sshr.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_sub.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_xnor.v (100%) rename tests/functional/{ => single_bit}/verilog/my_module_xor.v (100%) create mode 100644 tests/verismith/yosys_all.toml diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index a1060c58d79..5623e795bc1 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -189,7 +189,8 @@ class CxxComputeGraphFactory { T logical_shift_left(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shl), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } T logical_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($shr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } T arithmetic_shift_right(T a, T b, int y_width, int) { return graph.add(CxxFunction(ID($asr), y_width, {{ID(WIDTH), y_width}}), 0, std::array{a, b}); } - + T mul(T a, T b, int width) {return graph.add(CxxFunction(ID($mul), width), 0, std::array{a, b}); } + T constant(RTLIL::Const value) { return graph.add(CxxFunction(ID($$const), value.size(), {{ID(value), value}}), 0); } diff --git a/backends/functional/cxx_runtime/sim.h b/backends/functional/cxx_runtime/sim.h index 829266da0e6..0cbbe9831a1 100644 --- a/backends/functional/cxx_runtime/sim.h +++ b/backends/functional/cxx_runtime/sim.h @@ -365,4 +365,18 @@ Signal $sign_extend(Signal const& a) return ret; } +template +Signal $mul(Signal const& a, Signal const& b) +{ + Signal ret = $const(0); + + for(size_t i = 0; i < n; i++) { + if(b[i]) { + Signal shifted_a = $shl($zero_extend(a), $const(i)); + ret = $add(ret, shifted_a); + } + } + return ret; +} + #endif diff --git a/backends/functional/smtlib.cc b/backends/functional/smtlib.cc index cd11111b9d8..2811d0bea7e 100644 --- a/backends/functional/smtlib.cc +++ b/backends/functional/smtlib.cc @@ -367,7 +367,8 @@ class SmtlibComputeGraphFactory { T logical_shift_left(T a, T b, int y_width, int b_width) { return shift("bvshl", a, b, y_width, b_width); } T logical_shift_right(T a, T b, int y_width, int b_width) { return shift("bvlshl", a, b, y_width, b_width); } T arithmetic_shift_right(T a, T b, int y_width, int b_width) { return shift("bvashr", a, b, y_width, b_width, true); } - + T mul(T a, T b, int width) { return node(SExpr {"bvmul", Arg(1), Arg(2)}, width, {a, b}); } + T constant(RTLIL::Const value) { return node(SExpr(value), value.size(), {}); } T input(IdString name, int width) { module.input_struct.insert(name, width); diff --git a/kernel/graphtools.h b/kernel/graphtools.h index adf4764c201..1c6b927739d 100644 --- a/kernel/graphtools.h +++ b/kernel/graphtools.h @@ -183,6 +183,12 @@ class CellSimplifier { int offset = parameters.at(ID(OFFSET)).as_int(); T a = inputs.at(ID(A)); return factory.slice(a, a_width, offset, y_width); + }else if(cellType == ID($mul)){ + bool is_signed = a_signed && b_signed; + int width = a_width + b_width; + T a = extend(inputs.at(ID(A)), a_width, width, is_signed); + T b = extend(inputs.at(ID(B)), b_width, width, is_signed); + return extend(factory.mul(a, b, width), width, y_width, is_signed); }else{ log_error("unhandled cell in CellSimplifier %s\n", cellType.c_str()); } diff --git a/tests/functional/run-test.sh b/tests/functional/multi_bit/run-test.sh similarity index 84% rename from tests/functional/run-test.sh rename to tests/functional/multi_bit/run-test.sh index 7dc842a797a..421630d5be5 100755 --- a/tests/functional/run-test.sh +++ b/tests/functional/multi_bit/run-test.sh @@ -2,6 +2,9 @@ set -ex +# Define the common variable for the relative path +BASE_PATH="../../../" + # Initialize an array to store the names of failing Verilog files and their failure types declare -A failing_files @@ -11,11 +14,11 @@ for verilog_file in verilog/*.v; do base_name=$(basename "$verilog_file" .v) # Run yosys to process each Verilog file - if ../../yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then echo "Yosys processed $verilog_file successfully." # Compile the generated C++ files with vcd_harness.cpp - ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ../../backends/functional/cxx_runtime/ -I ../../backends/cxxrtl/runtime/ -o vcd_harness + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ${BASE_PATH}backends/functional/cxx_runtime/ -I ${BASE_PATH}backends/cxxrtl/runtime/ -o vcd_harness # Generate VCD files with base_name if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd ; then diff --git a/tests/functional/multi_bit/vcd_harness.cpp b/tests/functional/multi_bit/vcd_harness.cpp new file mode 100644 index 00000000000..bb8cca6fc8d --- /dev/null +++ b/tests/functional/multi_bit/vcd_harness.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include + +#include + +#include "my_module_cxxrtl.cc" +#include "my_module_functional_cxx.cc" + +struct DumpHeader { + std::ofstream &ofs; + DumpHeader(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + ofs << "$var wire " << n << " " << name[0] << " " << name << " $end\n"; + } +}; + +struct Dump { + std::ofstream &ofs; + Dump(std::ofstream &ofs) : ofs(ofs) {} + template + void operator()(const char *name, Signal value) { + // Bit + if (n == 1) { + ofs << (value[0] ? '1' : '0'); + ofs << name[0] << "\n"; + return; + } + // vector (multi-bit) signals + ofs << "b"; + for (size_t i = n; i-- > 0;) + ofs << (value[i] ? '1' : '0'); + ofs << " " << name[0] << "\n"; + } +}; + +int main(int argc, char **argv) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + const std::string functional_vcd_filename = argv[1]; + const std::string cxxrtl_vcd_filename = argv[2]; + + constexpr int steps = 10; + constexpr int number_timescale = 1; + const std::string units_timescale = "us"; + my_module_Inputs inputs; + my_module_Outputs outputs; + my_module_State state; + my_module_State next_state; + + std::ofstream vcd_file(functional_vcd_filename); + + vcd_file << "$timescale " << number_timescale << " " << units_timescale << " $end\n"; + { + DumpHeader d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + vcd_file << "$enddefinitions $end\n$dumpvars\n"; + + cxxrtl_design::p_my__module top; + + cxxrtl::debug_items all_debug_items; + cxxrtl::debug_scope debug_scope; + top.debug_info(&all_debug_items, nullptr, ""); + + cxxrtl::vcd_writer vcd; + vcd.timescale(number_timescale, units_timescale); + vcd.add_without_memories(all_debug_items); + + std::ofstream waves(cxxrtl_vcd_filename); + + top.p_a.set<8>(false); + top.p_b.set<8>(false); + top.step(); + + vcd.sample(0); + vcd_file << "#0\n"; + inputs.a = $const<8>(false); + inputs.b = $const<8>(false); + my_module(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + std::random_device rd; + std::mt19937 gen(rd()); + std::bernoulli_distribution dist(0.5); + + for (int step = 0; step < steps; ++step) { + const bool a_value = dist(gen); + const bool b_value = dist(gen); + + // cxxrtl + top.p_a.set(a_value); + top.p_b.set(b_value); + top.step(); + vcd.sample(step + 1); + + waves << vcd.buffer; + vcd.buffer.clear(); + + // Functional backend cxx + vcd_file << "#" << (step + 1) << "\n"; + inputs.a = $const<8>(a_value); + inputs.b = $const<8>(b_value); + + my_module(inputs, outputs, state, next_state); + { + Dump d(vcd_file); + inputs.dump(d); + outputs.dump(d); + state.dump(d); + } + + state = next_state; + } + + vcd_file.close(); + waves.close(); + + return 0; +} diff --git a/tests/functional/multi_bit/verilog/and.v b/tests/functional/multi_bit/verilog/and.v new file mode 100644 index 00000000000..be20c778e65 --- /dev/null +++ b/tests/functional/multi_bit/verilog/and.v @@ -0,0 +1,9 @@ +module my_module( + input [7:0] a, + input [7:0] b, + output [7:0] y +); + // Perform bitwise AND + assign y = a & b; + +endmodule diff --git a/tests/functional/single_bit/run-test.sh b/tests/functional/single_bit/run-test.sh new file mode 100755 index 00000000000..ff5636f93f9 --- /dev/null +++ b/tests/functional/single_bit/run-test.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Initialize an array to store the names of failing Verilog files and their failure types +declare -A failing_files + +# Function to run the test on a given Verilog file +run_test() { + # Define the common variable for the relative path + BASE_PATH="../../../" + + local verilog_file=$1 + + # Extract the base name without extension + local base_name=$(basename "$verilog_file" .v) + + # Run yosys to process each Verilog file + if ${BASE_PATH}yosys -p "read_verilog $verilog_file; write_cxxrtl my_module_cxxrtl.cc; write_functional_cxx my_module_functional_cxx.cc"; then + echo "Yosys processed $verilog_file successfully." + + # Compile the generated C++ files with vcd_harness.cpp + ${CXX:-g++} -g -fprofile-arcs -ftest-coverage vcd_harness.cpp -I ${BASE_PATH}backends/functional/cxx_runtime/ -I ${BASE_PATH}backends/cxxrtl/runtime/ -o vcd_harness + + # Generate VCD files with base_name + if ./vcd_harness ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd ; then + # Run vcdiff and capture the output + local output=$(vcdiff ${base_name}_functional_cxx.vcd ${base_name}_cxxrtl.vcd) + + # Check if there is any output + if [ -n "$output" ]; then + echo "Differences detected in $verilog_file:" + echo "$output" + failing_files["$verilog_file"]="Differences detected" + else + echo "No differences detected in $verilog_file." + fi + else + echo "Failed to generate VCD files for $verilog_file." + failing_files["$verilog_file"]="VCD generation failure" + fi + else + echo "Yosys failed to process $verilog_file." + failing_files["$verilog_file"]="Yosys failure" + fi +} + +# Main function to run all tests +run_all_tests() { + # Loop through all Verilog files in the verilog directory + for verilog_file in verilog/*.v; do + run_test "$verilog_file" + done + + # Check if the array of failing files is empty + if [ ${#failing_files[@]} -eq 0 ]; then + echo "All files passed." + return 0 + else + echo "The following files failed:" + for file in "${!failing_files[@]}"; do + echo "$file: ${failing_files[$file]}" + done + return 1 + fi +} + +# If the script is being sourced, do not execute the tests +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + run_all_tests +fi diff --git a/tests/functional/vcd_harness.cpp b/tests/functional/single_bit/vcd_harness.cpp similarity index 100% rename from tests/functional/vcd_harness.cpp rename to tests/functional/single_bit/vcd_harness.cpp diff --git a/tests/functional/verilog/add.v b/tests/functional/single_bit/verilog/add.v similarity index 100% rename from tests/functional/verilog/add.v rename to tests/functional/single_bit/verilog/add.v diff --git a/tests/functional/verilog/and.v b/tests/functional/single_bit/verilog/and.v similarity index 100% rename from tests/functional/verilog/and.v rename to tests/functional/single_bit/verilog/and.v diff --git a/tests/functional/verilog/my_module_div.v b/tests/functional/single_bit/verilog/my_module_div.v similarity index 100% rename from tests/functional/verilog/my_module_div.v rename to tests/functional/single_bit/verilog/my_module_div.v diff --git a/tests/functional/verilog/my_module_eqx.v b/tests/functional/single_bit/verilog/my_module_eqx.v similarity index 100% rename from tests/functional/verilog/my_module_eqx.v rename to tests/functional/single_bit/verilog/my_module_eqx.v diff --git a/tests/functional/verilog/my_module_ge.v b/tests/functional/single_bit/verilog/my_module_ge.v similarity index 100% rename from tests/functional/verilog/my_module_ge.v rename to tests/functional/single_bit/verilog/my_module_ge.v diff --git a/tests/functional/verilog/my_module_gt.v b/tests/functional/single_bit/verilog/my_module_gt.v similarity index 100% rename from tests/functional/verilog/my_module_gt.v rename to tests/functional/single_bit/verilog/my_module_gt.v diff --git a/tests/functional/verilog/my_module_le.v b/tests/functional/single_bit/verilog/my_module_le.v similarity index 100% rename from tests/functional/verilog/my_module_le.v rename to tests/functional/single_bit/verilog/my_module_le.v diff --git a/tests/functional/verilog/my_module_logic_and.v b/tests/functional/single_bit/verilog/my_module_logic_and.v similarity index 100% rename from tests/functional/verilog/my_module_logic_and.v rename to tests/functional/single_bit/verilog/my_module_logic_and.v diff --git a/tests/functional/verilog/my_module_logic_or.v b/tests/functional/single_bit/verilog/my_module_logic_or.v similarity index 100% rename from tests/functional/verilog/my_module_logic_or.v rename to tests/functional/single_bit/verilog/my_module_logic_or.v diff --git a/tests/functional/verilog/my_module_lt.v b/tests/functional/single_bit/verilog/my_module_lt.v similarity index 100% rename from tests/functional/verilog/my_module_lt.v rename to tests/functional/single_bit/verilog/my_module_lt.v diff --git a/tests/functional/verilog/my_module_mod.v b/tests/functional/single_bit/verilog/my_module_mod.v similarity index 100% rename from tests/functional/verilog/my_module_mod.v rename to tests/functional/single_bit/verilog/my_module_mod.v diff --git a/tests/functional/verilog/my_module_mul.v b/tests/functional/single_bit/verilog/my_module_mul.v similarity index 100% rename from tests/functional/verilog/my_module_mul.v rename to tests/functional/single_bit/verilog/my_module_mul.v diff --git a/tests/functional/verilog/my_module_ne.v b/tests/functional/single_bit/verilog/my_module_ne.v similarity index 100% rename from tests/functional/verilog/my_module_ne.v rename to tests/functional/single_bit/verilog/my_module_ne.v diff --git a/tests/functional/verilog/my_module_nex.v b/tests/functional/single_bit/verilog/my_module_nex.v similarity index 100% rename from tests/functional/verilog/my_module_nex.v rename to tests/functional/single_bit/verilog/my_module_nex.v diff --git a/tests/functional/verilog/my_module_or.v b/tests/functional/single_bit/verilog/my_module_or.v similarity index 100% rename from tests/functional/verilog/my_module_or.v rename to tests/functional/single_bit/verilog/my_module_or.v diff --git a/tests/functional/verilog/my_module_pow.v b/tests/functional/single_bit/verilog/my_module_pow.v similarity index 100% rename from tests/functional/verilog/my_module_pow.v rename to tests/functional/single_bit/verilog/my_module_pow.v diff --git a/tests/functional/verilog/my_module_shl.v b/tests/functional/single_bit/verilog/my_module_shl.v similarity index 100% rename from tests/functional/verilog/my_module_shl.v rename to tests/functional/single_bit/verilog/my_module_shl.v diff --git a/tests/functional/verilog/my_module_shr.v b/tests/functional/single_bit/verilog/my_module_shr.v similarity index 100% rename from tests/functional/verilog/my_module_shr.v rename to tests/functional/single_bit/verilog/my_module_shr.v diff --git a/tests/functional/verilog/my_module_sshl.v b/tests/functional/single_bit/verilog/my_module_sshl.v similarity index 100% rename from tests/functional/verilog/my_module_sshl.v rename to tests/functional/single_bit/verilog/my_module_sshl.v diff --git a/tests/functional/verilog/my_module_sshr.v b/tests/functional/single_bit/verilog/my_module_sshr.v similarity index 100% rename from tests/functional/verilog/my_module_sshr.v rename to tests/functional/single_bit/verilog/my_module_sshr.v diff --git a/tests/functional/verilog/my_module_sub.v b/tests/functional/single_bit/verilog/my_module_sub.v similarity index 100% rename from tests/functional/verilog/my_module_sub.v rename to tests/functional/single_bit/verilog/my_module_sub.v diff --git a/tests/functional/verilog/my_module_xnor.v b/tests/functional/single_bit/verilog/my_module_xnor.v similarity index 100% rename from tests/functional/verilog/my_module_xnor.v rename to tests/functional/single_bit/verilog/my_module_xnor.v diff --git a/tests/functional/verilog/my_module_xor.v b/tests/functional/single_bit/verilog/my_module_xor.v similarity index 100% rename from tests/functional/verilog/my_module_xor.v rename to tests/functional/single_bit/verilog/my_module_xor.v diff --git a/tests/verismith/yosys_all.toml b/tests/verismith/yosys_all.toml new file mode 100644 index 00000000000..a60a8371db5 --- /dev/null +++ b/tests/verismith/yosys_all.toml @@ -0,0 +1,33 @@ +[probability] + expr.binary = 5 + expr.concatenation = 5 + expr.number = 1 + expr.rangeselect = 5 + expr.signed = 5 + expr.string = 0 + expr.ternary = 5 + expr.unary = 5 + expr.unsigned = 5 + expr.variable = 5 + moditem.assign = 2 + moditem.combinational = 0 + moditem.instantiation = 0 + moditem.sequential = 3 + statement.blocking = 0 + statement.conditional = 1 + statement.forloop = 0 + statement.nonblocking = 2 + +[property] + module.depth = 2 + module.max = 5 + size = 20 + statement.depth = 7 + sample.method = "hat" + sample.size = 10 + +[[synthesiser]] + name = "yosys" + description = "yosys_nix" + output = "yosys_nix.v" + bin = "/nix/store/fzqckbn2ajj6illgrbcja6fj8qzrbacb-yosys/bin/" \ No newline at end of file