From cdc728b6f009ba9faa9829e26332f428896a0b77 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Fri, 20 Feb 2026 09:33:51 -0800 Subject: [PATCH 001/262] Suggest use of YW when possible --- passes/sat/sim.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 27d6d12c1..5392cd9e5 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -2624,6 +2624,7 @@ struct SimPass : public Pass { log(" -r \n"); log(" read simulation or formal results file\n"); log(" File formats supported: FST, VCD, AIW, WIT and .yw\n"); + log(" Yosys witness (.yw) replay is preferred when possible.\n"); log(" VCD support requires vcd2fst external tool to be present\n"); log("\n"); log(" -width \n"); From b454582f540753343524d33e7d2e3ad8ca95972b Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Fri, 20 Feb 2026 11:00:59 -0800 Subject: [PATCH 002/262] Detect undriven and error/warn --- passes/sat/sim.cc | 81 ++++++++++++++++++++++++++++++++--- tests/sim/undriven_replay.v | 7 +++ tests/sim/undriven_replay.vcd | 15 +++++++ tests/sim/undriven_replay.ys | 10 +++++ 4 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 tests/sim/undriven_replay.v create mode 100644 tests/sim/undriven_replay.vcd create mode 100644 tests/sim/undriven_replay.ys diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 5392cd9e5..bd723f5f1 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -26,6 +26,7 @@ #include "kernel/yw.h" #include "kernel/json.h" #include "kernel/fmt.h" +#include "kernel/drivertools.h" #include @@ -125,6 +126,8 @@ struct SimShared bool serious_asserts = false; bool fst_noinit = false; bool initstate = true; + bool undriven_check = true; + bool undriven_warning = false; }; void zinit(Const &v) @@ -426,7 +429,7 @@ struct SimInstance Const value = builder.build(); if (shared->debug) - log("[%s] get %s: %s\n", hiername(), log_signal(sig), log_signal(value)); + log("[%s] get %s: %s\n", hiername(), log_signal(sig, true), log_signal(value, true)); return value; } @@ -445,7 +448,7 @@ struct SimInstance } if (shared->debug) - log("[%s] set %s: %s\n", hiername(), log_signal(sig), log_signal(value)); + log("[%s] set %s: %s\n", hiername(), log_signal(sig, true), log_signal(value, true)); return did_something; } @@ -1192,6 +1195,54 @@ struct SimInstance child.second->addAdditionalInputs(); } + // Preconditions / assumptions: + // 1) fst_handles is populated for this instance (0 handle means not in trace). + // 2) fst_inputs is finalized (top-level inputs + addAdditionalInputs() for $anyseq). + // 3) module has no processes (sim enforces proc-lowered input before this point). + // 4) sigmap is valid for per-bit queries on this instance. + // 5) shared->fst is active, i.e. this is called from FST/VCD replay flow. + int checkUndrivenReplaySignals() + { + int issue_count = 0; + bool has_replay_candidates = false; + + for (auto &item : fst_handles) + if (item.second != 0 && !fst_inputs.count(item.first)) { + has_replay_candidates = true; + break; + } + + if (has_replay_candidates) { + DriverMap drivermap(module->design); + drivermap.add(module); + + for (auto &item : fst_handles) { + Wire *wire = item.first; + if (item.second == 0 || fst_inputs.count(wire)) + continue; + + SigSpec undriven; + for (auto bit : sigmap(wire)) + if (bit.wire != nullptr && drivermap(DriveBit(bit)).is_none()) + undriven.append(bit); + + undriven.sort_and_unify(); + if (undriven.empty()) + continue; + + issue_count++; + std::string wire_name = scope + "." + RTLIL::unescape_id(wire->name); + log_warning("Input trace contains undriven signal `%s` (%s); values for this signal are not replayed from FST/VCD input.\n", + wire_name.c_str(), log_signal(undriven, true)); + } + } + + for (auto child : children) + issue_count += child.second->checkUndrivenReplaySignals(); + + return issue_count; + } + bool setInputs() { bool did_something = false; @@ -1248,7 +1299,7 @@ struct SimInstance } else if (shared->sim_mode == SimulationMode::gate && !fst_val.is_fully_def()) { // FST data contains X for(int i=0;isim_mode == SimulationMode::gold && !sim_val.is_fully_def()) { // sim data contains X for(int i=0;iaddAdditionalInputs(); + if (undriven_check) { + int issue_count = top->checkUndrivenReplaySignals(); + if (issue_count > 0 && !undriven_warning) + log_cmd_error("Found %d undriven signal%s in the replay trace. Use -undriven-warn to continue or -no-undriven-check to disable this check.\n", + issue_count, issue_count == 1 ? "" : "s"); + } uint64_t startCount = 0; uint64_t stopCount = 0; @@ -2627,6 +2684,12 @@ struct SimPass : public Pass { log(" Yosys witness (.yw) replay is preferred when possible.\n"); log(" VCD support requires vcd2fst external tool to be present\n"); log("\n"); + log(" -no-undriven-check\n"); + log(" skip undriven-signal checks for FST/VCD replay\n"); + log("\n"); + log(" -undriven-warn\n"); + log(" downgrade undriven-signal replay errors to warnings\n"); + log("\n"); log(" -width \n"); log(" cycle width in generated simulation output (must be divisible by 2).\n"); log("\n"); @@ -2844,6 +2907,14 @@ struct SimPass : public Pass { worker.fst_noinit = true; continue; } + if (args[argidx] == "-no-undriven-check") { + worker.undriven_check = false; + continue; + } + if (args[argidx] == "-undriven-warn") { + worker.undriven_warning = true; + continue; + } if (args[argidx] == "-x") { worker.ignore_x = true; continue; diff --git a/tests/sim/undriven_replay.v b/tests/sim/undriven_replay.v new file mode 100644 index 000000000..501f438a1 --- /dev/null +++ b/tests/sim/undriven_replay.v @@ -0,0 +1,7 @@ +module undriven_replay ( + input wire in, + output wire out, + output wire undrv +); + assign out = in; +endmodule diff --git a/tests/sim/undriven_replay.vcd b/tests/sim/undriven_replay.vcd new file mode 100644 index 000000000..e9cc35ae5 --- /dev/null +++ b/tests/sim/undriven_replay.vcd @@ -0,0 +1,15 @@ +$version Yosys $end +$scope module undriven_replay $end +$var wire 1 ! in $end +$var wire 1 " out $end +$var wire 1 # undrv $end +$upscope $end +$enddefinitions $end +#0 +b0 ! +b0 " +b1 # +#10 +b1 ! +b1 " +b0 # diff --git a/tests/sim/undriven_replay.ys b/tests/sim/undriven_replay.ys new file mode 100644 index 000000000..9766a8d60 --- /dev/null +++ b/tests/sim/undriven_replay.ys @@ -0,0 +1,10 @@ +read_verilog undriven_replay.v +prep -top undriven_replay + +logger -expect error "Found 1 undriven signal in the replay trace" 1 +sim -r undriven_replay.vcd -scope undriven_replay -q + +logger -expect warning "Input trace contains undriven signal" 1 +sim -r undriven_replay.vcd -scope undriven_replay -q -undriven-warn + +sim -r undriven_replay.vcd -scope undriven_replay -q -no-undriven-check From c0f1654028736cd88d2fa7cae5b0335371e8e866 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Mon, 23 Feb 2026 10:27:36 -0800 Subject: [PATCH 003/262] Expand test into three tests for three cases (1) no check, (2) check with warning, (3) check with error. Previously the single test was not testing all cases, as it was exiting after the first error. --- tests/sim/undriven_replay.ys | 5 ----- tests/sim/undriven_replay_nocheck.ys | 4 ++++ tests/sim/undriven_replay_warn.ys | 5 +++++ 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 tests/sim/undriven_replay_nocheck.ys create mode 100644 tests/sim/undriven_replay_warn.ys diff --git a/tests/sim/undriven_replay.ys b/tests/sim/undriven_replay.ys index 9766a8d60..854a40049 100644 --- a/tests/sim/undriven_replay.ys +++ b/tests/sim/undriven_replay.ys @@ -3,8 +3,3 @@ prep -top undriven_replay logger -expect error "Found 1 undriven signal in the replay trace" 1 sim -r undriven_replay.vcd -scope undriven_replay -q - -logger -expect warning "Input trace contains undriven signal" 1 -sim -r undriven_replay.vcd -scope undriven_replay -q -undriven-warn - -sim -r undriven_replay.vcd -scope undriven_replay -q -no-undriven-check diff --git a/tests/sim/undriven_replay_nocheck.ys b/tests/sim/undriven_replay_nocheck.ys new file mode 100644 index 000000000..dcb1cfc92 --- /dev/null +++ b/tests/sim/undriven_replay_nocheck.ys @@ -0,0 +1,4 @@ +read_verilog undriven_replay.v +prep -top undriven_replay + +sim -r undriven_replay.vcd -scope undriven_replay -q -no-undriven-check diff --git a/tests/sim/undriven_replay_warn.ys b/tests/sim/undriven_replay_warn.ys new file mode 100644 index 000000000..ca3b1937c --- /dev/null +++ b/tests/sim/undriven_replay_warn.ys @@ -0,0 +1,5 @@ +read_verilog undriven_replay.v +prep -top undriven_replay + +logger -expect warning "Input trace contains undriven signal" 1 +sim -r undriven_replay.vcd -scope undriven_replay -q -undriven-warn From 366f98ae25bf45be94a6ea8118abe431eb676bdf Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Mon, 23 Feb 2026 11:51:54 -0800 Subject: [PATCH 004/262] ADd clarification --- passes/sat/sim.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index bd723f5f1..ddc256384 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -2685,7 +2685,7 @@ struct SimPass : public Pass { log(" VCD support requires vcd2fst external tool to be present\n"); log("\n"); log(" -no-undriven-check\n"); - log(" skip undriven-signal checks for FST/VCD replay\n"); + log(" skip undriven-signal checks for FST/VCD replay (can be expensive for large designs)\n"); log("\n"); log(" -undriven-warn\n"); log(" downgrade undriven-signal replay errors to warnings\n"); From 7d3e56523bf93fb3c63fc19de843278f38e43012 Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 13 May 2026 16:25:15 +0200 Subject: [PATCH 005/262] Preserve param signedness across overrides. --- kernel/rtlil.cc | 9 +++++++++ kernel/rtlil.h | 2 ++ passes/cmds/setattr.cc | 1 + passes/hierarchy/hierarchy.cc | 8 ++++++-- tests/verilog/issue5745.ys | 18 ++++++++++++++++++ 5 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/verilog/issue5745.ys diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a99f0803e..1a7dc6b41 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -615,6 +615,15 @@ int RTLIL::Const::as_int_saturating(bool is_signed) const return as_int(is_signed); } +void RTLIL::Const::tag_bare_integer_const(const std::string &value) +{ + if (value.empty() || value.find('\'') != std::string::npos) + return; + size_t start = (value[0] == '-' || value[0] == '+') ? 1 : 0; + if (start < value.size() && std::all_of(value.begin() + start, value.end(), ::isdigit)) + flags |= RTLIL::CONST_FLAG_SIGNED; +} + int RTLIL::Const::get_min_size(bool is_signed) const { if (empty()) return 0; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index b32f9ea76..e55caf35a 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1091,6 +1091,8 @@ public: // over/underflow, otherwise the max/min value for int depending on the sign. int as_int_saturating(bool is_signed = false) const; + void tag_bare_integer_const(const std::string &value); + std::string as_string(const char* any = "-") const; static Const from_string(const std::string &str); std::vector to_bits() const; diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc index 25d8fd34c..ef9bd0d34 100644 --- a/passes/cmds/setattr.cc +++ b/passes/cmds/setattr.cc @@ -41,6 +41,7 @@ struct setunset_t if (!RTLIL::SigSpec::parse(sig_value, nullptr, set_value)) log_cmd_error("Can't decode value '%s'!\n", set_value); value = sig_value.as_const(); + value.tag_bare_integer_const(set_value); } } }; diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 416997bee..34cedfd34 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -985,7 +985,9 @@ struct HierarchyPass : public Pass { SigSpec sig_value; if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) log_cmd_error("Can't decode value '%s'!\n", para.second); - top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); + RTLIL::Const c = sig_value.as_const(); + c.tag_bare_integer_const(para.second); + top_parameters[RTLIL::escape_id(para.first)] = c; } } @@ -1073,7 +1075,9 @@ struct HierarchyPass : public Pass { SigSpec sig_value; if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) log_cmd_error("Can't decode value '%s'!\n", para.second); - top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); + RTLIL::Const c = sig_value.as_const(); + c.tag_bare_integer_const(para.second); + top_parameters[RTLIL::escape_id(para.first)] = c; } top_mod = design->module(top_mod->derive(design, top_parameters)); diff --git a/tests/verilog/issue5745.ys b/tests/verilog/issue5745.ys new file mode 100644 index 000000000..938ead63a --- /dev/null +++ b/tests/verilog/issue5745.ys @@ -0,0 +1,18 @@ +# Issue #5745: chparam values are unsigned when using read_verilog frontend +# +# When chparam overrides a parameter value, the signed attribute is lost, +# causing signed comparisons to silently use unsigned logic. +# +# m = -32 (signed 9-bit), p2 = 11. Correct signed semantics: -32 < 11, so k = 1. +# Bug: chparam strips the signed attribute from p2. The $lt cell gets A_SIGNED=0, +# B_SIGNED=0, so the comparison treats m as unsigned (480 > 11), giving k = 0. + +read_verilog < Date: Wed, 13 May 2026 16:52:07 +0200 Subject: [PATCH 006/262] Make sure to apply correct signedness to loop vars. --- backends/verilog/verilog_backend.cc | 11 ++--- frontends/ast/simplify.cc | 29 ++++++++----- tests/verilog/for_loop_signed_index.ys | 56 ++++++++++++++++++++++++++ tests/verilog/issue4402.ys | 32 +++++++++++++++ 4 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 tests/verilog/for_loop_signed_index.ys create mode 100644 tests/verilog/issue4402.ys diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 73ffcbf3e..d5f83aefc 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -456,21 +456,22 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire) if (wire->attributes.count(ID::single_bit_vector)) range = stringf(" [%d:%d]", wire->start_offset, wire->start_offset); } + std::string sign = wire->is_signed ? " signed" : ""; if (wire->port_input && !wire->port_output) - f << stringf("%s" "input%s %s;\n", indent, range, id(wire->name)); + f << stringf("%s" "input%s%s %s;\n", indent, sign, range, id(wire->name)); if (!wire->port_input && wire->port_output) - f << stringf("%s" "output%s %s;\n", indent, range, id(wire->name)); + f << stringf("%s" "output%s%s %s;\n", indent, sign, range, id(wire->name)); if (wire->port_input && wire->port_output) - f << stringf("%s" "inout%s %s;\n", indent, range, id(wire->name)); + f << stringf("%s" "inout%s%s %s;\n", indent, sign, range, id(wire->name)); if (reg_wires.count(wire->name)) { - f << stringf("%s" "reg%s %s", indent, range, id(wire->name)); + f << stringf("%s" "reg%s%s %s", indent, sign, range, id(wire->name)); if (wire->attributes.count(ID::init)) { f << stringf(" = "); dump_const(f, wire->attributes.at(ID::init)); } f << stringf(";\n"); } else - f << stringf("%s" "wire%s %s;\n", indent, range, id(wire->name)); + f << stringf("%s" "wire%s%s %s;\n", indent, sign, range, id(wire->name)); #endif } diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 48a4291d2..3012a4ccf 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2619,21 +2619,27 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("Right hand side of 1st expression of %s for-loop is not constant!\n", loop_type_str); auto resolved = current_scope.at(init_ast->children[0]->str); - if (resolved->range_valid) { - int const_size = varbuf->range_left - varbuf->range_right; - int resolved_size = resolved->range_left - resolved->range_right; - if (const_size < resolved_size) { - for (int i = const_size; i < resolved_size; i++) - varbuf->bits.push_back(resolved->is_signed ? varbuf->bits.back() : State::S0); - varbuf->range_left = resolved->range_left; - varbuf->range_right = resolved->range_right; - varbuf->range_swapped = resolved->range_swapped; - varbuf->range_valid = resolved->range_valid; + auto apply_loop_var_type = [&resolved](std::unique_ptr &value) { + if (resolved->range_valid) { + int const_size = value->range_left - value->range_right; + int resolved_size = resolved->range_left - resolved->range_right; + if (const_size < resolved_size) { + for (int i = const_size; i < resolved_size; i++) + value->bits.push_back(resolved->is_signed ? value->bits.back() : State::S0); + value->range_left = resolved->range_left; + value->range_right = resolved->range_right; + value->range_swapped = resolved->range_swapped; + value->range_valid = resolved->range_valid; + } } - } + value->is_signed = resolved->is_signed; + }; + + apply_loop_var_type(varbuf); varbuf = std::make_unique(location, AST_LOCALPARAM, std::move(varbuf)); varbuf->str = init_ast->children[0]->str; + varbuf->is_signed = resolved->is_signed; AstNode *backup_scope_varbuf = current_scope[varbuf->str]; current_scope[varbuf->str] = varbuf.get(); @@ -2708,6 +2714,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (buf->type != AST_CONSTANT) input_error("Right hand side of 3rd expression of %s for-loop is not constant (%s)!\n", loop_type_str, type2str(buf->type)); + apply_loop_var_type(buf); varbuf->children[0] = std::move(buf); } diff --git a/tests/verilog/for_loop_signed_index.ys b/tests/verilog/for_loop_signed_index.ys new file mode 100644 index 000000000..a2bde3395 --- /dev/null +++ b/tests/verilog/for_loop_signed_index.ys @@ -0,0 +1,56 @@ +# Regression test: when procedural for-loops are unrolled, the constant +# replacement for the loop variable must keep the variable's declared +# signedness. + +read_verilog < y=0 +# Post-synthesis (unfixed): wire0 loses signed, 1<=0 false -> y=1 (BUG) +# Post-synthesis (fixed): wire0 retains signed, -1<=0 true -> y=0 + +! mkdir -p temp + +read_verilog < Date: Sun, 17 May 2026 02:27:55 +0000 Subject: [PATCH 007/262] smt2: use canonical SMT names in memory metadata --- backends/smt2/smt2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index a9030e18a..66ae4d51c 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -788,7 +788,7 @@ struct Smt2Worker if (has_async_wr && has_sync_wr) log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", cell, module); - decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", mem->memid.unescape(), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync")); + decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", get_id(mem->memid), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync")); decls.push_back(witness_memory(get_id(mem->memid), cell, mem)); string memstate; From 44a1abdadeabf9a9a3d30ccb468ae7a9b14e6864 Mon Sep 17 00:00:00 2001 From: nella Date: Tue, 19 May 2026 12:16:29 +0200 Subject: [PATCH 008/262] Don't repeat VCD warnings + fixups. --- passes/sat/sim.cc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index ddc256384..2b2982ceb 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -429,7 +429,7 @@ struct SimInstance Const value = builder.build(); if (shared->debug) - log("[%s] get %s: %s\n", hiername(), log_signal(sig, true), log_signal(value, true)); + log("[%s] get %s: %s\n", hiername(), log_signal(sig), log_signal(value, true)); return value; } @@ -448,7 +448,7 @@ struct SimInstance } if (shared->debug) - log("[%s] set %s: %s\n", hiername(), log_signal(sig, true), log_signal(value, true)); + log("[%s] set %s: %s\n", hiername(), log_signal(sig), log_signal(value, true)); return did_something; } @@ -1201,7 +1201,7 @@ struct SimInstance // 3) module has no processes (sim enforces proc-lowered input before this point). // 4) sigmap is valid for per-bit queries on this instance. // 5) shared->fst is active, i.e. this is called from FST/VCD replay flow. - int checkUndrivenReplaySignals() + int checkUndrivenReplaySignals(bool &any_undriven_found) { int issue_count = 0; bool has_replay_candidates = false; @@ -1231,14 +1231,14 @@ struct SimInstance continue; issue_count++; + any_undriven_found = true; std::string wire_name = scope + "." + RTLIL::unescape_id(wire->name); - log_warning("Input trace contains undriven signal `%s` (%s); values for this signal are not replayed from FST/VCD input.\n", - wire_name.c_str(), log_signal(undriven, true)); + log_warning("Input trace contains undriven signal `%s` (%s).\n", wire_name.c_str(), log_signal(undriven)); } } for (auto child : children) - issue_count += child.second->checkUndrivenReplaySignals(); + issue_count += child.second->checkUndrivenReplaySignals(any_undriven_found); return issue_count; } @@ -1550,7 +1550,10 @@ struct SimWorker : SimShared top->addAdditionalInputs(); if (undriven_check) { - int issue_count = top->checkUndrivenReplaySignals(); + bool any_undriven_found = false; + int issue_count = top->checkUndrivenReplaySignals(any_undriven_found); + if (any_undriven_found) + log_warning("Values for the undriven signal(s) listed above are not replayed from FST/VCD input.\n"); if (issue_count > 0 && !undriven_warning) log_cmd_error("Found %d undriven signal%s in the replay trace. Use -undriven-warn to continue or -no-undriven-check to disable this check.\n", issue_count, issue_count == 1 ? "" : "s"); From f69a5fc0779ba91eb92a6152dc33d29523e43347 Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 29 Apr 2026 11:21:26 +0200 Subject: [PATCH 009/262] Elim equiv bits. --- passes/opt/opt_dff.cc | 284 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 283 insertions(+), 1 deletion(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 709b5fc4c..cc669f902 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -919,6 +919,286 @@ struct OptDffWorker return did_something; } + + struct EqBit { + Cell *cell; + int idx; + SigBit q; + }; + + struct SigKey { + enum Flag : uint16_t { + InitOne = 1u << 0, + InitX = 1u << 1, + PolClk = 1u << 2, + PolCe = 1u << 3, + PolSrst = 1u << 4, + PolArst = 1u << 5, + PolAload = 1u << 6, + PolClr = 1u << 7, + PolSet = 1u << 8, + CeOverSrst = 1u << 9, + }; + + SigBit clk, ce, srst, arst, aload, clr, set; + IdString cell_type; // for SR + uint16_t flags; + + bool operator==(const SigKey &o) const { + return flags == o.flags && clk == o.clk && ce == o.ce && srst == o.srst && arst == o.arst + && aload == o.aload && clr == o.clr && set == o.set && cell_type == o.cell_type; + } + + Hasher hash_into(Hasher h) const { + h.eat(flags); + h.eat(clk); + h.eat(ce); + h.eat(srst); + h.eat(arst); + h.eat(aload); + h.eat(clr); + h.eat(set); + h.eat(cell_type); + return h; + } + }; + + bool is_def(State s) { + return s == State::S0 || s == State::S1; + } + + int sat_mux(QuickConeSat &qcsat, int s, int a, int b) { + return qcsat.ez->OR(qcsat.ez->AND(s, a), qcsat.ez->AND(qcsat.ez->NOT(s), b)); + } + + int sat_const(QuickConeSat &qcsat, State v) { + return v == State::S1 ? qcsat.ez->CONST_TRUE : qcsat.ez->CONST_FALSE; + } + + bool run_eqbits() + { + std::vector bits; + std::vector keys; + dict ff_for_cell; + + // Collect FF bits eligible for merging + for (auto cell : module->selected_cells()) { + if (!cell->is_builtin_ff()) + continue; + + FfData ff(&initvals, cell); + if (!ff.has_clk && !ff.has_gclk) + continue; + + ff_for_cell.emplace(cell, ff); + + for (int i = 0; i < ff.width; i++) { + // X value + if (ff.has_srst && !is_def(ff.val_srst[i])) continue; + if (ff.has_arst && !is_def(ff.val_arst[i])) continue; + + // Missing anchor + bool def_init = is_def(ff.val_init[i]); + if (!def_init && !ff.has_srst && !ff.has_arst) + continue; + + SigKey k = {}; + + // Flags + if (def_init && ff.val_init[i] == State::S1) + k.flags |= SigKey::InitOne; + else if (!def_init) + k.flags |= SigKey::InitX; + + if (ff.has_clk) { + k.clk = ff.sig_clk; + if (ff.pol_clk) k.flags |= SigKey::PolClk; + } + if (ff.has_ce) { + k.ce = ff.sig_ce; + if (ff.pol_ce) k.flags |= SigKey::PolCe; + } + if (ff.has_srst) { + k.srst = ff.sig_srst; + if (ff.pol_srst) k.flags |= SigKey::PolSrst; + if (ff.ce_over_srst) k.flags |= SigKey::CeOverSrst; + } + if (ff.has_arst) { + k.arst = ff.sig_arst; + if (ff.pol_arst) k.flags |= SigKey::PolArst; + } + if (ff.has_aload) { + k.aload = ff.sig_aload; + if (ff.pol_aload) k.flags |= SigKey::PolAload; + } + if (ff.has_sr) { + k.clr = ff.sig_clr[i]; + k.set = ff.sig_set[i]; + k.cell_type = cell->type; + if (ff.pol_clr) k.flags |= SigKey::PolClr; + if (ff.pol_set) k.flags |= SigKey::PolSet; + } + + bits.push_back({cell, i, ff.sig_q[i]}); + keys.push_back(k); + } + } + + if (GetSize(bits) < 2) + return false; + + // Group bits by control signature + dict> buckets; + for (int i = 0; i < GetSize(bits); i++) + buckets[keys[i]].push_back(i); + + std::vector> classes; + classes.reserve(GetSize(buckets)); + for (auto &kv : buckets) + if (GetSize(kv.second) >= 2) + classes.push_back(std::move(kv.second)); + + if (classes.empty()) + return false; + + ModWalker modwalker(module->design, module); + QuickConeSat qcsat(modwalker); + std::vector q_lit(bits.size(), -1); + std::vector n_lit(bits.size(), -1); + + // Per candidate SAT for its next state, model difference + for (auto &cls : classes) { + for (int idx : cls) { + const EqBit &eb = bits[idx]; + const FfData &ff = ff_for_cell.at(eb.cell); + q_lit[idx] = qcsat.importSigBit(eb.q); + int n = qcsat.importSigBit(ff.sig_d[eb.idx]); + + if (ff.has_aload) { + int al = qcsat.importSigBit(ff.sig_aload); + if (!ff.pol_aload) al = qcsat.ez->NOT(al); + int ad = qcsat.importSigBit(ff.sig_ad[eb.idx]); + n = sat_mux(qcsat, al, ad, n); + } + if (ff.has_arst) { + int ar = qcsat.importSigBit(ff.sig_arst); + if (!ff.pol_arst) ar = qcsat.ez->NOT(ar); + n = sat_mux(qcsat, ar, sat_const(qcsat, ff.val_arst[eb.idx]), n); + } + if (ff.has_sr) { + int clr = qcsat.importSigBit(ff.sig_clr[eb.idx]); + if (!ff.pol_clr) clr = qcsat.ez->NOT(clr); + int set = qcsat.importSigBit(ff.sig_set[eb.idx]); + if (!ff.pol_set) set = qcsat.ez->NOT(set); + n = qcsat.ez->AND(qcsat.ez->NOT(clr), qcsat.ez->OR(set, n)); + } + if (ff.has_srst) { + int srst = qcsat.importSigBit(ff.sig_srst); + if (!ff.pol_srst) srst = qcsat.ez->NOT(srst); + n = sat_mux(qcsat,srst, sat_const(qcsat, ff.val_srst[eb.idx]), n); + } + + n_lit[idx] = n; + } + } + + qcsat.prepare(); + bool any_change = false; + bool changed = true; + + // Bit = class rep, split classes whenever two next states differ + while (changed) { + changed = false; + int joint = qcsat.ez->CONST_TRUE; + + for (auto &cls : classes) { + int rep = cls[0]; + for (int k = 1; k < GetSize(cls); k++) + joint = qcsat.ez->AND(joint, qcsat.ez->IFF(q_lit[rep], q_lit[cls[k]])); + } + + std::vector> new_classes; + new_classes.reserve(classes.size()); + + for (auto &cls : classes) { + std::vector> subs; + for (int b : cls) { + bool placed = false; + + // Identical literal - trivially eq + for (auto &sub : subs) { + if (n_lit[sub[0]] == n_lit[b]) { + sub.push_back(b); + placed = true; + break; + } + } + + if (placed) continue; + + for (auto &sub : subs) { + int rep = sub[0]; + int query = qcsat.ez->NOT(qcsat.ez->IFF(n_lit[rep], n_lit[b])); + if (!qcsat.ez->solve(joint, query)) { + sub.push_back(b); + placed = true; + break; + } + } + + if (!placed) + subs.push_back({b}); + } + + if (GetSize(subs) > 1) + changed = true; + for (auto &sub : subs) + if (GetSize(sub) >= 2) + new_classes.push_back(std::move(sub)); + } + + classes = std::move(new_classes); + if (changed) + any_change = true; + } + + if (classes.empty()) + return any_change; + + dict> remove_bits; + + // Drive every non-rep Q from its class rep, drop merged bits from their FFs + for (auto &cls : classes) { + SigBit rep_q = bits[cls[0]].q; + for (int k = 1; k < GetSize(cls); k++) { + const EqBit &eb = bits[cls[k]]; + initvals.remove_init(eb.q); + module->connect(eb.q, rep_q); + remove_bits[eb.cell].insert(eb.idx); + } + } + + for (auto &kv : remove_bits) { + Cell *cell = kv.first; + const std::set &drop = kv.second; + FfData &ff = ff_for_cell.at(cell); + std::vector keep; + + for (int i = 0; i < ff.width; i++) + if (!drop.count(i)) + keep.push_back(i); + + if (keep.empty()) { + module->remove(cell); + } else { + FfData new_ff = ff.slice(keep); + new_ff.cell = cell; + new_ff.emit(); + } + } + + return true; + } }; struct OptDffPass : public Pass { @@ -946,7 +1226,7 @@ struct OptDffPass : public Pass { log(" -simple-dffe\n"); log(" only enables clock enable recognition transform for obvious cases\n"); log("\n"); - log(" -sat\n"); + log(" -sat AAA\n"); log(" additionally invoke SAT solver to detect and remove flip-flops (with\n"); log(" non-constant inputs) that can also be replaced with a constant driver\n"); log("\n"); @@ -987,6 +1267,8 @@ struct OptDffPass : public Pass { did_something = true; if (worker.run_constbits()) did_something = true; + if (opt.sat && worker.run_eqbits()) + did_something = true; } if (did_something) From d85e3f10de301d1bd594042cf71a3d8f15cf4d8a Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 29 Apr 2026 15:55:45 +0200 Subject: [PATCH 010/262] Add tests. --- passes/opt/opt_dff.cc | 4 +- tests/opt/opt_dff_eqbits.ys | 56 ++++++++ tests/opt/opt_dff_eqbits_large.sv | 231 ++++++++++++++++++++++++++++++ tests/opt/opt_dff_eqbits_small.sv | 30 ++++ 4 files changed, 319 insertions(+), 2 deletions(-) create mode 100644 tests/opt/opt_dff_eqbits.ys create mode 100644 tests/opt/opt_dff_eqbits_large.sv create mode 100644 tests/opt/opt_dff_eqbits_small.sv diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index cc669f902..241ea6888 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -1095,7 +1095,7 @@ struct OptDffWorker if (ff.has_srst) { int srst = qcsat.importSigBit(ff.sig_srst); if (!ff.pol_srst) srst = qcsat.ez->NOT(srst); - n = sat_mux(qcsat,srst, sat_const(qcsat, ff.val_srst[eb.idx]), n); + n = sat_mux(qcsat, srst, sat_const(qcsat, ff.val_srst[eb.idx]), n); } n_lit[idx] = n; @@ -1226,7 +1226,7 @@ struct OptDffPass : public Pass { log(" -simple-dffe\n"); log(" only enables clock enable recognition transform for obvious cases\n"); log("\n"); - log(" -sat AAA\n"); + log(" -sat\n"); log(" additionally invoke SAT solver to detect and remove flip-flops (with\n"); log(" non-constant inputs) that can also be replaced with a constant driver\n"); log("\n"); diff --git a/tests/opt/opt_dff_eqbits.ys b/tests/opt/opt_dff_eqbits.ys new file mode 100644 index 000000000..10e9045e4 --- /dev/null +++ b/tests/opt/opt_dff_eqbits.ys @@ -0,0 +1,56 @@ +# small test case +design -reset +read_verilog -sv opt_dff_eqbits_small.sv +hierarchy -top test_case +techmap +opt_dff -sat +synth +opt_dff -sat +opt_clean -purge + +select -assert-count 2 t:$_SDFF_PN0_ + +# equivalence +design -reset +read_verilog -sv opt_dff_eqbits_small.sv +hierarchy -top test_case +prep +design -save gold + +opt_dff -sat +design -save gate + +design -copy-from gold -as gold test_case +design -copy-from gate -as gate test_case +equiv_make gold gate equiv +equiv_induct equiv +equiv_status -assert + + +# large test case +design -reset +read_verilog -sv opt_dff_eqbits_large.sv +hierarchy -top test_case +techmap +opt_dff -sat +synth +opt_dff -sat +opt_clean -purge + +select -assert-count 6 t:$_SDFFE_PN0P_ + +# equivalence +design -reset +read_verilog -sv opt_dff_eqbits_large.sv +hierarchy -top test_case +prep +design -save gold + +opt_dff -sat +design -save gate + +design -copy-from gold -as gold test_case +design -copy-from gate -as gate test_case +equiv_make gold gate equiv +equiv_induct equiv +equiv_status -assert diff --git a/tests/opt/opt_dff_eqbits_large.sv b/tests/opt/opt_dff_eqbits_large.sv new file mode 100644 index 000000000..4b32c7f8e --- /dev/null +++ b/tests/opt/opt_dff_eqbits_large.sv @@ -0,0 +1,231 @@ +module test_case ( + input wire clk, + input wire rst_n, + input wire [3:0] chan_0_data, + input wire chan_0_vld, + input wire chan_1_rdy, + output wire chan_0_rdy, + output wire [207:0] chan_1_data, + output wire chan_1_vld, + output wire idle +); + wire [12:0] state_init[0:15]; + assign state_init[0] = 13'h0000; + assign state_init[1] = 13'h0000; + assign state_init[2] = 13'h0000; + assign state_init[3] = 13'h0000; + assign state_init[4] = 13'h0000; + assign state_init[5] = 13'h0000; + assign state_init[6] = 13'h0000; + assign state_init[7] = 13'h0000; + assign state_init[8] = 13'h0000; + assign state_init[9] = 13'h0000; + assign state_init[10] = 13'h0000; + assign state_init[11] = 13'h0000; + assign state_init[12] = 13'h0000; + assign state_init[13] = 13'h0000; + assign state_init[14] = 13'h0000; + assign state_init[15] = 13'h0000; + + wire [12:0] ch1_init[0:15]; + assign ch1_init[0] = 13'h0000; + assign ch1_init[1] = 13'h0000; + assign ch1_init[2] = 13'h0000; + assign ch1_init[3] = 13'h0000; + assign ch1_init[4] = 13'h0000; + assign ch1_init[5] = 13'h0000; + assign ch1_init[6] = 13'h0000; + assign ch1_init[7] = 13'h0000; + assign ch1_init[8] = 13'h0000; + assign ch1_init[9] = 13'h0000; + assign ch1_init[10] = 13'h0000; + assign ch1_init[11] = 13'h0000; + assign ch1_init[12] = 13'h0000; + assign ch1_init[13] = 13'h0000; + assign ch1_init[14] = 13'h0000; + assign ch1_init[15] = 13'h0000; + + wire [12:0] mask_1fff[0:15]; + assign mask_1fff[0] = 13'h1fff; + assign mask_1fff[1] = 13'h1fff; + assign mask_1fff[2] = 13'h1fff; + assign mask_1fff[3] = 13'h1fff; + assign mask_1fff[4] = 13'h1fff; + assign mask_1fff[5] = 13'h1fff; + assign mask_1fff[6] = 13'h1fff; + assign mask_1fff[7] = 13'h1fff; + assign mask_1fff[8] = 13'h1fff; + assign mask_1fff[9] = 13'h1fff; + assign mask_1fff[10] = 13'h1fff; + assign mask_1fff[11] = 13'h1fff; + assign mask_1fff[12] = 13'h1fff; + assign mask_1fff[13] = 13'h1fff; + assign mask_1fff[14] = 13'h1fff; + assign mask_1fff[15] = 13'h1fff; + + reg [12:0] state_array[0:15]; + reg [3:0] ch0_in_buf; + reg ch0_in_buf_vld; + reg [12:0] ch1_out_buf[0:15]; + reg ch1_out_buf_vld; + reg stg1_vld; + + wire ch1_not_vld; + wire [3:0] ch0_sel_data; + wire ch0_is_vld; + wire ch1_vld_we; + wire ch1_data_we; + wire stg0_vld_out; + wire ch0_buf_ready; + wire ch0_pipe_stall; + wire [1:0] sel_concat; + wire ch0_buf_data_we; + wire ch0_buf_vld_rst; + wire stg0_idle; + wire stg1_idle; + wire ch0_is_inactive; + wire ch1_is_inactive; + wire [12:0] next_state_val[0:15]; + wire state_we; + wire ch0_buf_vld_we; + wire stg1_vld_we; + wire pipe_idle; + + assign ch1_not_vld = ~ch1_out_buf_vld; + assign ch0_sel_data = ch0_in_buf_vld ? ch0_in_buf : chan_0_data; + assign ch0_is_vld = chan_0_vld | ch0_in_buf_vld; + assign ch1_vld_we = chan_1_rdy | ch1_not_vld; + assign ch1_data_we = ch0_is_vld & ch1_vld_we; + assign stg0_vld_out = ch0_is_vld & ch1_data_we; + assign ch0_buf_ready = ~ch0_in_buf_vld; + assign ch0_pipe_stall = ~stg0_vld_out; + assign sel_concat = {ch0_is_vld & ch0_sel_data[0], ch0_is_vld & ~ch0_sel_data[0]}; + assign ch0_buf_data_we = chan_0_vld & ch0_buf_ready & ch0_pipe_stall; + assign ch0_buf_vld_rst = ch0_in_buf_vld & stg0_vld_out; + assign stg0_idle = ~ch0_is_vld; + assign stg1_idle = ~stg1_vld; + assign ch0_is_inactive = ~(chan_0_vld & ch0_buf_ready); + assign ch1_is_inactive = ~(ch1_out_buf_vld & chan_1_rdy); + + assign next_state_val[0] = state_array[0] & {13{sel_concat[0]}} | mask_1fff[0] & {13{sel_concat[1]}}; + assign next_state_val[1] = state_array[1] & {13{sel_concat[0]}} | mask_1fff[1] & {13{sel_concat[1]}}; + assign next_state_val[2] = state_array[2] & {13{sel_concat[0]}} | mask_1fff[2] & {13{sel_concat[1]}}; + assign next_state_val[3] = state_array[3] & {13{sel_concat[0]}} | mask_1fff[3] & {13{sel_concat[1]}}; + assign next_state_val[4] = state_array[4] & {13{sel_concat[0]}} | mask_1fff[4] & {13{sel_concat[1]}}; + assign next_state_val[5] = state_array[5] & {13{sel_concat[0]}} | mask_1fff[5] & {13{sel_concat[1]}}; + assign next_state_val[6] = state_array[6] & {13{sel_concat[0]}} | mask_1fff[6] & {13{sel_concat[1]}}; + assign next_state_val[7] = state_array[7] & {13{sel_concat[0]}} | mask_1fff[7] & {13{sel_concat[1]}}; + assign next_state_val[8] = state_array[8] & {13{sel_concat[0]}} | mask_1fff[8] & {13{sel_concat[1]}}; + assign next_state_val[9] = state_array[9] & {13{sel_concat[0]}} | mask_1fff[9] & {13{sel_concat[1]}}; + assign next_state_val[10] = state_array[10] & {13{sel_concat[0]}} | mask_1fff[10] & {13{sel_concat[1]}}; + assign next_state_val[11] = state_array[11] & {13{sel_concat[0]}} | mask_1fff[11] & {13{sel_concat[1]}}; + assign next_state_val[12] = state_array[12] & {13{sel_concat[0]}} | mask_1fff[12] & {13{sel_concat[1]}}; + assign next_state_val[13] = state_array[13] & {13{sel_concat[0]}} | mask_1fff[13] & {13{sel_concat[1]}}; + assign next_state_val[14] = state_array[14] & {13{sel_concat[0]}} | mask_1fff[14] & {13{sel_concat[1]}}; + assign next_state_val[15] = state_array[15] & {13{sel_concat[0]}} | mask_1fff[15] & {13{sel_concat[1]}}; + + assign state_we = stg0_vld_out & ch0_sel_data[0] | stg0_vld_out & ~ch0_sel_data[0]; + assign ch0_buf_vld_we = ch0_buf_data_we | ch0_buf_vld_rst; + assign stg1_vld_we = stg0_vld_out | stg1_vld; + assign pipe_idle = stg0_idle & stg1_idle & ch0_is_inactive & ch1_is_inactive; + + always @(posedge clk) begin + if (!rst_n) begin + state_array[0] <= state_init[0]; + state_array[1] <= state_init[1]; + state_array[2] <= state_init[2]; + state_array[3] <= state_init[3]; + state_array[4] <= state_init[4]; + state_array[5] <= state_init[5]; + state_array[6] <= state_init[6]; + state_array[7] <= state_init[7]; + state_array[8] <= state_init[8]; + state_array[9] <= state_init[9]; + state_array[10] <= state_init[10]; + state_array[11] <= state_init[11]; + state_array[12] <= state_init[12]; + state_array[13] <= state_init[13]; + state_array[14] <= state_init[14]; + state_array[15] <= state_init[15]; + ch0_in_buf <= 4'h0; + ch0_in_buf_vld <= 1'h0; + ch1_out_buf[0] <= ch1_init[0]; + ch1_out_buf[1] <= ch1_init[1]; + ch1_out_buf[2] <= ch1_init[2]; + ch1_out_buf[3] <= ch1_init[3]; + ch1_out_buf[4] <= ch1_init[4]; + ch1_out_buf[5] <= ch1_init[5]; + ch1_out_buf[6] <= ch1_init[6]; + ch1_out_buf[7] <= ch1_init[7]; + ch1_out_buf[8] <= ch1_init[8]; + ch1_out_buf[9] <= ch1_init[9]; + ch1_out_buf[10] <= ch1_init[10]; + ch1_out_buf[11] <= ch1_init[11]; + ch1_out_buf[12] <= ch1_init[12]; + ch1_out_buf[13] <= ch1_init[13]; + ch1_out_buf[14] <= ch1_init[14]; + ch1_out_buf[15] <= ch1_init[15]; + ch1_out_buf_vld <= 1'h0; + stg1_vld <= 1'h0; + end else begin + state_array[0] <= state_we ? next_state_val[0] : state_array[0]; + state_array[1] <= state_we ? next_state_val[1] : state_array[1]; + state_array[2] <= state_we ? next_state_val[2] : state_array[2]; + state_array[3] <= state_we ? next_state_val[3] : state_array[3]; + state_array[4] <= state_we ? next_state_val[4] : state_array[4]; + state_array[5] <= state_we ? next_state_val[5] : state_array[5]; + state_array[6] <= state_we ? next_state_val[6] : state_array[6]; + state_array[7] <= state_we ? next_state_val[7] : state_array[7]; + state_array[8] <= state_we ? next_state_val[8] : state_array[8]; + state_array[9] <= state_we ? next_state_val[9] : state_array[9]; + state_array[10] <= state_we ? next_state_val[10] : state_array[10]; + state_array[11] <= state_we ? next_state_val[11] : state_array[11]; + state_array[12] <= state_we ? next_state_val[12] : state_array[12]; + state_array[13] <= state_we ? next_state_val[13] : state_array[13]; + state_array[14] <= state_we ? next_state_val[14] : state_array[14]; + state_array[15] <= state_we ? next_state_val[15] : state_array[15]; + ch0_in_buf <= ch0_buf_data_we ? chan_0_data : ch0_in_buf; + ch0_in_buf_vld <= ch0_buf_vld_we ? ch0_buf_ready : ch0_in_buf_vld; + ch1_out_buf[0] <= ch1_data_we ? state_array[0] : ch1_out_buf[0]; + ch1_out_buf[1] <= ch1_data_we ? state_array[1] : ch1_out_buf[1]; + ch1_out_buf[2] <= ch1_data_we ? state_array[2] : ch1_out_buf[2]; + ch1_out_buf[3] <= ch1_data_we ? state_array[3] : ch1_out_buf[3]; + ch1_out_buf[4] <= ch1_data_we ? state_array[4] : ch1_out_buf[4]; + ch1_out_buf[5] <= ch1_data_we ? state_array[5] : ch1_out_buf[5]; + ch1_out_buf[6] <= ch1_data_we ? state_array[6] : ch1_out_buf[6]; + ch1_out_buf[7] <= ch1_data_we ? state_array[7] : ch1_out_buf[7]; + ch1_out_buf[8] <= ch1_data_we ? state_array[8] : ch1_out_buf[8]; + ch1_out_buf[9] <= ch1_data_we ? state_array[9] : ch1_out_buf[9]; + ch1_out_buf[10] <= ch1_data_we ? state_array[10] : ch1_out_buf[10]; + ch1_out_buf[11] <= ch1_data_we ? state_array[11] : ch1_out_buf[11]; + ch1_out_buf[12] <= ch1_data_we ? state_array[12] : ch1_out_buf[12]; + ch1_out_buf[13] <= ch1_data_we ? state_array[13] : ch1_out_buf[13]; + ch1_out_buf[14] <= ch1_data_we ? state_array[14] : ch1_out_buf[14]; + ch1_out_buf[15] <= ch1_data_we ? state_array[15] : ch1_out_buf[15]; + ch1_out_buf_vld <= ch1_vld_we ? ch0_is_vld : ch1_out_buf_vld; + stg1_vld <= stg1_vld_we ? stg0_vld_out : stg1_vld; + end + end + + assign chan_0_rdy = ch0_buf_ready; + assign chan_1_data = { + ch1_out_buf[15], + ch1_out_buf[14], + ch1_out_buf[13], + ch1_out_buf[12], + ch1_out_buf[11], + ch1_out_buf[10], + ch1_out_buf[9], + ch1_out_buf[8], + ch1_out_buf[7], + ch1_out_buf[6], + ch1_out_buf[5], + ch1_out_buf[4], + ch1_out_buf[3], + ch1_out_buf[2], + ch1_out_buf[1], + ch1_out_buf[0] + }; + assign chan_1_vld = ch1_out_buf_vld; + assign idle = pipe_idle; +endmodule diff --git a/tests/opt/opt_dff_eqbits_small.sv b/tests/opt/opt_dff_eqbits_small.sv new file mode 100644 index 000000000..7c6aeba7f --- /dev/null +++ b/tests/opt/opt_dff_eqbits_small.sv @@ -0,0 +1,30 @@ +module test_case ( + input wire clk, + input wire rst_n, + input wire in_val, + output wire out_a, + output wire out_b, + output wire out_c, + output wire out_d +); + reg a, b, c, d; + + always @(posedge clk) begin + if (!rst_n) begin + a <= 1'b0; + b <= 1'b0; + c <= 1'b0; + d <= 1'b0; + end else begin + a <= c & in_val; + b <= d & in_val; + c <= b | in_val; + d <= a | in_val; + end + end + + assign out_a = a; + assign out_b = b; + assign out_c = c; + assign out_d = d; +endmodule From c6bf13bb94ed8b3f5f7eee14eb67823f497f0e4a Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 13 May 2026 10:49:12 +0200 Subject: [PATCH 011/262] Implement worklist and SAT counterexample splitting. --- passes/opt/opt_dff.cc | 113 ++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 48 deletions(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 241ea6888..ef5c56896 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -1104,62 +1104,76 @@ struct OptDffWorker qcsat.prepare(); bool any_change = false; - bool changed = true; + std::vector worklist; + std::vector in_worklist(GetSize(classes), true); - // Bit = class rep, split classes whenever two next states differ - while (changed) { - changed = false; - int joint = qcsat.ez->CONST_TRUE; + for (int i = 0; i < GetSize(classes); i++) { + worklist.push_back(i); + } - for (auto &cls : classes) { - int rep = cls[0]; - for (int k = 1; k < GetSize(cls); k++) - joint = qcsat.ez->AND(joint, qcsat.ez->IFF(q_lit[rep], q_lit[cls[k]])); + while (!worklist.empty()) { + int cls_idx = worklist.back(); + worklist.pop_back(); + in_worklist[cls_idx] = false; + + auto &cls = classes[cls_idx]; + if (GetSize(cls) < 2) continue; + + std::vector assumptions; + for (auto &c : classes) { + if (GetSize(c) < 2) continue; + int rep = c[0]; + for (int k = 1; k < GetSize(c); k++) { + assumptions.push_back(qcsat.ez->IFF(q_lit[rep], q_lit[c[k]])); + } } - std::vector> new_classes; - new_classes.reserve(classes.size()); + // Split at counterexamples + int rep = cls[0]; + for (int i = 1; i < GetSize(cls); i++) { + // Trivially eqivalent + if (n_lit[rep] == n_lit[cls[i]]) + continue; + + int query = qcsat.ez->NOT(qcsat.ez->IFF(n_lit[rep], n_lit[cls[i]])); + std::vector modelExprs; - for (auto &cls : classes) { - std::vector> subs; for (int b : cls) { - bool placed = false; - - // Identical literal - trivially eq - for (auto &sub : subs) { - if (n_lit[sub[0]] == n_lit[b]) { - sub.push_back(b); - placed = true; - break; - } - } - - if (placed) continue; - - for (auto &sub : subs) { - int rep = sub[0]; - int query = qcsat.ez->NOT(qcsat.ez->IFF(n_lit[rep], n_lit[b])); - if (!qcsat.ez->solve(joint, query)) { - sub.push_back(b); - placed = true; - break; - } - } - - if (!placed) - subs.push_back({b}); + modelExprs.push_back(n_lit[b]); } - if (GetSize(subs) > 1) - changed = true; - for (auto &sub : subs) - if (GetSize(sub) >= 2) - new_classes.push_back(std::move(sub)); - } + std::vector modelVals; + assumptions.push_back(query); + + if (qcsat.ez->solve(modelExprs, modelVals, assumptions)) { + // SAT -> partition entire class + std::vector sub0; + std::vector sub1; - classes = std::move(new_classes); - if (changed) - any_change = true; + for (size_t b_idx = 0; b_idx < cls.size(); b_idx++) { + if (modelVals[b_idx]) + sub1.push_back(cls[b_idx]); + else + sub0.push_back(cls[b_idx]); + } + + classes[cls_idx] = std::move(sub0); + classes.push_back(std::move(sub1)); + in_worklist.push_back(false); + + // Partition was split -> the induction hypo weakened + for (int j = 0; j < GetSize(classes); j++) { + if (GetSize(classes[j]) >= 2 && !in_worklist[j]) { + worklist.push_back(j); + in_worklist[j] = true; + } + } + + break; // Process new splits + } + + assumptions.pop_back(); // Remove query for the next pairwise check if UNSAT + } } if (classes.empty()) @@ -1169,7 +1183,10 @@ struct OptDffWorker // Drive every non-rep Q from its class rep, drop merged bits from their FFs for (auto &cls : classes) { + if (GetSize(cls) < 2) + continue; SigBit rep_q = bits[cls[0]].q; + any_change = true; for (int k = 1; k < GetSize(cls); k++) { const EqBit &eb = bits[cls[k]]; initvals.remove_init(eb.q); @@ -1197,7 +1214,7 @@ struct OptDffWorker } } - return true; + return any_change; } }; From bbec8d2902d3bdf65fb90a99881a94c8dfed520b Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 20 May 2026 15:51:04 +0200 Subject: [PATCH 012/262] Gate behind flag. --- passes/opt/opt_dff.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index ef5c56896..e657a8a2d 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -41,6 +41,7 @@ struct OptDffOptions bool simple_dffe; bool sat; bool keepdc; + bool eqbits; }; struct OptDffWorker @@ -977,6 +978,10 @@ struct OptDffWorker bool run_eqbits() { + if(!opt.eqbits) { + return false; + } + std::vector bits; std::vector keys; dict ff_for_cell; @@ -1253,6 +1258,11 @@ struct OptDffPass : public Pass { log(" all result bits to be set to x. this behavior changes when 'a+0' is\n"); log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n"); log("\n"); + log(" -eqbits\n"); + log(" finds groups of flip flop bits provably holding always-equal values\n"); + log(" across cycles and collapses each group to a single bit, potentially\n"); + log(" reducing the number of required flip flops.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override @@ -1265,6 +1275,7 @@ struct OptDffPass : public Pass { opt.simple_dffe = false; opt.keepdc = false; opt.sat = false; + opt.eqbits = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -1273,6 +1284,7 @@ struct OptDffPass : public Pass { if (args[argidx] == "-simple-dffe") { opt.simple_dffe = true; continue; } if (args[argidx] == "-keepdc") { opt.keepdc = true; continue; } if (args[argidx] == "-sat") { opt.sat = true; continue; } + if (args[argidx] == "-eqbits") { opt.eqbits = true; continue; } break; } extra_args(args, argidx, design); @@ -1284,7 +1296,7 @@ struct OptDffPass : public Pass { did_something = true; if (worker.run_constbits()) did_something = true; - if (opt.sat && worker.run_eqbits()) + if (worker.run_eqbits()) did_something = true; } From 04a1611346afbd7ffbed8b4d625c674694a1f972 Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 20 May 2026 15:58:27 +0200 Subject: [PATCH 013/262] Tests. --- tests/opt/opt_dff_eqbits.ys | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/opt/opt_dff_eqbits.ys b/tests/opt/opt_dff_eqbits.ys index 10e9045e4..181b5d0a7 100644 --- a/tests/opt/opt_dff_eqbits.ys +++ b/tests/opt/opt_dff_eqbits.ys @@ -3,9 +3,9 @@ design -reset read_verilog -sv opt_dff_eqbits_small.sv hierarchy -top test_case techmap -opt_dff -sat +opt_dff -sat -eqbits synth -opt_dff -sat +opt_dff -sat -eqbits opt_clean -purge select -assert-count 2 t:$_SDFF_PN0_ @@ -17,7 +17,7 @@ hierarchy -top test_case prep design -save gold -opt_dff -sat +opt_dff -sat -eqbits design -save gate design -copy-from gold -as gold test_case @@ -32,9 +32,9 @@ design -reset read_verilog -sv opt_dff_eqbits_large.sv hierarchy -top test_case techmap -opt_dff -sat +opt_dff -sat -eqbits synth -opt_dff -sat +opt_dff -sat -eqbits opt_clean -purge select -assert-count 6 t:$_SDFFE_PN0P_ @@ -46,7 +46,7 @@ hierarchy -top test_case prep design -save gold -opt_dff -sat +opt_dff -sat -eqbits design -save gate design -copy-from gold -as gold test_case From 386e63ae20465e401d749ffe160098e7be97f799 Mon Sep 17 00:00:00 2001 From: nella Date: Mon, 25 May 2026 12:49:29 +0200 Subject: [PATCH 014/262] Add prepass for bit simulation. --- kernel/bitsim.h | 79 +++++++++++++++++++++++++++++++++++++++++++ passes/opt/opt_dff.cc | 64 ++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 kernel/bitsim.h diff --git a/kernel/bitsim.h b/kernel/bitsim.h new file mode 100644 index 000000000..a0915e28b --- /dev/null +++ b/kernel/bitsim.h @@ -0,0 +1,79 @@ +#ifndef BITSIM_H +#define BITSIM_H + +#include "kernel/modtools.h" + +YOSYS_NAMESPACE_BEGIN + +struct BitSim { + Module *module; + SigMap &sigmap; + ModWalker &modwalker; + dict sim_vals; + uint64_t rng_state; + + BitSim(Module *m, SigMap &sm, ModWalker &mw) + : module(m), sigmap(sm), modwalker(mw), rng_state(1337) {} + + uint64_t xorshift64() { + rng_state ^= rng_state << 13; + rng_state ^= rng_state >> 7; + rng_state ^= rng_state << 17; + return rng_state; + } + + uint64_t eval_bit(SigBit b) { + SigBit mapped = sigmap(b); + if (mapped == State::S0) return 0ULL; + if (mapped == State::S1) return ~0ULL; + if (mapped == State::Sx || mapped == State::Sz) return 0ULL; + + auto it = sim_vals.find(mapped); + if (it != sim_vals.end()) return it->second; + sim_vals[mapped] = 0; + uint64_t res = 0; + + if (!modwalker.has_drivers(mapped)) { + res = xorshift64(); + } else { + auto &drivers = modwalker.signal_drivers[mapped]; + if (drivers.empty()) { + res = xorshift64(); + } else { + auto driver = *drivers.begin(); + Cell *cell = driver.cell; + + if (cell->is_builtin_ff()) { + res = xorshift64(); + } else if (cell->type == ID($_AND_)) { + res = eval_bit(cell->getPort(ID::A)[0]) & eval_bit(cell->getPort(ID::B)[0]); + } else if (cell->type == ID($_OR_)) { + res = eval_bit(cell->getPort(ID::A)[0]) | eval_bit(cell->getPort(ID::B)[0]); + } else if (cell->type == ID($_XOR_)) { + res = eval_bit(cell->getPort(ID::A)[0]) ^ eval_bit(cell->getPort(ID::B)[0]); + } else if (cell->type == ID($_NOT_)) { + res = ~eval_bit(cell->getPort(ID::A)[0]); + } else if (cell->type == ID($_MUX_)) { + uint64_t s = eval_bit(cell->getPort(ID::S)[0]); + uint64_t a = eval_bit(cell->getPort(ID::A)[0]); + uint64_t b = eval_bit(cell->getPort(ID::B)[0]); + res = (a & ~s) | (b & s); + } else if (cell->type == ID($mux)) { + uint64_t s = eval_bit(cell->getPort(ID::S)[0]); + uint64_t a = eval_bit(cell->getPort(ID::A)[driver.offset]); + uint64_t b = eval_bit(cell->getPort(ID::B)[driver.offset]); + res = (a & ~s) | (b & s); + } else { + res = xorshift64(); + } + } + } + + sim_vals[mapped] = res; + return res; + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index e657a8a2d..dbe0e521a 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -26,6 +26,7 @@ #include "kernel/sigtools.h" #include "kernel/ffinit.h" #include "kernel/ff.h" +#include "kernel/bitsim.h" #include "kernel/pattern.h" #include "passes/techmap/simplemap.h" #include @@ -1067,6 +1068,67 @@ struct OptDffWorker return false; ModWalker modwalker(module->design, module); + BitSim sim(module, sigmap, modwalker); + + // Simulation prepass + // Assume same class + for (auto &cls : classes) { + uint64_t class_q_val = sim.xorshift64(); + for (int idx : cls) { + sim.sim_vals[sigmap(bits[idx].q)] = class_q_val; + } + } + + std::vector> refined_classes; + + for (auto &cls : classes) { + dict> sim_buckets; + for (int idx : cls) { + const EqBit &eb = bits[idx]; + const FfData &ff = ff_for_cell.at(eb.cell); + + uint64_t n_val = sim.eval_bit(ff.sig_d[eb.idx]); + + if (ff.has_aload) { + uint64_t al = sim.eval_bit(ff.sig_aload); + if (!ff.pol_aload) al = ~al; + uint64_t ad = sim.eval_bit(ff.sig_ad[eb.idx]); + n_val = (n_val & ~al) | (ad & al); + } + if (ff.has_arst) { + uint64_t ar = sim.eval_bit(ff.sig_arst); + if (!ff.pol_arst) ar = ~ar; + uint64_t ar_val = (ff.val_arst[eb.idx] == State::S1) ? ~0ULL : 0ULL; + n_val = (n_val & ~ar) | (ar_val & ar); + } + if (ff.has_sr) { + uint64_t clr = sim.eval_bit(ff.sig_clr[eb.idx]); + if (!ff.pol_clr) clr = ~clr; + uint64_t set = sim.eval_bit(ff.sig_set[eb.idx]); + if (!ff.pol_set) set = ~set; + n_val = ~clr & (set | n_val); + } + if (ff.has_srst) { + uint64_t srst = sim.eval_bit(ff.sig_srst); + if (!ff.pol_srst) srst = ~srst; + uint64_t srst_val = (ff.val_srst[eb.idx] == State::S1) ? ~0ULL : 0ULL; + n_val = (n_val & ~srst) | (srst_val & srst); + } + + sim_buckets[n_val].push_back(idx); + } + + for (auto &kv : sim_buckets) { + if (GetSize(kv.second) >= 2) { + refined_classes.push_back(std::move(kv.second)); + } + } + } + + classes = std::move(refined_classes); + if (classes.empty()) + return false; + QuickConeSat qcsat(modwalker); std::vector q_lit(bits.size(), -1); std::vector n_lit(bits.size(), -1); @@ -1136,7 +1198,7 @@ struct OptDffWorker // Split at counterexamples int rep = cls[0]; for (int i = 1; i < GetSize(cls); i++) { - // Trivially eqivalent + // Trivially equivalent if (n_lit[rep] == n_lit[cls[i]]) continue; From 68df0be7d2ef7b3a0dd54abe469b81b9494a48e1 Mon Sep 17 00:00:00 2001 From: nella Date: Mon, 25 May 2026 14:16:55 +0200 Subject: [PATCH 015/262] Remove eqbits flag. --- passes/opt/opt_dff.cc | 106 ++++++++++++++++++++---------------- tests/opt/opt_dff_eqbits.ys | 12 ++-- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index dbe0e521a..500df142e 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -42,7 +42,6 @@ struct OptDffOptions bool simple_dffe; bool sat; bool keepdc; - bool eqbits; }; struct OptDffWorker @@ -977,15 +976,9 @@ struct OptDffWorker return v == State::S1 ? qcsat.ez->CONST_TRUE : qcsat.ez->CONST_FALSE; } - bool run_eqbits() + std::vector> gather_initial_eq_classes(std::vector &bits, dict &ff_for_cell) { - if(!opt.eqbits) { - return false; - } - - std::vector bits; std::vector keys; - dict ff_for_cell; // Collect FF bits eligible for merging for (auto cell : module->selected_cells()) { @@ -1050,27 +1043,26 @@ struct OptDffWorker } } - if (GetSize(bits) < 2) - return false; - - // Group bits by control signature dict> buckets; for (int i = 0; i < GetSize(bits); i++) buckets[keys[i]].push_back(i); std::vector> classes; - classes.reserve(GetSize(buckets)); for (auto &kv : buckets) if (GetSize(kv.second) >= 2) classes.push_back(std::move(kv.second)); - if (classes.empty()) - return false; + return classes; + } - ModWalker modwalker(module->design, module); + std::vector> filter_classes_sim( + const std::vector> &classes, + const std::vector &bits, + const dict &ff_for_cell, + ModWalker &modwalker + ) { BitSim sim(module, sigmap, modwalker); - - // Simulation prepass + // Assume same class for (auto &cls : classes) { uint64_t class_q_val = sim.xorshift64(); @@ -1080,15 +1072,13 @@ struct OptDffWorker } std::vector> refined_classes; - for (auto &cls : classes) { dict> sim_buckets; for (int idx : cls) { const EqBit &eb = bits[idx]; const FfData &ff = ff_for_cell.at(eb.cell); - uint64_t n_val = sim.eval_bit(ff.sig_d[eb.idx]); - + if (ff.has_aload) { uint64_t al = sim.eval_bit(ff.sig_aload); if (!ff.pol_aload) al = ~al; @@ -1118,17 +1108,20 @@ struct OptDffWorker sim_buckets[n_val].push_back(idx); } - for (auto &kv : sim_buckets) { - if (GetSize(kv.second) >= 2) { + for (auto &kv : sim_buckets) + if (GetSize(kv.second) >= 2) refined_classes.push_back(std::move(kv.second)); - } - } } - classes = std::move(refined_classes); - if (classes.empty()) - return false; + return refined_classes; + } + std::vector> filter_classes_sat( + std::vector> classes, + const std::vector &bits, + const dict &ff_for_cell, + ModWalker &modwalker + ) { QuickConeSat qcsat(modwalker); std::vector q_lit(bits.size(), -1); std::vector n_lit(bits.size(), -1); @@ -1144,8 +1137,7 @@ struct OptDffWorker if (ff.has_aload) { int al = qcsat.importSigBit(ff.sig_aload); if (!ff.pol_aload) al = qcsat.ez->NOT(al); - int ad = qcsat.importSigBit(ff.sig_ad[eb.idx]); - n = sat_mux(qcsat, al, ad, n); + n = sat_mux(qcsat, al, qcsat.importSigBit(ff.sig_ad[eb.idx]), n); } if (ff.has_arst) { int ar = qcsat.importSigBit(ff.sig_arst); @@ -1170,13 +1162,11 @@ struct OptDffWorker } qcsat.prepare(); - bool any_change = false; std::vector worklist; std::vector in_worklist(GetSize(classes), true); - for (int i = 0; i < GetSize(classes); i++) { + for (int i = 0; i < GetSize(classes); i++) worklist.push_back(i); - } while (!worklist.empty()) { int cls_idx = worklist.back(); @@ -1190,9 +1180,8 @@ struct OptDffWorker for (auto &c : classes) { if (GetSize(c) < 2) continue; int rep = c[0]; - for (int k = 1; k < GetSize(c); k++) { + for (int k = 1; k < GetSize(c); k++) assumptions.push_back(qcsat.ez->IFF(q_lit[rep], q_lit[c[k]])); - } } // Split at counterexamples @@ -1204,14 +1193,12 @@ struct OptDffWorker int query = qcsat.ez->NOT(qcsat.ez->IFF(n_lit[rep], n_lit[cls[i]])); std::vector modelExprs; - - for (int b : cls) { + for (int b : cls) modelExprs.push_back(n_lit[b]); - } std::vector modelVals; assumptions.push_back(query); - + if (qcsat.ez->solve(modelExprs, modelVals, assumptions)) { // SAT -> partition entire class std::vector sub0; @@ -1243,9 +1230,12 @@ struct OptDffWorker } } - if (classes.empty()) - return any_change; + return classes; + } + bool apply_eq_merges(const std::vector> &classes, const std::vector &bits, dict &ff_for_cell) + { + bool any_change = false; dict> remove_bits; // Drive every non-rep Q from its class rep, drop merged bits from their FFs @@ -1283,6 +1273,33 @@ struct OptDffWorker return any_change; } + + bool run_eqbits() + { + if (!opt.sat) + return false; + + std::vector bits; + dict ff_for_cell; + + std::vector> classes = gather_initial_eq_classes(bits, ff_for_cell); + if (classes.empty()) + return false; + + ModWalker modwalker(module->design, module); + + // Simulation prepass + classes = filter_classes_sim(classes, bits, ff_for_cell, modwalker); + if (classes.empty()) + return false; + + // SAT prove + classes = filter_classes_sat(std::move(classes), bits, ff_for_cell, modwalker); + if (classes.empty()) + return false; + + return apply_eq_merges(classes, bits, ff_for_cell); + } }; struct OptDffPass : public Pass { @@ -1320,11 +1337,6 @@ struct OptDffPass : public Pass { log(" all result bits to be set to x. this behavior changes when 'a+0' is\n"); log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n"); log("\n"); - log(" -eqbits\n"); - log(" finds groups of flip flop bits provably holding always-equal values\n"); - log(" across cycles and collapses each group to a single bit, potentially\n"); - log(" reducing the number of required flip flops.\n"); - log("\n"); } void execute(std::vector args, RTLIL::Design *design) override @@ -1337,7 +1349,6 @@ struct OptDffPass : public Pass { opt.simple_dffe = false; opt.keepdc = false; opt.sat = false; - opt.eqbits = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -1346,7 +1357,6 @@ struct OptDffPass : public Pass { if (args[argidx] == "-simple-dffe") { opt.simple_dffe = true; continue; } if (args[argidx] == "-keepdc") { opt.keepdc = true; continue; } if (args[argidx] == "-sat") { opt.sat = true; continue; } - if (args[argidx] == "-eqbits") { opt.eqbits = true; continue; } break; } extra_args(args, argidx, design); diff --git a/tests/opt/opt_dff_eqbits.ys b/tests/opt/opt_dff_eqbits.ys index 181b5d0a7..10e9045e4 100644 --- a/tests/opt/opt_dff_eqbits.ys +++ b/tests/opt/opt_dff_eqbits.ys @@ -3,9 +3,9 @@ design -reset read_verilog -sv opt_dff_eqbits_small.sv hierarchy -top test_case techmap -opt_dff -sat -eqbits +opt_dff -sat synth -opt_dff -sat -eqbits +opt_dff -sat opt_clean -purge select -assert-count 2 t:$_SDFF_PN0_ @@ -17,7 +17,7 @@ hierarchy -top test_case prep design -save gold -opt_dff -sat -eqbits +opt_dff -sat design -save gate design -copy-from gold -as gold test_case @@ -32,9 +32,9 @@ design -reset read_verilog -sv opt_dff_eqbits_large.sv hierarchy -top test_case techmap -opt_dff -sat -eqbits +opt_dff -sat synth -opt_dff -sat -eqbits +opt_dff -sat opt_clean -purge select -assert-count 6 t:$_SDFFE_PN0P_ @@ -46,7 +46,7 @@ hierarchy -top test_case prep design -save gold -opt_dff -sat -eqbits +opt_dff -sat design -save gate design -copy-from gold -as gold test_case From 07e3d648aa26fb9f24802b5bb0b5b2e7b5d1c85b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:23 +1200 Subject: [PATCH 016/262] Add check_mem command Comes with a set of tests which (currently) pass with `read_verilog` but fail with `verific` based on #5878. Add `--check-sv`, an alternative to `--prove-sv` with generator defined yosys commands. Helpful for when you want to run the same set of commands on a bunch of sv files. --- passes/cmds/check.cc | 78 +++++++++++++++++++++++++++++++++ tests/check_mem/bad_il.ys | 47 ++++++++++++++++++++ tests/check_mem/generate_mk.py | 8 ++++ tests/check_mem/init.sv | 15 +++++++ tests/check_mem/non_zero.sv | 21 +++++++++ tests/check_mem/power_of_two.sv | 24 ++++++++++ tests/gen_tests_makefile.py | 21 +++++++-- 7 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 tests/check_mem/bad_il.ys create mode 100644 tests/check_mem/generate_mk.py create mode 100644 tests/check_mem/init.sv create mode 100644 tests/check_mem/non_zero.sv create mode 100644 tests/check_mem/power_of_two.sv diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index 6e0d65297..9a0070996 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -23,6 +23,7 @@ #include "kernel/newcelltypes.h" #include "kernel/utils.h" #include "kernel/log_help.h" +#include "kernel/mem.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -453,4 +454,81 @@ struct CheckPass : public Pass { } } CheckPass; +struct CheckMemPass : public Pass { + CheckMemPass() : Pass("check_mem", "check for obvious memory problems in the design") { } + bool formatted_help() override { + auto *help = PrettyHelp::get_current(); + help->set_group("passes/status"); + + auto content_root = help->get_root(); + + content_root->usage("check_mem [selection]"); + content_root->paragraph( + "This pass identifies the following problems in the current design: " + "addressing invalid memory." + ); + + content_root->option("-assert", "produce a runtime error if any problems are found in the current design"); + + return true; + } + void execute(std::vector args, RTLIL::Design *design) override + { + int counter = 0; + bool assert_mode = false; + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-assert") { + assert_mode = true; + continue; + } + break; + } + + extra_args(args, argidx, design); + + log_header(design, "Executing CHECK_MEM pass.\n"); + + for (auto *module : design->selected_unboxed_modules_warn()) { + for (auto mem : Mem::get_selected_memories(module)) { + int min_addr = mem.mem->start_offset; + int max_addr = mem.mem->size + min_addr - 1; + for (auto &init : mem.inits) { + int start = init.addr.as_int(); + if (start < min_addr) { + log_warning("Mem %s.%s starts at %d but initializes address %d.\n", log_id(module), log_id(mem.mem), min_addr, start); + counter++; + } + int end = start + (GetSize(init.data) / mem.width) - 1; + if (end > max_addr) { + log_warning("Mem %s.%s ends at %d but initializes address %d.\n", log_id(module), log_id(mem.mem), max_addr, end); + counter++; + } + } + + auto check_addr = [min_addr, max_addr, &counter, module, &mem](SigSpec &addr_sig, const char* access) { + if (addr_sig.is_fully_const()) { + auto addr = addr_sig.as_int(); + if (addr < min_addr || addr > max_addr) { + log_warning("Mem %s.%s contains entries for addresses %d..%d but %s address %d.\n", log_id(module), log_id(mem.mem), min_addr, max_addr, access, addr); + counter++; + } + } else { + // TODO test variable addresses? may need sat solver + } + }; + + // TODO test ABITS and WIDTH? + for (auto &rd_port : mem.rd_ports) + check_addr(rd_port.addr, "reads"); + for (auto &wr_port : mem.wr_ports) + check_addr(wr_port.addr, "writes"); + } + } + + if (assert_mode && counter > 0) + log_error("Found %d problems in 'check_mem -assert'.\n", counter); + } +} CheckMemPass; + PRIVATE_NAMESPACE_END diff --git a/tests/check_mem/bad_il.ys b/tests/check_mem/bad_il.ys new file mode 100644 index 000000000..06968c32c --- /dev/null +++ b/tests/check_mem/bad_il.ys @@ -0,0 +1,47 @@ +read_rtlil << EOF +module \top + wire input 1 \clk + wire output 1 \o + memory size 2 offset 1 \my_array + cell $meminit \bad_init + parameter \WORDS 1 + parameter \MEMID "\\my_array" + parameter \ABITS 32 + parameter \WIDTH 1 + parameter \PRIORITY 1 + connect \ADDR 0 + connect \DATA 1'0 + end + cell $memwr \bad_wr + parameter \MEMID "\\my_array" + parameter \CLK_ENABLE 1 + parameter \CLK_POLARITY 1 + parameter \PRIORITY 1 + parameter \ABITS 2 + parameter \WIDTH 1 + connect \EN 1'1 + connect \CLK \clk + connect \ADDR 2'00 + connect \DATA 1'0 + end + cell $memrd \bad_rd + parameter \MEMID "\\my_array" + parameter \CLK_ENABLE 0 + parameter \CLK_POLARITY 1 + parameter \TRANSPARENT 0 + parameter \ABITS 2 + parameter \WIDTH 1 + connect \CLK 1'x + connect \EN 1'x + connect \ADDR 2'11 + connect \DATA \o + end +end +EOF + +logger -expect warning "initializes address 0" 1 +logger -expect warning "writes address 0" 1 +logger -expect warning "reads address 3" 1 +check_mem +logger -check-expected +design -reset diff --git a/tests/check_mem/generate_mk.py b/tests/check_mem/generate_mk.py new file mode 100644 index 000000000..ee8dbeb44 --- /dev/null +++ b/tests/check_mem/generate_mk.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 + +import sys +sys.path.append("..") + +import gen_tests_makefile + +gen_tests_makefile.generate(["--check-sv", "--yosys-scripts"], yosys_cmds="hierarchy; proc; check_mem -assert") diff --git a/tests/check_mem/init.sv b/tests/check_mem/init.sv new file mode 100644 index 000000000..f55a0d1c5 --- /dev/null +++ b/tests/check_mem/init.sv @@ -0,0 +1,15 @@ +module top ( + input logic clk, + input logic idx, + output logic [2:0] out_data +); + (* nomem2reg *) + logic my_array [3:2][2:0] = '{'{0, 1, 1}, '{1, 0, 1}}; + + always_comb begin + for (int i=0; i < 3; i++) begin + out_data[i] = my_array[{1'b1, idx}][i]; + end + end + +endmodule diff --git a/tests/check_mem/non_zero.sv b/tests/check_mem/non_zero.sv new file mode 100644 index 000000000..5b3f45c0a --- /dev/null +++ b/tests/check_mem/non_zero.sv @@ -0,0 +1,21 @@ +module top ( + input logic clk, + input logic [3:1][2:0] in_data, + output logic [3:1][2:0] out_data +); + (* nomem2reg *) + logic [2:0] my_array [3:1]; + + always_ff @(posedge clk) begin + for (int i = 1; i <= 3; i++) begin + my_array[i] <= in_data[i]; + end + end + + always_comb begin + for (int i = 1; i <= 3; i++) begin + out_data[i] = my_array[i]; + end + end + +endmodule diff --git a/tests/check_mem/power_of_two.sv b/tests/check_mem/power_of_two.sv new file mode 100644 index 000000000..786168ea0 --- /dev/null +++ b/tests/check_mem/power_of_two.sv @@ -0,0 +1,24 @@ +module top ( + input logic clk, + input logic [1:0][5:0] in_data, + output logic [1:0][5:0] out_data +); + (* nomem2reg *) + logic my_array [1:0][5:0]; + + always_ff @(posedge clk) begin + for (int i = 0; i < 2; i++) begin + for (int j = 0; j <= 5; j++) begin + my_array[i][j] <= in_data[i][j]; + end + end + end + + always_comb begin + for (int i = 0; i < 2; i++) begin + for (int j = 0; j <= 5; j++) begin + out_data[i][j] = my_array[i][j]; + end + end + end +endmodule diff --git a/tests/gen_tests_makefile.py b/tests/gen_tests_makefile.py index 034883a2c..efaa9a652 100644 --- a/tests/gen_tests_makefile.py +++ b/tests/gen_tests_makefile.py @@ -37,6 +37,11 @@ def generate_tcl_test(tcl_file, yosys_args="", commands=""): cmd += f"; \\\n{commands}" generate_target(tcl_file, cmd) +def generate_sv_check(sv_file, yosys_args="", yosys_cmds=""): + yosys_cmd = f'read -sv {sv_file}; {yosys_cmds}' + cmd = f'$(YOSYS) -ql {sv_file}.err -p "{yosys_cmd}" {yosys_args} && mv {sv_file}.err {sv_file}.log' + generate_target(sv_file, cmd) + def generate_sv_test(sv_file, yosys_args="", commands=""): base = os.path.splitext(sv_file)[0] if not os.path.exists(base + ".ys"): @@ -62,19 +67,23 @@ def unpack_cmd(cmd): def generate_cmd_test(test_name, cmd, yosys_args="", deps = None): generate_target(test_name, unpack_cmd(cmd), deps) -def generate_tests(argv, cmds): +def generate_tests(argv, cmds, yosys_cmds=""): parser = argparse.ArgumentParser(add_help=False) parser.add_argument("-y", "--yosys-scripts", action="store_true") parser.add_argument("-t", "--tcl-scripts", action="store_true") + parser.add_argument("-c", "--check-sv", action="store_true") parser.add_argument("-s", "--prove-sv", action="store_true") parser.add_argument("-b", "--bash", action="store_true") parser.add_argument("-a", "--yosys-args", default="") args = parser.parse_args(argv) - if not (args.yosys_scripts or args.tcl_scripts or args.prove_sv or args.bash): + if not (args.yosys_scripts or args.tcl_scripts or args.check_sv or args.prove_sv or args.bash): raise RuntimeError("No file types selected") + if args.check_sv and args.prove_sv: + raise RuntimeError("Unable to use --check-sv and --prove-sv together") + if args.yosys_scripts: for f in sorted(glob.glob("*.ys")): generate_ys_test(f, args.yosys_args, cmds) @@ -83,6 +92,10 @@ def generate_tests(argv, cmds): for f in sorted(glob.glob("*.tcl")): generate_tcl_test(f, args.yosys_args, cmds) + if args.check_sv: + for f in sorted(glob.glob("*.sv")): + generate_sv_check(f, args.yosys_args, yosys_cmds) + if args.prove_sv: for f in sorted(glob.glob("*.sv")): generate_sv_test(f, args.yosys_args, cmds) @@ -109,11 +122,11 @@ def redirect_stdout(new_target): finally: sys.stdout = old_target -def generate(argv, extra=None, cmds=""): +def generate(argv, extra=None, cmds="", yosys_cmds=""): with open("Makefile", "w") as f: with redirect_stdout(f): print_header(extra) - generate_tests(argv, cmds) + generate_tests(argv, cmds, yosys_cmds) def generate_custom(callback, extra=None): with open("Makefile", "w") as f: From 7cf0c554665f40a8ba717e98ab393b009fe819f1 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:23 +1200 Subject: [PATCH 017/262] verific: Fix non-contiguous memory flattening May not be the best approach, insofar as it uses empty memory elements for padding out the alignment, but it does avoid costly address arithmetic. Still needs to adjust ascii init val addresses, but should work fine for read/write accesses. --- frontends/verific/verific.cc | 81 ++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 6b876c0f1..76a5c13bc 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1630,22 +1630,78 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma import_attributes(memory->attributes, net, nl); int number_of_bits = net->Size(); - int bits_in_word = number_of_bits; + int min_bits_in_word = number_of_bits; + int max_bits_in_addr = 0; + + // get the size of each memory access FOREACH_PORTREF_OF_NET(net, si, pr) { - if (pr->GetInst()->Type() == OPER_READ_PORT) { - bits_in_word = min(bits_in_word, pr->GetInst()->OutputSize()); - continue; + auto *inst = pr->GetInst(); + int bits_in_word; + if (inst->Type() == OPER_READ_PORT) + bits_in_word = inst->OutputSize(); + else if (inst->Type() == OPER_WRITE_PORT || inst->Type() == OPER_CLOCKED_WRITE_PORT) + bits_in_word = inst->Input2Size(); + else + log_error("%sVerific RamNet %s is connected to unsupported instance type %s (%s).\n", announce_src_location(inst), + net->Name(), inst->View()->Owner()->Name(), inst->Name()); + + if (bits_in_word < min_bits_in_word) { + min_bits_in_word = bits_in_word; + max_bits_in_addr = inst->Input1Size(); } - if (pr->GetInst()->Type() == OPER_WRITE_PORT || pr->GetInst()->Type() == OPER_CLOCKED_WRITE_PORT) { - bits_in_word = min(bits_in_word, pr->GetInst()->Input2Size()); - continue; - } - log_error("%sVerific RamNet %s is connected to unsupported instance type %s (%s).\n", announce_src_location(pr->GetInst()), - net->Name(), pr->GetInst()->View()->Owner()->Name(), pr->GetInst()->Name()); } - memory->width = bits_in_word; - memory->size = number_of_bits / bits_in_word; + int number_of_words = number_of_bits / min_bits_in_word; + // TODO Verific has u64 sizes + int size = 1 << max_bits_in_addr; + int min_idx = 0; + int max_idx = size - 1; + + // attempt to infer min/max address for memory definition + RTLIL::SigSpec min_addr, max_addr; + auto typeRange = net->GetOrigTypeRange(); + while (typeRange) { + RTLIL::SigSpec min_addr_chunk(RTLIL::Const(typeRange->RightRangeBound(), typeRange->NumBits())); + min_addr_chunk.reverse(); + min_addr.append(min_addr_chunk); + + RTLIL::SigSpec max_addr_chunk(RTLIL::Const(typeRange->LeftRangeBound(), typeRange->NumBits())); + max_addr_chunk.reverse(); + max_addr.append(max_addr_chunk); + + typeRange = typeRange->GetNext(); + } + min_addr = min_addr.extract(0, max_bits_in_addr); + max_addr = max_addr.extract(0, max_bits_in_addr); + min_addr.reverse(); + max_addr.reverse(); + + if (min_addr.convertible_to_int()) { + min_idx = min_addr.as_int(); + if (max_addr.convertible_to_int()) { + max_idx = max_addr.as_int(); + } else { + log_debug("Unable to set maximum index\n"); + } + size = max_idx - min_idx + 1; + } else { + log_debug("Unable to set minimum index\n"); + } + + // sanity check we haven't shrunk the memory + log_assert(size >= number_of_words); + + memory->width = min_bits_in_word; + memory->size = size; + memory->start_offset = min_idx; + + // warn on oversize memories + // TODO consider using a minimum ratio? + if (size > number_of_words) { + float ratio = size / (float)number_of_words; + log_warning("RAM for identifier '%s' may be up to %.0f%% oversize due to addressing\n", net->Name(), (ratio-1)*100); + log_debug("Expected memory of size %d words, but got %d for address range %d to %d (inclusive)\n", number_of_words, size, min_idx, max_idx); + } const char *ascii_initdata = net->GetWideInitialValue(); if (ascii_initdata) { @@ -1672,6 +1728,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (initval_valid) { RTLIL::Cell *cell = module->addCell(new_verific_id(net), ID($meminit)); cell->parameters[ID::WORDS] = 1; + // TODO non contiguous memory addressing if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound()) cell->setPort(ID::ADDR, word_idx); else From 099c664dc9cb08955dba5ae508bc7801b24e3e54 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:23 +1200 Subject: [PATCH 018/262] verific: Fix upto ranges --- frontends/verific/verific.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 76a5c13bc..74ebcc2be 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1661,11 +1661,13 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma RTLIL::SigSpec min_addr, max_addr; auto typeRange = net->GetOrigTypeRange(); while (typeRange) { - RTLIL::SigSpec min_addr_chunk(RTLIL::Const(typeRange->RightRangeBound(), typeRange->NumBits())); + auto left = typeRange->LeftRangeBound(); + auto right = typeRange->RightRangeBound(); + RTLIL::SigSpec min_addr_chunk(RTLIL::Const(left > right ? right : left, typeRange->NumBits())); min_addr_chunk.reverse(); min_addr.append(min_addr_chunk); - RTLIL::SigSpec max_addr_chunk(RTLIL::Const(typeRange->LeftRangeBound(), typeRange->NumBits())); + RTLIL::SigSpec max_addr_chunk(RTLIL::Const(left > right ? left : right, typeRange->NumBits())); max_addr_chunk.reverse(); max_addr.append(max_addr_chunk); From f6327cc4447187f19658e01833eb2d6ec26f553c Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:24 +1200 Subject: [PATCH 019/262] check_mem: Add -non-const option Can identify potentially dangerous addressing, but also prone to false-positives. --- passes/cmds/check.cc | 20 ++++++++++-- tests/check_mem/variable.ys | 65 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 tests/check_mem/variable.ys diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index 9a0070996..426216800 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -468,6 +468,7 @@ struct CheckMemPass : public Pass { "addressing invalid memory." ); + content_root->option("-non-const", "also check non-const address signals (may produce false-positives)"); content_root->option("-assert", "produce a runtime error if any problems are found in the current design"); return true; @@ -476,12 +477,17 @@ struct CheckMemPass : public Pass { { int counter = 0; bool assert_mode = false; + bool nonconst_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-assert") { assert_mode = true; continue; } + if (args[argidx] == "-non-const") { + nonconst_mode = true; + continue; + } break; } @@ -506,19 +512,27 @@ struct CheckMemPass : public Pass { } } - auto check_addr = [min_addr, max_addr, &counter, module, &mem](SigSpec &addr_sig, const char* access) { + auto check_addr = [min_addr, max_addr, &counter, module, &mem, &nonconst_mode](SigSpec &addr_sig, const char* access) { if (addr_sig.is_fully_const()) { auto addr = addr_sig.as_int(); if (addr < min_addr || addr > max_addr) { log_warning("Mem %s.%s contains entries for addresses %d..%d but %s address %d.\n", log_id(module), log_id(mem.mem), min_addr, max_addr, access, addr); counter++; } - } else { - // TODO test variable addresses? may need sat solver + } else if (nonconst_mode) { + // TODO check addr_sig.has_const() for constant MSb/LSb that may change effective min/max + // TODO consider sat solver for variable addresses + int addr_sig_min = 0; + int addr_sig_max = (1 << addr_sig.size()) - 1; + if (min_addr > addr_sig_min || max_addr < addr_sig_max) { + log_warning("Mem %s.%s contains entries for addresses %d..%d but has a potentially dangerous non-const input %s\n", log_id(module), log_id(mem.mem), min_addr, max_addr, log_signal(addr_sig)); + counter++; + } } }; // TODO test ABITS and WIDTH? + // TODO can we limit ports via selection? for (auto &rd_port : mem.rd_ports) check_addr(rd_port.addr, "reads"); for (auto &wr_port : mem.wr_ports) diff --git a/tests/check_mem/variable.ys b/tests/check_mem/variable.ys new file mode 100644 index 000000000..8da49758b --- /dev/null +++ b/tests/check_mem/variable.ys @@ -0,0 +1,65 @@ + + +read_rtlil << EOF +module \top + wire input 1 \clk + wire input 2 width 2 \addr + wire output 1 \o + memory size 3 offset 0 \my_array + # potentially dangerous - requires external control to avoid illegal access + cell $memrd \bad_rd + parameter \MEMID "\\my_array" + parameter \CLK_ENABLE 0 + parameter \CLK_POLARITY 1 + parameter \TRANSPARENT 0 + parameter \ABITS 2 + parameter \WIDTH 1 + connect \CLK 1'x + connect \EN 1'x + connect \ADDR \addr + connect \DATA \o + end + wire width 2 \n_addr + cell $not \not_addr + parameter \A_SIGNED 0 + parameter \A_WIDTH 2 + parameter \Y_WIDTH 2 + connect \A \addr + connect \Y \n_addr + end + # address is partially const, making the illegal access of 2'11 impossible + cell $memrd \partial_const_rd + parameter \MEMID "\\my_array" + parameter \CLK_ENABLE 0 + parameter \CLK_POLARITY 1 + parameter \TRANSPARENT 0 + parameter \ABITS 2 + parameter \WIDTH 1 + connect \CLK 1'x + connect \EN 1'x + connect \ADDR { 1'0 \addr [0] } + connect \DATA \o + end + # address is non-const but limited to 2'10 and 2'01 - both of which are valid + cell $memrd \limited_rd + parameter \MEMID "\\my_array" + parameter \CLK_ENABLE 0 + parameter \CLK_POLARITY 1 + parameter \TRANSPARENT 0 + parameter \ABITS 2 + parameter \WIDTH 1 + connect \CLK 1'x + connect \EN 1'x + connect \ADDR { \n_addr [0] \addr [0] } + connect \DATA \o + end +end +EOF + +logger -expect warning "potentially dangerous non-const input \\addr" 1 +# unhandled false-positives +# logger -werror "potentially dangerous non-const input \{ 1'0" +# logger -werror "potentially dangerous non-const input \{ \\n_addr" +check_mem -non-const +logger -check-expected +design -reset From aac7366862af73a4b51b452f44fb1339f828d607 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:24 +1200 Subject: [PATCH 020/262] tests: Add check_mem to vanilla-test --- tests/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile b/tests/Makefile index 05e5410b7..6c2689c79 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -78,6 +78,7 @@ MK_TEST_DIRS += ./liberty MK_TEST_DIRS += ./memories MK_TEST_DIRS += ./aiger MK_TEST_DIRS += ./alumacc +MK_TEST_DIRS += ./check_mem all: vanilla-test From ab5f25db9a0c498342caac1d19afce83bbd7e1cd Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:24 +1200 Subject: [PATCH 021/262] Add test for non-contiguous memory init Also negative memory addresses. --- tests/check_mem/init_correct.ys | 44 +++++++++++++++++++++++++++++++++ tests/check_mem/negative_idx.sv | 13 ++++++++++ 2 files changed, 57 insertions(+) create mode 100644 tests/check_mem/init_correct.ys create mode 100644 tests/check_mem/negative_idx.sv diff --git a/tests/check_mem/init_correct.ys b/tests/check_mem/init_correct.ys new file mode 100644 index 000000000..5e922c7df --- /dev/null +++ b/tests/check_mem/init_correct.ys @@ -0,0 +1,44 @@ +read -sv << EOT +module top; + (* nomem2reg *) + logic a1 [2:3][3:1] = '{'{0, 1, 1}, '{1, 0, 1}}; + + always_comb begin + assert(a1[2][3] == 0); + assert(a1[2][2] == 1); + assert(a1[2][1] == 1); + assert(a1[3][3] == 1); + assert(a1[3][2] == 0); + assert(a1[3][1] == 1); + end + + (* nomem2reg *) + logic [1:0] a2 [6:5][2:4] = '{'{0, 1, 2}, '{1, 0, 3}}; + + always_comb begin + assert(a2[6][2] == 0); + assert(a2[6][3] == 1); + assert(a2[6][4] == 2); + assert(a2[5][2] == 1); + assert(a2[5][3] == 0); + assert(a2[5][4] == 3); + end + + (* nomem2reg *) + logic [1:0] a3 [-2:-1][-1:1] = '{'{0, 1, 2}, '{1, 0, 3}}; + + always_comb begin + assert(a3[-2][-1] == 0); + assert(a3[-2][0] == 1); + assert(a3[-2][1] == 2); + assert(a3[-1][-1] == 1); + assert(a3[-1][0] == 0); + assert(a3[-1][1] == 3); + end +endmodule +EOT +hierarchy +proc +memory +async2sync +sat -enable_undef -verify -prove-asserts diff --git a/tests/check_mem/negative_idx.sv b/tests/check_mem/negative_idx.sv new file mode 100644 index 000000000..dcfad94a3 --- /dev/null +++ b/tests/check_mem/negative_idx.sv @@ -0,0 +1,13 @@ +module top; + (* nomem2reg *) + logic [1:0] a3 [-2:-1][-1:1] = '{'{0, 1, 2}, '{1, 0, 3}}; + + always_comb begin + assert(a3[-2][-1] == 0); + assert(a3[-2][0] == 1); + assert(a3[-2][1] == 2); + assert(a3[-1][-1] == 1); + assert(a3[-1][0] == 0); + assert(a3[-1][1] == 3); + end +endmodule \ No newline at end of file From 21966ef496fc11ffc6a9e5076a095f5d30e7ce92 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:25 +1200 Subject: [PATCH 022/262] verific: Fix non-contiguous memory init Recurse over nested type ranges to calculate true addresses. --- frontends/verific/verific.cc | 66 +++++++++++++++++++++--------------- frontends/verific/verific.h | 3 ++ 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 74ebcc2be..24c91c3c4 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1444,6 +1444,44 @@ static std::string sha1_if_contain_spaces(std::string str) return str; } +void VerificImporter::recurse_ascii_initdata(RTLIL::Module *module, RTLIL::Memory *memory, Net *net, const char *&ascii_initdata, TypeRange *typeRange, int base_idx) { + if (typeRange == nullptr) + typeRange = net->GetOrigTypeRange(); + + auto *nextRange = typeRange->GetNext(); + base_idx <<= typeRange->NumBits(); + auto left = typeRange->LeftRangeBound(); + auto right = typeRange->RightRangeBound(); + for (auto i = left; left < right ? i <= right : i >= right; left < right ? i++ : i--) { + auto next_idx = base_idx + i; + if (nextRange != nullptr) { + recurse_ascii_initdata(module, memory, net, ascii_initdata, nextRange, next_idx); + } else { + Const initval = Const(State::Sx, memory->width); + bool initval_valid = false; + for (int bit_idx = memory->width-1; bit_idx >= 0; bit_idx--) { + if (*ascii_initdata == 0) + break; + if (*ascii_initdata == '0' || *ascii_initdata == '1') { + initval.set(bit_idx, (*ascii_initdata == '0') ? State::S0 : State::S1); + initval_valid = true; + } + ascii_initdata++; + } + if (initval_valid) { + RTLIL::Cell *cell = module->addCell(new_verific_id(net), ID($meminit)); + cell->parameters[ID::WORDS] = 1; + cell->setPort(ID::ADDR, next_idx); + cell->setPort(ID::DATA, initval); + cell->parameters[ID::MEMID] = RTLIL::Const(memory->name.str()); + cell->parameters[ID::ABITS] = 32; + cell->parameters[ID::WIDTH] = memory->width; + cell->parameters[ID::PRIORITY] = RTLIL::Const(autoidx-1); + } + } + } +} + void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::map &nl_todo, bool norename) { std::string netlist_name = nl->GetAtt(" \\top") || is_blackbox(nl) ? nl->CellBaseName() : nl->Owner()->Name(); @@ -1715,33 +1753,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log_assert(*ascii_initdata == 'b'); ascii_initdata++; } - for (int word_idx = 0; word_idx < memory->size; word_idx++) { - Const initval = Const(State::Sx, memory->width); - bool initval_valid = false; - for (int bit_idx = memory->width-1; bit_idx >= 0; bit_idx--) { - if (*ascii_initdata == 0) - break; - if (*ascii_initdata == '0' || *ascii_initdata == '1') { - initval.set(bit_idx, (*ascii_initdata == '0') ? State::S0 : State::S1); - initval_valid = true; - } - ascii_initdata++; - } - if (initval_valid) { - RTLIL::Cell *cell = module->addCell(new_verific_id(net), ID($meminit)); - cell->parameters[ID::WORDS] = 1; - // TODO non contiguous memory addressing - if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound()) - cell->setPort(ID::ADDR, word_idx); - else - cell->setPort(ID::ADDR, memory->size - word_idx - 1); - cell->setPort(ID::DATA, initval); - cell->parameters[ID::MEMID] = RTLIL::Const(memory->name.str()); - cell->parameters[ID::ABITS] = 32; - cell->parameters[ID::WIDTH] = memory->width; - cell->parameters[ID::PRIORITY] = RTLIL::Const(autoidx-1); - } - } + recurse_ascii_initdata(module, memory, net, ascii_initdata); } continue; } diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index f33a380f7..478ab82cb 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -66,6 +66,9 @@ struct VerificClocking { struct VerificImporter { +private: + void recurse_ascii_initdata(RTLIL::Module *module, RTLIL::Memory *memory, Verific::Net *net, const char *&ascii_initdata, Verific::TypeRange *typeRange = nullptr, int base_idx = 0); +public: RTLIL::Module *module; Verific::Netlist *netlist; From 52e0030cc52a3af6a65de62c54b47f3476244f64 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:25 +1200 Subject: [PATCH 023/262] tests/check_mem: Add problematic case Verific reports it as 16 2-bit addresses, meaning we have to iterate over the last dimension while skipping indices. --- tests/check_mem/negative_idx.sv | 2 +- tests/check_mem/sub_addr.sv | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/check_mem/sub_addr.sv diff --git a/tests/check_mem/negative_idx.sv b/tests/check_mem/negative_idx.sv index dcfad94a3..99a26cdae 100644 --- a/tests/check_mem/negative_idx.sv +++ b/tests/check_mem/negative_idx.sv @@ -10,4 +10,4 @@ module top; assert(a3[-1][0] == 0); assert(a3[-1][1] == 3); end -endmodule \ No newline at end of file +endmodule diff --git a/tests/check_mem/sub_addr.sv b/tests/check_mem/sub_addr.sv new file mode 100644 index 000000000..cc4cb3ba3 --- /dev/null +++ b/tests/check_mem/sub_addr.sv @@ -0,0 +1,32 @@ +module memtest05(clk, addr, wdata, rdata, wen); + +input clk; +input [1:0] addr; +input [7:0] wdata; +output reg [7:0] rdata; +input [3:0] wen; + +reg [7:0] mem [0:3] = {8'h01, 8'h23, 8'h45, 8'h67}; + +integer i; +always @(posedge clk) begin + for (i = 0; i < 4; i = i+1) + if (wen[i]) mem[addr][i*2 +: 2] <= wdata[i*2 +: 2]; + rdata <= mem[addr]; +end + +always @(posedge clk) begin + // not sure how to verify this one without SBY + // or alternatively, how to replicate the problematic sub addressing without the read&write + assume (wen == 0); + assert (mem[0][7:4] == 4'h0); + assert (mem[0][3:0] == 4'h1); + assert (mem[1][7:4] == 4'h2); + assert (mem[1][3:0] == 4'h3); + assert (mem[2][7:4] == 4'h4); + assert (mem[2][3:0] == 4'h5); + assert (mem[3][7:4] == 4'h6); + assert (mem[3][3:0] == 4'h7); +end + +endmodule From 5f53410db71d76f55af5f98cf998ffa4e567169e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 29 May 2026 18:40:25 +1200 Subject: [PATCH 024/262] verific: Fix negative array dimensions Recurse over memory dimensions once, doing both our min/max address checking and parsing out the initval. This also avoids problems with negative numbers (if `a < b` and one or both are negative, `a` might be the intended `max_addr_chunk`). Fix sub addressing, where we use some but not all of the current dimension's bits. --- frontends/verific/verific.cc | 119 ++++++++++++++++------------------- frontends/verific/verific.h | 2 +- 2 files changed, 56 insertions(+), 65 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 24c91c3c4..4d1bd0e48 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1444,30 +1444,48 @@ static std::string sha1_if_contain_spaces(std::string str) return str; } -void VerificImporter::recurse_ascii_initdata(RTLIL::Module *module, RTLIL::Memory *memory, Net *net, const char *&ascii_initdata, TypeRange *typeRange, int base_idx) { +void VerificImporter::recurse_mem_dimensions(RTLIL::Module *module, RTLIL::Memory *memory, Net *net, const char *&ascii_initdata, int max_bits_in_addr, const RTLIL::SigSpec &prefix, TypeRange *typeRange) { if (typeRange == nullptr) typeRange = net->GetOrigTypeRange(); auto *nextRange = typeRange->GetNext(); - base_idx <<= typeRange->NumBits(); auto left = typeRange->LeftRangeBound(); auto right = typeRange->RightRangeBound(); - for (auto i = left; left < right ? i <= right : i >= right; left < right ? i++ : i--) { - auto next_idx = base_idx + i; - if (nextRange != nullptr) { - recurse_ascii_initdata(module, memory, net, ascii_initdata, nextRange, next_idx); + bool is_up = left < right; + for (auto i = left; is_up ? i <= right : i >= right; is_up ? i++ : i--) { + // TODO verific can do u64 + auto max_bits = max_bits_in_addr - prefix.size(); + auto next_sig = SigSpec(Const(i, typeRange->NumBits())); + auto extra_bits = next_sig.size() - max_bits; + if (extra_bits > 0) { + next_sig = next_sig.extract_end(extra_bits); + auto extra_inc = (1 << extra_bits) - 1; + i = is_up ? i + extra_inc : i - extra_inc; + } + next_sig.append(prefix); + if (nextRange != nullptr && extra_bits < 0) { + recurse_mem_dimensions(module, memory, net, ascii_initdata, max_bits_in_addr, next_sig, nextRange); } else { + if (next_sig.size() != max_bits_in_addr) { + // TODO verific can do u64 + log_error("Expected %d bits for addr but got %d!\n", max_bits_in_addr, next_sig.size()); + } Const initval = Const(State::Sx, memory->width); bool initval_valid = false; - for (int bit_idx = memory->width-1; bit_idx >= 0; bit_idx--) { - if (*ascii_initdata == 0) - break; - if (*ascii_initdata == '0' || *ascii_initdata == '1') { - initval.set(bit_idx, (*ascii_initdata == '0') ? State::S0 : State::S1); - initval_valid = true; + if (ascii_initdata) { + for (int bit_idx = memory->width-1; bit_idx >= 0; bit_idx--) { + if (*ascii_initdata == 0) + break; + if (*ascii_initdata == '0' || *ascii_initdata == '1') { + initval.set(bit_idx, (*ascii_initdata == '0') ? State::S0 : State::S1); + initval_valid = true; + } + ascii_initdata++; } - ascii_initdata++; } + if (!next_sig.convertible_to_int()) + log_error("Address %s on RAM for identifier '%s' too wide!\n", log_signal(next_sig), net->Name()); + auto next_idx = next_sig.as_int(); if (initval_valid) { RTLIL::Cell *cell = module->addCell(new_verific_id(net), ID($meminit)); cell->parameters[ID::WORDS] = 1; @@ -1478,6 +1496,8 @@ void VerificImporter::recurse_ascii_initdata(RTLIL::Module *module, RTLIL::Memor cell->parameters[ID::WIDTH] = memory->width; cell->parameters[ID::PRIORITY] = RTLIL::Const(autoidx-1); } + memory->start_offset = min(memory->start_offset, next_idx); + memory->size = max(memory->size, next_idx); } } } @@ -1690,58 +1710,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma } int number_of_words = number_of_bits / min_bits_in_word; - // TODO Verific has u64 sizes - int size = 1 << max_bits_in_addr; - int min_idx = 0; - int max_idx = size - 1; - - // attempt to infer min/max address for memory definition - RTLIL::SigSpec min_addr, max_addr; - auto typeRange = net->GetOrigTypeRange(); - while (typeRange) { - auto left = typeRange->LeftRangeBound(); - auto right = typeRange->RightRangeBound(); - RTLIL::SigSpec min_addr_chunk(RTLIL::Const(left > right ? right : left, typeRange->NumBits())); - min_addr_chunk.reverse(); - min_addr.append(min_addr_chunk); - - RTLIL::SigSpec max_addr_chunk(RTLIL::Const(left > right ? left : right, typeRange->NumBits())); - max_addr_chunk.reverse(); - max_addr.append(max_addr_chunk); - - typeRange = typeRange->GetNext(); - } - min_addr = min_addr.extract(0, max_bits_in_addr); - max_addr = max_addr.extract(0, max_bits_in_addr); - min_addr.reverse(); - max_addr.reverse(); - - if (min_addr.convertible_to_int()) { - min_idx = min_addr.as_int(); - if (max_addr.convertible_to_int()) { - max_idx = max_addr.as_int(); - } else { - log_debug("Unable to set maximum index\n"); - } - size = max_idx - min_idx + 1; - } else { - log_debug("Unable to set minimum index\n"); - } - - // sanity check we haven't shrunk the memory - log_assert(size >= number_of_words); memory->width = min_bits_in_word; - memory->size = size; - memory->start_offset = min_idx; - - // warn on oversize memories - // TODO consider using a minimum ratio? - if (size > number_of_words) { - float ratio = size / (float)number_of_words; - log_warning("RAM for identifier '%s' may be up to %.0f%% oversize due to addressing\n", net->Name(), (ratio-1)*100); - log_debug("Expected memory of size %d words, but got %d for address range %d to %d (inclusive)\n", number_of_words, size, min_idx, max_idx); - } + memory->size = 0; + memory->start_offset = INT_MAX; const char *ascii_initdata = net->GetWideInitialValue(); if (ascii_initdata) { @@ -1753,7 +1725,26 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log_assert(*ascii_initdata == 'b'); ascii_initdata++; } - recurse_ascii_initdata(module, memory, net, ascii_initdata); + } + + // process initdata and fixup min/max address + auto prefix = SigSpec(); + recurse_mem_dimensions(module, memory, net, ascii_initdata, max_bits_in_addr, prefix); + + auto min_idx = memory->start_offset; + auto max_idx = memory->size; + memory->size = max_idx - min_idx + 1; + + // sanity check we haven't shrunk the memory + if (memory->size < number_of_words) + log_error("Expected memory of size %d words, but got %d for address range %d to %d (inclusive)\n", number_of_words, memory->size, min_idx, max_idx); + + // warn on oversize memories + // TODO consider using a minimum ratio? + if (memory->size > number_of_words) { + float ratio = memory->size / (float)number_of_words; + log_warning("RAM for identifier '%s' may be up to %.0f%% oversize due to addressing\n", net->Name(), (ratio-1)*100); + log_debug("Expected memory of size %d words, but got %d for address range %d to %d (inclusive)\n", number_of_words, memory->size, min_idx, max_idx); } continue; } diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index 478ab82cb..0bd4d800a 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -67,7 +67,7 @@ struct VerificClocking { struct VerificImporter { private: - void recurse_ascii_initdata(RTLIL::Module *module, RTLIL::Memory *memory, Verific::Net *net, const char *&ascii_initdata, Verific::TypeRange *typeRange = nullptr, int base_idx = 0); + void recurse_mem_dimensions(RTLIL::Module *module, RTLIL::Memory *memory, Verific::Net *net, const char *&ascii_initdata, int max_bits_in_addr, const RTLIL::SigSpec &prefix, Verific::TypeRange *typeRange = nullptr); public: RTLIL::Module *module; Verific::Netlist *netlist; From a14650d07b8415db6eb98d11c19dfff1825aec03 Mon Sep 17 00:00:00 2001 From: Mike Inouye Date: Fri, 29 May 2026 17:53:31 +0000 Subject: [PATCH 025/262] verilog backend: runtime optimization for keyword pool Signed-off-by: Mike Inouye --- backends/verilog/verilog_backend.cc | 2 +- backends/verilog/verilog_backend.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 473918264..fd9986144 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -38,7 +38,7 @@ USING_YOSYS_NAMESPACE using namespace VERILOG_BACKEND; -const pool VERILOG_BACKEND::verilog_keywords() { +const pool &VERILOG_BACKEND::verilog_keywords() { static const pool res = { // IEEE 1800-2017 Annex B "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before", diff --git a/backends/verilog/verilog_backend.h b/backends/verilog/verilog_backend.h index 7e550a37c..affad995b 100644 --- a/backends/verilog/verilog_backend.h +++ b/backends/verilog/verilog_backend.h @@ -29,7 +29,7 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_BACKEND { - const pool verilog_keywords(); + const pool &verilog_keywords(); bool char_is_verilog_escaped(char c); bool id_is_verilog_escaped(const std::string &str); From 0360a4bd0af91ba8b019dbf77d2dd9b8a0f7b095 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 30 May 2026 11:06:11 +1200 Subject: [PATCH 026/262] tests/check_mem: Drop unused init check It was also raising an error in `read_verilog`. --- tests/check_mem/sub_addr.sv | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/check_mem/sub_addr.sv b/tests/check_mem/sub_addr.sv index cc4cb3ba3..025bdc881 100644 --- a/tests/check_mem/sub_addr.sv +++ b/tests/check_mem/sub_addr.sv @@ -6,7 +6,7 @@ input [7:0] wdata; output reg [7:0] rdata; input [3:0] wen; -reg [7:0] mem [0:3] = {8'h01, 8'h23, 8'h45, 8'h67}; +reg [7:0] mem [0:3]; integer i; always @(posedge clk) begin @@ -15,18 +15,4 @@ always @(posedge clk) begin rdata <= mem[addr]; end -always @(posedge clk) begin - // not sure how to verify this one without SBY - // or alternatively, how to replicate the problematic sub addressing without the read&write - assume (wen == 0); - assert (mem[0][7:4] == 4'h0); - assert (mem[0][3:0] == 4'h1); - assert (mem[1][7:4] == 4'h2); - assert (mem[1][3:0] == 4'h3); - assert (mem[2][7:4] == 4'h4); - assert (mem[2][3:0] == 4'h5); - assert (mem[3][7:4] == 4'h6); - assert (mem[3][3:0] == 4'h7); -end - endmodule From bcc736ed7d44d0d1a9e0dc1d0a02cea75f432bb6 Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 28 May 2026 13:44:43 +0000 Subject: [PATCH 027/262] Revert "Putting back some Makefile.conf" This reverts commit d8587f44f0566b5d442216ed12860f03cd7a49e2. --- tests/common.mk | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/common.mk b/tests/common.mk index 0e85e9fb9..ef6982514 100644 --- a/tests/common.mk +++ b/tests/common.mk @@ -1,16 +1,9 @@ ROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) BUILD_DIR ?= $(ROOT_DIR)/.. -ifneq ($(wildcard $(ROOT_DIR)/../Makefile.conf),) -include $(ROOT_DIR)/../Makefile.conf -endif SBY ?= sby YOSYS ?= $(BUILD_DIR)/yosys -ifneq ($(ABCEXTERNAL),) -ABC ?= $(ABCEXTERNAL) -else ABC ?= $(BUILD_DIR)/yosys-abc -endif YOSYS_FILTERLIB ?= $(BUILD_DIR)/yosys-filterlib YOSYS_CONFIG ?= $(BUILD_DIR)/yosys-config YOSYS_SMTBMC ?= $(BUILD_DIR)/yosys-smtbmc From a727e7f6e73c610624c694fcf4b756af416140c5 Mon Sep 17 00:00:00 2001 From: Catherine Date: Tue, 12 May 2026 05:33:04 +0000 Subject: [PATCH 028/262] Migrate build system to CMake See #5895 for details. This commit does not include CI or documentation changes. --- .gitignore | 4 + CMakeLists.txt | 523 +++++++ Makefile | 1219 ----------------- backends/CMakeLists.txt | 18 + backends/aiger/CMakeLists.txt | 8 + backends/aiger/Makefile.inc | 4 - backends/aiger2/CMakeLists.txt | 5 + backends/aiger2/Makefile.inc | 1 - backends/blif/CMakeLists.txt | 3 + backends/blif/Makefile.inc | 3 - backends/btor/CMakeLists.txt | 7 + backends/btor/Makefile.inc | 3 - backends/cxxrtl/CMakeLists.txt | 19 + backends/cxxrtl/Makefile.inc | 11 - backends/edif/CMakeLists.txt | 3 + backends/edif/Makefile.inc | 3 - backends/firrtl/CMakeLists.txt | 8 + backends/firrtl/Makefile.inc | 3 - backends/functional/CMakeLists.txt | 12 + backends/functional/Makefile.inc | 4 - backends/intersynth/CMakeLists.txt | 3 + backends/intersynth/Makefile.inc | 3 - backends/jny/CMakeLists.txt | 5 + backends/jny/Makefile.inc | 2 - backends/json/CMakeLists.txt | 5 + backends/json/Makefile.inc | 3 - backends/rtlil/CMakeLists.txt | 11 + backends/rtlil/Makefile.inc | 3 - backends/simplec/CMakeLists.txt | 3 + backends/simplec/Makefile.inc | 3 - backends/smt2/CMakeLists.txt | 20 + backends/smt2/Makefile.inc | 46 - backends/smt2/smtbmc.py | 4 +- backends/smt2/witness.py | 4 +- backends/smv/CMakeLists.txt | 7 + backends/smv/Makefile.inc | 3 - backends/spice/CMakeLists.txt | 3 + backends/spice/Makefile.inc | 3 - backends/table/CMakeLists.txt | 3 + backends/table/Makefile.inc | 3 - backends/verilog/CMakeLists.txt | 8 + backends/verilog/Makefile.inc | 3 - cmake/CheckLibcFeatures.cmake | 40 + cmake/Condition.cmake | 35 + cmake/FindDlfcn.cmake | 24 + cmake/FindPyosysEnv.cmake | 42 + cmake/FindPython3Embed.cmake | 16 + cmake/PkgConfig.cmake | 43 + cmake/PmgenCommand.cmake | 60 + cmake/YosysAbc.cmake | 96 ++ cmake/YosysAbcSubmodule.cmake | 64 + cmake/YosysComponent.cmake | 321 +++++ cmake/YosysConfigScript.cmake | 66 + cmake/YosysInstallDirs.cmake | 9 + cmake/YosysLinkTarget.cmake | 101 ++ cmake/YosysVerific.cmake | 48 + cmake/YosysVersion.cmake | 162 +++ cmake/YosysVersionData.cmake | 2 + cmake/toolchain/toolchain-mingw-i686.cmake | 8 + cmake/toolchain/toolchain-mingw-x86_64.cmake | 8 + docs/Makefile | 27 + docs/source/code_examples/extensions/Makefile | 5 +- docs/source/code_examples/stubnets/Makefile | 12 +- examples/cxx-api/demomain.cc | 4 +- flake.lock | 14 +- flake.nix | 94 +- frontends/CMakeLists.txt | 10 + frontends/aiger/CMakeLists.txt | 6 + frontends/aiger/Makefile.inc | 3 - frontends/aiger2/CMakeLists.txt | 3 + frontends/aiger2/Makefile.inc | 2 - frontends/ast/CMakeLists.txt | 13 + frontends/ast/Makefile.inc | 7 - frontends/ast/dpicall.cc | 6 +- frontends/blif/CMakeLists.txt | 8 + frontends/blif/Makefile.inc | 3 - frontends/json/CMakeLists.txt | 3 + frontends/json/Makefile.inc | 3 - frontends/liberty/CMakeLists.txt | 5 + frontends/liberty/Makefile.inc | 3 - frontends/rpc/CMakeLists.txt | 8 + frontends/rpc/Makefile.inc | 3 - frontends/rtlil/CMakeLists.txt | 3 + frontends/rtlil/Makefile.inc | 1 - frontends/verific/CMakeLists.txt | 70 + frontends/verific/Makefile.inc | 23 - frontends/verilog/CMakeLists.txt | 43 + frontends/verilog/Makefile.inc | 29 - kernel/CMakeLists.txt | 187 +++ {techlibs/common => kernel}/cellhelp.py | 0 kernel/fstdata.cc | 14 +- kernel/log.cc | 4 +- kernel/register.cc | 8 +- kernel/threading.h | 8 +- kernel/version.cc.in | 4 + kernel/yosys.cc | 12 +- kernel/yosys_common.h | 4 + kernel/yosys_config.h.in | 22 + libs/CMakeLists.txt | 9 + libs/bigint/CMakeLists.txt | 14 + libs/dlfcn-win32/CMakeLists.txt | 9 + libs/ezsat/CMakeLists.txt | 16 + libs/ezsat/ezcmdline.cc | 2 +- libs/flex/FlexLexer.h | 220 +++ libs/flex/README.txt | 2 + libs/fst/CMakeLists.txt | 18 + libs/json11/CMakeLists.txt | 8 + libs/minisat/CMakeLists.txt | 24 + libs/sha1/CMakeLists.txt | 8 + libs/subcircuit/CMakeLists.txt | 4 + misc/cmake/check_missing_depends.sh | 9 + misc/cmake/script_pass_depends.py | 29 + nix/cross/tcl.nix | 66 + nix/cross/win-overlay.nix | 51 + nix/cross/win32.nix | 15 + nix/cross/win64.nix | 15 + nix/pkgs/yosys.nix | 53 + passes/CMakeLists.txt | 11 + passes/cmds/CMakeLists.txt | 213 +++ passes/cmds/Makefile.inc | 64 - passes/cmds/sdc/CMakeLists.txt | 9 + passes/cmds/sdc/Makefile.inc | 3 - passes/cmds/sdc/sdc.cc | 1 + passes/cmds/show.cc | 8 +- passes/cmds/viz.cc | 6 +- passes/equiv/CMakeLists.txt | 54 + passes/equiv/Makefile.inc | 12 - passes/fsm/CMakeLists.txt | 52 + passes/fsm/Makefile.inc | 11 - passes/hierarchy/CMakeLists.txt | 22 + passes/hierarchy/Makefile.inc | 7 - passes/memory/CMakeLists.txt | 59 + passes/memory/Makefile.inc | 15 - passes/opt/.gitignore | 1 - passes/opt/CMakeLists.txt | 97 ++ passes/opt/Makefile.inc | 44 - passes/opt/opt_clean/CMakeLists.txt | 11 + passes/opt/opt_clean/Makefile.inc | 10 - passes/pmgen/.gitignore | 1 - passes/pmgen/CMakeLists.txt | 15 + passes/pmgen/Makefile.inc | 10 - passes/proc/CMakeLists.txt | 47 + passes/proc/Makefile.inc | 12 - passes/sat/CMakeLists.txt | 74 + passes/sat/Makefile.inc | 23 - passes/techmap/CMakeLists.txt | 225 +++ passes/techmap/Makefile.inc | 68 - passes/techmap/abc.cc | 2 +- passes/tests/CMakeLists.txt | 13 + passes/tests/Makefile.inc | 6 - pyosys/.gitignore | 2 - pyosys/CMakeLists.txt | 29 + pyosys/generator.py | 41 +- pyosys/{__init__.py => modinit.py} | 0 pyosys/wrappers_tpl.cc | 4 - techlibs/.gitignore | 2 - techlibs/CMakeLists.txt | 20 + techlibs/achronix/CMakeLists.txt | 28 + techlibs/achronix/Makefile.inc | 6 - techlibs/analogdevices/CMakeLists.txt | 65 + techlibs/analogdevices/Makefile.inc | 21 - techlibs/anlogic/CMakeLists.txt | 45 + techlibs/anlogic/Makefile.inc | 13 - techlibs/common/.gitignore | 2 - techlibs/common/CMakeLists.txt | 87 ++ techlibs/common/Makefile.inc | 41 - techlibs/common/opensta.cc | 2 +- techlibs/coolrunner2/CMakeLists.txt | 42 + techlibs/coolrunner2/Makefile.inc | 10 - techlibs/easic/CMakeLists.txt | 19 + techlibs/easic/Makefile.inc | 3 - techlibs/efinix/CMakeLists.txt | 40 + techlibs/efinix/Makefile.inc | 10 - techlibs/fabulous/CMakeLists.txt | 41 + techlibs/fabulous/Makefile.inc | 11 - techlibs/gatemate/.gitignore | 2 - techlibs/gatemate/CMakeLists.txt | 65 + techlibs/gatemate/Makefile.inc | 34 - techlibs/gatemate/make_lut_tree_lib.py | 4 +- techlibs/gowin/CMakeLists.txt | 55 + techlibs/gowin/Makefile.inc | 16 - techlibs/greenpak4/CMakeLists.txt | 42 + techlibs/greenpak4/Makefile.inc | 12 - techlibs/ice40/CMakeLists.txt | 84 ++ techlibs/ice40/Makefile.inc | 26 - techlibs/intel/CMakeLists.txt | 52 + techlibs/intel/Makefile.inc | 14 - techlibs/intel_alm/CMakeLists.txt | 57 + techlibs/intel_alm/Makefile.inc | 26 - techlibs/lattice/CMakeLists.txt | 101 ++ techlibs/lattice/Makefile.inc | 60 - techlibs/microchip/CMakeLists.txt | 76 + techlibs/microchip/Makefile.inc | 40 - techlibs/nanoxplore/CMakeLists.txt | 68 + techlibs/nanoxplore/Makefile.inc | 31 - techlibs/quicklogic/.gitignore | 1 - techlibs/quicklogic/CMakeLists.txt | 104 ++ techlibs/quicklogic/Makefile.inc | 44 - techlibs/sf2/CMakeLists.txt | 34 + techlibs/sf2/Makefile.inc | 7 - techlibs/xilinx/CMakeLists.txt | 125 ++ techlibs/xilinx/Makefile.inc | 64 - tests/unit/CMakeLists.txt | 29 + tests/unit/kernel/CMakeLists.txt | 14 + tests/unit/opt/CMakeLists.txt | 5 + tests/unit/techmap/CMakeLists.txt | 5 + 206 files changed, 5184 insertions(+), 2303 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 Makefile create mode 100644 backends/CMakeLists.txt create mode 100644 backends/aiger/CMakeLists.txt delete mode 100644 backends/aiger/Makefile.inc create mode 100644 backends/aiger2/CMakeLists.txt delete mode 100644 backends/aiger2/Makefile.inc create mode 100644 backends/blif/CMakeLists.txt delete mode 100644 backends/blif/Makefile.inc create mode 100644 backends/btor/CMakeLists.txt delete mode 100644 backends/btor/Makefile.inc create mode 100644 backends/cxxrtl/CMakeLists.txt delete mode 100644 backends/cxxrtl/Makefile.inc create mode 100644 backends/edif/CMakeLists.txt delete mode 100644 backends/edif/Makefile.inc create mode 100644 backends/firrtl/CMakeLists.txt delete mode 100644 backends/firrtl/Makefile.inc create mode 100644 backends/functional/CMakeLists.txt delete mode 100644 backends/functional/Makefile.inc create mode 100644 backends/intersynth/CMakeLists.txt delete mode 100644 backends/intersynth/Makefile.inc create mode 100644 backends/jny/CMakeLists.txt delete mode 100644 backends/jny/Makefile.inc create mode 100644 backends/json/CMakeLists.txt delete mode 100644 backends/json/Makefile.inc create mode 100644 backends/rtlil/CMakeLists.txt delete mode 100644 backends/rtlil/Makefile.inc create mode 100644 backends/simplec/CMakeLists.txt delete mode 100644 backends/simplec/Makefile.inc create mode 100644 backends/smt2/CMakeLists.txt delete mode 100644 backends/smt2/Makefile.inc mode change 100644 => 100755 backends/smt2/smtbmc.py mode change 100644 => 100755 backends/smt2/witness.py create mode 100644 backends/smv/CMakeLists.txt delete mode 100644 backends/smv/Makefile.inc create mode 100644 backends/spice/CMakeLists.txt delete mode 100644 backends/spice/Makefile.inc create mode 100644 backends/table/CMakeLists.txt delete mode 100644 backends/table/Makefile.inc create mode 100644 backends/verilog/CMakeLists.txt delete mode 100644 backends/verilog/Makefile.inc create mode 100644 cmake/CheckLibcFeatures.cmake create mode 100644 cmake/Condition.cmake create mode 100644 cmake/FindDlfcn.cmake create mode 100644 cmake/FindPyosysEnv.cmake create mode 100644 cmake/FindPython3Embed.cmake create mode 100644 cmake/PkgConfig.cmake create mode 100644 cmake/PmgenCommand.cmake create mode 100644 cmake/YosysAbc.cmake create mode 100644 cmake/YosysAbcSubmodule.cmake create mode 100644 cmake/YosysComponent.cmake create mode 100644 cmake/YosysConfigScript.cmake create mode 100644 cmake/YosysInstallDirs.cmake create mode 100644 cmake/YosysLinkTarget.cmake create mode 100644 cmake/YosysVerific.cmake create mode 100644 cmake/YosysVersion.cmake create mode 100644 cmake/YosysVersionData.cmake create mode 100644 cmake/toolchain/toolchain-mingw-i686.cmake create mode 100644 cmake/toolchain/toolchain-mingw-x86_64.cmake create mode 100644 frontends/CMakeLists.txt create mode 100644 frontends/aiger/CMakeLists.txt delete mode 100644 frontends/aiger/Makefile.inc create mode 100644 frontends/aiger2/CMakeLists.txt delete mode 100644 frontends/aiger2/Makefile.inc create mode 100644 frontends/ast/CMakeLists.txt delete mode 100644 frontends/ast/Makefile.inc create mode 100644 frontends/blif/CMakeLists.txt delete mode 100644 frontends/blif/Makefile.inc create mode 100644 frontends/json/CMakeLists.txt delete mode 100644 frontends/json/Makefile.inc create mode 100644 frontends/liberty/CMakeLists.txt delete mode 100644 frontends/liberty/Makefile.inc create mode 100644 frontends/rpc/CMakeLists.txt delete mode 100644 frontends/rpc/Makefile.inc create mode 100644 frontends/rtlil/CMakeLists.txt delete mode 100644 frontends/rtlil/Makefile.inc create mode 100644 frontends/verific/CMakeLists.txt delete mode 100644 frontends/verific/Makefile.inc create mode 100644 frontends/verilog/CMakeLists.txt delete mode 100644 frontends/verilog/Makefile.inc create mode 100644 kernel/CMakeLists.txt rename {techlibs/common => kernel}/cellhelp.py (100%) create mode 100644 kernel/version.cc.in create mode 100644 kernel/yosys_config.h.in create mode 100644 libs/CMakeLists.txt create mode 100644 libs/bigint/CMakeLists.txt create mode 100644 libs/dlfcn-win32/CMakeLists.txt create mode 100644 libs/ezsat/CMakeLists.txt create mode 100644 libs/flex/FlexLexer.h create mode 100644 libs/flex/README.txt create mode 100644 libs/fst/CMakeLists.txt create mode 100644 libs/json11/CMakeLists.txt create mode 100644 libs/minisat/CMakeLists.txt create mode 100644 libs/sha1/CMakeLists.txt create mode 100644 libs/subcircuit/CMakeLists.txt create mode 100644 misc/cmake/check_missing_depends.sh create mode 100644 misc/cmake/script_pass_depends.py create mode 100644 nix/cross/tcl.nix create mode 100644 nix/cross/win-overlay.nix create mode 100644 nix/cross/win32.nix create mode 100644 nix/cross/win64.nix create mode 100644 nix/pkgs/yosys.nix create mode 100644 passes/CMakeLists.txt create mode 100644 passes/cmds/CMakeLists.txt delete mode 100644 passes/cmds/Makefile.inc create mode 100644 passes/cmds/sdc/CMakeLists.txt delete mode 100644 passes/cmds/sdc/Makefile.inc create mode 100644 passes/equiv/CMakeLists.txt delete mode 100644 passes/equiv/Makefile.inc create mode 100644 passes/fsm/CMakeLists.txt delete mode 100644 passes/fsm/Makefile.inc create mode 100644 passes/hierarchy/CMakeLists.txt delete mode 100644 passes/hierarchy/Makefile.inc create mode 100644 passes/memory/CMakeLists.txt delete mode 100644 passes/memory/Makefile.inc delete mode 100644 passes/opt/.gitignore create mode 100644 passes/opt/CMakeLists.txt delete mode 100644 passes/opt/Makefile.inc create mode 100644 passes/opt/opt_clean/CMakeLists.txt delete mode 100644 passes/opt/opt_clean/Makefile.inc delete mode 100644 passes/pmgen/.gitignore create mode 100644 passes/pmgen/CMakeLists.txt delete mode 100644 passes/pmgen/Makefile.inc create mode 100644 passes/proc/CMakeLists.txt delete mode 100644 passes/proc/Makefile.inc create mode 100644 passes/sat/CMakeLists.txt delete mode 100644 passes/sat/Makefile.inc create mode 100644 passes/techmap/CMakeLists.txt delete mode 100644 passes/techmap/Makefile.inc create mode 100644 passes/tests/CMakeLists.txt delete mode 100644 passes/tests/Makefile.inc delete mode 100644 pyosys/.gitignore create mode 100644 pyosys/CMakeLists.txt rename pyosys/{__init__.py => modinit.py} (100%) delete mode 100644 techlibs/.gitignore create mode 100644 techlibs/CMakeLists.txt create mode 100644 techlibs/achronix/CMakeLists.txt delete mode 100644 techlibs/achronix/Makefile.inc create mode 100644 techlibs/analogdevices/CMakeLists.txt delete mode 100644 techlibs/analogdevices/Makefile.inc create mode 100644 techlibs/anlogic/CMakeLists.txt delete mode 100644 techlibs/anlogic/Makefile.inc delete mode 100644 techlibs/common/.gitignore create mode 100644 techlibs/common/CMakeLists.txt delete mode 100644 techlibs/common/Makefile.inc create mode 100644 techlibs/coolrunner2/CMakeLists.txt delete mode 100644 techlibs/coolrunner2/Makefile.inc create mode 100644 techlibs/easic/CMakeLists.txt delete mode 100644 techlibs/easic/Makefile.inc create mode 100644 techlibs/efinix/CMakeLists.txt delete mode 100644 techlibs/efinix/Makefile.inc create mode 100644 techlibs/fabulous/CMakeLists.txt delete mode 100644 techlibs/fabulous/Makefile.inc create mode 100644 techlibs/gatemate/CMakeLists.txt delete mode 100644 techlibs/gatemate/Makefile.inc create mode 100644 techlibs/gowin/CMakeLists.txt delete mode 100644 techlibs/gowin/Makefile.inc create mode 100644 techlibs/greenpak4/CMakeLists.txt delete mode 100644 techlibs/greenpak4/Makefile.inc create mode 100644 techlibs/ice40/CMakeLists.txt delete mode 100644 techlibs/ice40/Makefile.inc create mode 100644 techlibs/intel/CMakeLists.txt delete mode 100644 techlibs/intel/Makefile.inc create mode 100644 techlibs/intel_alm/CMakeLists.txt delete mode 100644 techlibs/intel_alm/Makefile.inc create mode 100644 techlibs/lattice/CMakeLists.txt delete mode 100644 techlibs/lattice/Makefile.inc create mode 100644 techlibs/microchip/CMakeLists.txt delete mode 100644 techlibs/microchip/Makefile.inc create mode 100644 techlibs/nanoxplore/CMakeLists.txt delete mode 100644 techlibs/nanoxplore/Makefile.inc delete mode 100644 techlibs/quicklogic/.gitignore create mode 100644 techlibs/quicklogic/CMakeLists.txt delete mode 100644 techlibs/quicklogic/Makefile.inc create mode 100644 techlibs/sf2/CMakeLists.txt delete mode 100644 techlibs/sf2/Makefile.inc create mode 100644 techlibs/xilinx/CMakeLists.txt delete mode 100644 techlibs/xilinx/Makefile.inc create mode 100644 tests/unit/CMakeLists.txt create mode 100644 tests/unit/kernel/CMakeLists.txt create mode 100644 tests/unit/opt/CMakeLists.txt create mode 100644 tests/unit/techmap/CMakeLists.txt diff --git a/.gitignore b/.gitignore index b39088088..84d11a7cb 100644 --- a/.gitignore +++ b/.gitignore @@ -49,7 +49,9 @@ /tests/unit/objtest/ /tests/ystests /build +/build-* /result +/result-* /dist # pyosys @@ -86,3 +88,5 @@ __pycache__ /qtcreator.creator /qtcreator.creator.user /compile_commands.json +/.direnv +/.envrc diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..51c40ec41 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,523 @@ +if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR) + set(rm "rm -rf") + if (WIN32) + set(rm "del /s /q") + endif() + message(FATAL_ERROR + "In-tree builds are not supported. Instead, run:\n" + "${rm} CMakeCache.txt CMakeFiles ; cmake -B build " + ) +endif() + +cmake_minimum_required(VERSION 3.27) +project(yosys LANGUAGES C CXX) + +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +include(CMakeDependentOption) +include(FeatureSummary) +include(CheckPIESupported) + +include(Condition) +include(CheckLibcFeatures) +include(PkgConfig) +include(PmgenCommand) +include(YosysVersion) +include(YosysInstallDirs) +include(YosysConfigScript) +include(YosysComponent) +include(YosysLinkTarget) +include(YosysAbc) +include(YosysAbcSubmodule) +include(YosysVerific) + +# Build options. +set(YOSYS_COMPILER_LAUNCHER "" CACHE STRING "Compiler launcher (ccache, sccache)") +option(YOSYS_ENABLE_COVERAGE "Enable code coverage" OFF) +option(YOSYS_ENABLE_PROFILING "Enable instruction profiling" OFF) + +set(YOSYS_PROGRAM_PREFIX "" CACHE STRING "Name prefix for programs, libraries, and data") +set(YOSYS_COMPONENTS "everything" CACHE STRING "List of components to build (use pass names)") +option(BUILD_SHARED_LIBS "Build libyosys as a shared library" ON) + +option(YOSYS_DISABLE_THREADS "Disable threading" OFF) +set(YOSYS_ABC_EXECUTABLE "" CACHE FILEPATH + "Path to the ABC executable (empty for vendored, 'INTEGRATED-NOTFOUND' for in-process)") +option(YOSYS_WITHOUT_ABC "Disable ABC support (not recommended)" OFF) +option(YOSYS_WITHOUT_ZLIB "Disable zlib integration" OFF) +option(YOSYS_WITHOUT_LIBFFI "Disable libffi integration" OFF) +option(YOSYS_WITHOUT_READLINE "Disable readline integration" OFF) +option(YOSYS_WITHOUT_EDITLINE "Disable editline integration" OFF) +option(YOSYS_WITHOUT_TCL "Disable Tcl integration" OFF) +option(YOSYS_WITH_PYTHON "Enable Python integration" OFF) + +set(YOSYS_VERIFIC_DIR "" CACHE FILEPATH "Path to the Verific source code (empty to disable)") +set(YOSYS_VERIFIC_COMPONENTS "" CACHE STRING + "List of Verific components to link (empty for autodetect)") +set(YOSYS_VERIFIC_FEATURES "" CACHE STRING + "List of Yosys Verific frontend features to enable (empty for autodetect)") + +option(YOSYS_INSTALL_DRIVER "Install Yosys executable" ON) +option(YOSYS_INSTALL_LIBRARY "Install libyosys library" OFF) +cmake_dependent_option(YOSYS_INSTALL_PYTHON "Install Python extension module" OFF + YOSYS_WITH_PYTHON OFF) +set(YOSYS_INSTALL_PYTHON_SITEDIR "" CACHE STRING "Path to Python package installation directory") + +# Configure compiler. +set(CMAKE_EXPORT_COMPILE_COMMANDS YES) + +if (YOSYS_COMPILER_LAUNCHER) + set(CMAKE_C_COMPILER_LAUNCHER "${YOSYS_COMPILER_LAUNCHER}") + set(CMAKE_CXX_COMPILER_LAUNCHER "${YOSYS_COMPILER_LAUNCHER}") +endif() + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED YES) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +check_pie_supported() # opportunistically enable PIE + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(CMAKE_CXX_FLAGS_DEBUG "-Og -ggdb") + set(CMAKE_CXX_FLAGS_RELEASE "-O3") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -ggdb") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") + set(CMAKE_CXX_FLAGS_SANITIZE "-O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls") + if ("${SANITIZE}" MATCHES "memory") + set(CMAKE_CXX_FLAGS_SANITIZE "${CMAKE_CXX_FLAGS_SANITIZE} -fsanitize-memory-track-origins") + endif() + set(no_abc_options + "$<$>>,$>:-fsanitize=${SANITIZE}>" + "$<$>>:-Wall;-Wextra;-Werror=unused>" + ) + add_compile_options("${no_abc_options}") + add_link_options("${no_abc_options}") +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS_DEBUG "/Od /DEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "/O2") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/O2 /DEBUG") + set(CMAKE_CXX_FLAGS_MINSIZEREL "/Os") + add_compile_options(/Zc:__cplusplus) + add_definitions( + _CRT_NONSTDC_NO_DEPRECATE + _CRT_SECURE_NO_WARNINGS + ) +else() + # We have to do this because CMake adds `-DNDEBUG` in release builds by default, and there's + # no particularly good way to prevent this without also erasing optimization flags. + # If you see this message, reproduce the block above with the flags supported by your compiler. + message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} compiler is not supported") +endif() + +if (YOSYS_ENABLE_COVERAGE) + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") + elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping") + else() + message(FATAL_ERROR "Code coverage is not supported on ${CMAKE_CXX_COMPILER_ID} compiler") + endif() +endif() + +if (YOSYS_ENABLE_PROFILING) + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") + else() + message(FATAL_ERROR "Instruction profiling is not supported on ${CMAKE_CXX_COMPILER_ID} compiler") + endif() +endif() + +if (NOT CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID) + message(FATAL_ERROR "C and C++ compilers must be provided by the same vendor") +endif() +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") +set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") +set(CMAKE_C_FLAGS_SANITIZE "${CMAKE_CXX_FLAGS_SANITIZE}") + +if (CMAKE_SYSTEM_NAME STREQUAL "WASI") + add_compile_options( + -fwasm-exceptions -mllvm -wasm-use-legacy-eh=false + -D_WASI_EMULATED_PROCESS_CLOCKS + ) + add_link_options( + -fwasm-exceptions -mllvm -wasm-use-legacy-eh=false -lunwind + -lwasi-emulated-process-clocks + -Wl,--stack-first,-z,stack-size=8388608 + ) +endif() + +if (MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "16.0.0") + # GCC 15.2 sometimes refuses to construct an import directory for yosys.exe/libyosys.dll with: + # .../ld.exe: error: export ordinal too large: 67035 + # The cause is unknown. + message(WARNING "MinGW GCC is supported starting with version 16.0.0") +endif() + +# Required dependencies. +find_package(FLEX) +set_package_properties(FLEX PROPERTIES + URL "https://github.com/westes/flex" + DESCRIPTION "The Fast Lexical Analyzer" + PURPOSE "Compiling the Verilog lexer" + TYPE REQUIRED +) + +find_package(BISON) +set_package_properties(BISON PROPERTIES + URL "https://www.gnu.org/software/bison/" + DESCRIPTION "The Yacc-compatible Parser Generator" + PURPOSE "Compiling the Verilog parser" + TYPE REQUIRED +) + +find_package(Python3 3.7 COMPONENTS Interpreter) +set_package_properties(Python3 PROPERTIES + URL "https://www.python.org/" + DESCRIPTION "Dynamic programming language (Interpreter)" + PURPOSE "Generating data files\n Running external SMT2 solvers" + TYPE REQUIRED +) + +# Optional dependencies. +check_glob() +check_system() +check_popen() +find_package(Threads QUIET) +check_pthread_create() +find_package(Dlfcn QUIET) + +find_package(PkgConfig) +set_package_properties(PkgConfig PROPERTIES + URL "https://www.freedesktop.org/wiki/Software/pkg-config/" + DESCRIPTION "Library metadata manager" + PURPOSE "Discovering dependencies" + TYPE RECOMMENDED +) + +pkg_config_import(zlib) +set_package_properties(zlib PROPERTIES + URL "https://github.com/madler/zlib" + DESCRIPTION "A massively spiffy yet delicately unobtrusive compression library" + PURPOSE "Handling Gzip and FST file formats" +) + +pkg_config_import(libffi) +set_package_properties(libffi PROPERTIES + URL "https://sourceware.org/libffi/" + DESCRIPTION "A Portable Foreign Function Interface Library" + PURPOSE "Implementing Verilog DPI-C" +) + +pkg_config_import(editline MODULES libedit) +set_package_properties(editline PROPERTIES + URL "https://www.thrysoee.dk/editline/" + DESCRIPTION "Line editing and history library (BSD)" + PURPOSE "Enhancing the command prompt" + TYPE RECOMMENDED +) + +pkg_config_import(readline) +set_package_properties(readline PROPERTIES + URL "https://tiswww.case.edu/php/chet/readline/rltop.html" + DESCRIPTION "Line editing and history library (GPL)" + PURPOSE "Enhancing the command prompt" + TYPE RECOMMENDED +) + +# See https://core.tcl-lang.org/tips/doc/trunk/tip/538.md +pkg_config_import(tcl MODULES tcl) +set_package_properties(tcl PROPERTIES + URL "https://www.tcl-lang.org/" + DESCRIPTION "Dynamic programming language" + PURPOSE "Parsing SDC constraint files\n Binding Yosys API" +) + +if (tcl_FOUND) + get_target_property(tcl_options PkgConfig::tcl INTERFACE_COMPILE_OPTIONS) + if (tcl_options MATCHES "TCL_WITH_EXTERNAL_TOMMATH") + pkg_config_import(libtommath) + set_package_properties(libtommath PROPERTIES + URL "https://www.libtom.net/LibTomMath/" + DESCRIPTION "Multiple-precision integer library" + PURPOSE "Required by this build of Tcl" + TYPE REQUIRED + ) + # Unfortunately the pkg-config file for Tcl includes libtommath as a private dependency, + # while it should be public since it is exposed in the public API and necessary for its use. + target_link_libraries(PkgConfig::tcl INTERFACE PkgConfig::libtommath) + else() + # Vendored within Tcl itself. + set(libtommath_FOUND TRUE) + endif() +endif() + +if (YOSYS_WITH_PYTHON) + find_package(Python3Embed REQUIRED) + set_property(GLOBAL PROPERTY _CMAKE_Python3Embed_REQUIRED_VERSION "== ${Python3_VERSION}") + set_package_properties(Python3Embed PROPERTIES + URL "https://www.python.org/" + DESCRIPTION "Dynamic programming language (Embedding)" + PURPOSE "Binding Yosys API" + ) + + find_package(PyosysEnv REQUIRED) + set_package_properties(PyosysEnv PROPERTIES + DESCRIPTION "Pyosys wrapper generator environment" + PURPOSE "Either 'uv' or 'pybind11>3,<4 cxxheaderparser'" + ) +endif() + +find_package(GTest) +set_package_properties(GTest PROPERTIES + URL "https://google.github.io/googletest/" + DESCRIPTION "C++ testing and mocking framework by Google" + PURPOSE "Running unit tests" + TYPE RECOMMENDED +) + +# Configure features based on dependency availability. +message(VERBOSE "Conditional features:") +condition(YOSYS_ENABLE_GLOB HAVE_GLOB) +condition(YOSYS_ENABLE_SPAWN HAVE_SYSTEM AND HAVE_POPEN) +condition(YOSYS_ENABLE_THREADS Threads_FOUND AND HAVE_PTHREAD_CREATE AND NOT YOSYS_DISABLE_THREADS) +condition(YOSYS_ENABLE_PLUGINS Dlfcn_FOUND) +condition(YOSYS_ENABLE_ABC NOT YOSYS_WITHOUT_ABC) +condition(YOSYS_ENABLE_ZLIB zlib_FOUND AND NOT YOSYS_WITHOUT_ZLIB) +condition(YOSYS_ENABLE_LIBFFI Dlfcn_FOUND AND libffi_FOUND AND NOT YOSYS_WITHOUT_LIBFFI) +condition(YOSYS_ENABLE_READLINE readline_FOUND AND NOT YOSYS_WITHOUT_READLINE) +condition(YOSYS_ENABLE_EDITLINE editline_FOUND AND NOT YOSYS_WITHOUT_EDITLINE AND NOT YOSYS_ENABLE_READLINE) +condition(YOSYS_ENABLE_TCL tcl_FOUND AND libtommath_FOUND AND NOT YOSYS_WITHOUT_TCL) +condition(YOSYS_ENABLE_PYTHON Python3Embed_FOUND AND PyosysEnv_FOUND AND YOSYS_WITH_PYTHON) +condition(YOSYS_ENABLE_VERIFIC YOSYS_VERIFIC_DIR AND zlib_FOUND) +condition(YOSYS_ENABLE_HELP_SOURCE NOT CMAKE_BUILD_TYPE MATCHES "^(Release|RelWithDebInfo)$") + +# Describe dependencies and features +# CMake 4.0 would let us use proper conditions, but that's too new for now. +add_feature_info(have_glob YOSYS_ENABLE_GLOB "Glob expansion in filenames") +add_feature_info(have_spawn YOSYS_ENABLE_SPAWN "Passes that invoke external tools") +add_feature_info(have_threads YOSYS_ENABLE_THREADS "Multithreaded netlist operations") +add_feature_info(have_plugins YOSYS_ENABLE_PLUGINS "Dynamically loadable binary plugins") +add_feature_info(with_abc YOSYS_ENABLE_ABC "Production-quality logic synthesis flow") +add_feature_info(with_zlib YOSYS_ENABLE_ZLIB "Transparent Gzip decompression and FST file format support") +add_feature_info(with_libffi YOSYS_ENABLE_LIBFFI "Verilog DPI-C foreign function interface") +add_feature_info(with_readline YOSYS_ENABLE_READLINE "Using readline for prompt editing and history") +add_feature_info(with_editline YOSYS_ENABLE_EDITLINE "Using editline for prompt editing and history") +add_feature_info(with_tcl YOSYS_ENABLE_TCL "Tcl scripting and SDC parsing") +add_feature_info(with_python YOSYS_ENABLE_PYTHON "Python scripting and embedding") +add_feature_info(with_verific YOSYS_ENABLE_VERIFIC "Verific frontend integration") +message(STATUS "") +feature_summary(WHAT PACKAGES_FOUND + DEFAULT_DESCRIPTION) +feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND + DEFAULT_DESCRIPTION QUIET_ON_EMPTY FATAL_ON_MISSING_REQUIRED_PACKAGES +) +feature_summary(WHAT PACKAGES_NOT_FOUND + DEFAULT_DESCRIPTION QUIET_ON_EMPTY +) +feature_summary(WHAT ENABLED_FEATURES + DEFAULT_DESCRIPTION QUIET_ON_EMPTY) +feature_summary(WHAT DISABLED_FEATURES + DEFAULT_DESCRIPTION QUIET_ON_EMPTY) + +# Describe project version. +yosys_extract_version() + +# Describe ABC integration. +if (YOSYS_ENABLE_ABC AND NOT YOSYS_ENABLE_SPAWN AND NOT YOSYS_ABC_EXECUTABLE STREQUAL "INTEGRATED-NOTFOUND") + message(WARNING "ABC support on this platform forces -DYOSYS_ABC_EXECUTABLE=INTEGRATED-NOTFOUND") + set(YOSYS_ABC_EXECUTABLE "INTEGRATED-NOTFOUND" CACHE FILEPATH "" FORCE) +endif() + +set(YOSYS_LINK_ABC 0) +if (YOSYS_ENABLE_ABC) + if (NOT YOSYS_ABC_EXECUTABLE AND NOT YOSYS_SKIP_ABC_SUBMODULE_CHECK) + yosys_check_abc_submodule() + endif() + if (YOSYS_ABC_EXECUTABLE STREQUAL "INTEGRATED-NOTFOUND") + set(YOSYS_LINK_ABC 1) + message(STATUS "Building ABC: (integrated)") + elseif (YOSYS_ABC_EXECUTABLE STREQUAL "") + set(abc_filename ${YOSYS_PROGRAM_PREFIX}yosys-abc${CMAKE_EXECUTABLE_SUFFIX}) + message(STATUS "Building ABC: ${YOSYS_INSTALL_FULL_BINDIR}/${abc_filename}") + else() + message(STATUS "External ABC: ${YOSYS_ABC_EXECUTABLE}") + endif() +endif() + +# Ensure invalid dependencies fail at configuration time, not link time. +set(CMAKE_LINK_LIBRARIES_ONLY_TARGETS ON) + +# Pseudo-library that injects common compilation options into every Yosys component. +add_library(yosys_common INTERFACE) +target_compile_definitions(yosys_common INTERFACE + _YOSYS_ + $<$:DEBUG> +) +target_include_directories(yosys_common INTERFACE + ${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} +) +if (SANITIZE) + target_compile_options(yosys_common INTERFACE + ${sanitize_options} + ) +endif() + +# Two pseudo-components used for dependency tracking only. +yosys_core(essentials BOOTSTRAP) +yosys_core(everything BOOTSTRAP) + +# All of the source code. +add_subdirectory(libs) +add_subdirectory(kernel) +add_subdirectory(passes) +add_subdirectory(frontends) +add_subdirectory(backends) +add_subdirectory(techlibs) +if (YOSYS_ENABLE_PYTHON) + add_subdirectory(pyosys) +endif() + +# ABC submodule. +if (YOSYS_ENABLE_ABC AND NOT YOSYS_ABC_EXECUTABLE) + set(YOSYS_ABC_INSTALL NO) + if (YOSYS_ABC_EXECUTABLE STREQUAL "" AND (YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY)) + set(YOSYS_ABC_INSTALL YES) + endif() + yosys_abc_target(libyosys-abc yosys-abc + INSTALL_IF ${YOSYS_ABC_INSTALL} + ) +endif() + +# Compute a transitive closure of enabled components. +yosys_expand_components(library_components essentials ${YOSYS_COMPONENTS}) +yosys_expand_components(driver_components driver ${YOSYS_COMPONENTS}) + +# Main Yosys executable (compiler driver). +yosys_cxx_executable(yosys + OUTPUT_NAME yosys + INSTALL_IF ${YOSYS_INSTALL_DRIVER} +) +yosys_link_components(yosys PRIVATE ${driver_components}) +set_property(TARGET yosys PROPERTY ENABLE_EXPORTS ON) +if (MINGW) + target_link_options(yosys PRIVATE LINKER:--export-all-symbols) + set_target_properties(yosys PROPERTIES + # Final name: `yosys.exe.a` (linked to explicitly) + IMPORT_PREFIX "" + IMPORT_SUFFIX ".exe.a" + ) + if (YOSYS_INSTALL_DRIVER) + install(FILES ${CMAKE_BINARY_DIR}/yosys.exe.a DESTINATION ${YOSYS_INSTALL_LIBDIR}) + endif() +endif() + +target_compile_options(yosys PRIVATE -fsanitize=undefined) + +# Yosys components as a library. +if (BUILD_SHARED_LIBS) + set(libyosys_type SHARED) +else() + set(libyosys_type STATIC) +endif() +yosys_cxx_library(libyosys ${libyosys_type} + OUTPUT_NAME libyosys + INSTALL_IF ${YOSYS_INSTALL_LIBRARY} +) +yosys_link_components(libyosys PRIVATE ${library_components}) +add_library(Yosys::libyosys ALIAS libyosys) +if (MINGW) + set_target_properties(libyosys PROPERTIES + # Final name: `libyosys.dll.a` (linked to via `-lyosys`) + IMPORT_PREFIX "" + ) +endif() + +# Yosys data files (mainly headers and technological libraries). +if (YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY) + yosys_install_component_data(${library_components} DESTINATION ${YOSYS_INSTALL_DATADIR}) +endif() + +# Python binary extension (for using Yosys as a Python library). +if (YOSYS_ENABLE_PYTHON) + yosys_cxx_library(pyosys MODULE + OUTPUT_NAME pyosys + ) + yosys_link_components(pyosys PRIVATE ${library_components}) + set_target_properties(pyosys PROPERTIES EXCLUDE_FROM_ALL FALSE) # build but not install + if (YOSYS_ENABLE_ABC AND YOSYS_ABC_EXECUTABLE STREQUAL "") + add_dependencies(pyosys yosys-abc) + endif() + + if (YOSYS_INSTALL_PYTHON) + string(REPLACE "-" "_" PYOSYS_MODULE_PREFIX "${YOSYS_PROGRAM_PREFIX}") + if (YOSYS_INSTALL_PYTHON_SITEDIR STREQUAL "") + set(YOSYS_INSTALL_PYTHON_SITEDIR ${Python3_SITEARCH}) + endif() + set(pyosys_install_dir ${YOSYS_INSTALL_PYTHON_SITEDIR}/${PYOSYS_MODULE_PREFIX}pyosys) + install(FILES pyosys/modinit.py + RENAME __init__.py + DESTINATION ${pyosys_install_dir} + ) + install(FILES $ + RENAME libyosys${CMAKE_SHARED_MODULE_SUFFIX} + DESTINATION ${pyosys_install_dir} + ) + if (YOSYS_ENABLE_ABC AND YOSYS_ABC_EXECUTABLE STREQUAL "") + # If ABC is vendored it needs to be installed as a part of pyosys. + install(TARGETS yosys-abc + DESTINATION ${pyosys_install_dir} + ) + endif() + yosys_install_component_data(${library_components} DESTINATION ${pyosys_install_dir}/share) + endif() +endif() + +# Plugin build tool. +yosys_config_script(BUILD) +if (YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY) + yosys_config_script(INSTALL) +endif() + +# Tests. +add_subdirectory(tests/unit) +# TODO(cmake): other tests + +# Docs. +add_custom_target(docs-prepare + COMMAND make -C ${CMAKE_SOURCE_DIR}/docs gen + BUILD_DIR=${CMAKE_BINARY_DIR} + PROGRAM_PREFIX=${YOSYS_PROGRAM_PREFIX} + YOSYS=$ +) +foreach (format html latexpdf) + add_custom_target(docs-${format} + COMMAND make -C ${CMAKE_SOURCE_DIR}/docs ${format} + DEPENDS docs-prepare + ) +endforeach() + +# Utilities. +add_custom_target(print-version + COMMAND ${CMAKE_COMMAND} -E echo ${YOSYS_VERSION} + VERBATIM +) + +yosys_expand_components(all_components everything QUIET) +list(TRANSFORM all_components PREPEND "COMMAND;${CMAKE_COMMAND};-E;echo;" OUTPUT_VARIABLE echo_all_components) +add_custom_target(print-yosys-components + ${echo_all_components} + VERBATIM +) + +math(EXPR YOSYS_VERSION_MINOR_next "${YOSYS_VERSION_MINOR} + 1") +add_custom_target(increment-minor-version + COMMAND ${CMAKE_COMMAND} -E echo + "set(YOSYS_VERSION_MAJOR ${YOSYS_VERSION_MAJOR})" + > ${CMAKE_SOURCE_DIR}/cmake/YosysVersionData.cmake + COMMAND ${CMAKE_COMMAND} -E echo + "set(YOSYS_VERSION_MINOR ${YOSYS_VERSION_MINOR_next})" + >> ${CMAKE_SOURCE_DIR}/cmake/YosysVersionData.cmake + VERBATIM +) diff --git a/Makefile b/Makefile deleted file mode 100644 index 8bb1c0b2a..000000000 --- a/Makefile +++ /dev/null @@ -1,1219 +0,0 @@ - -CONFIG := none -# CONFIG := clang -# CONFIG := gcc -# CONFIG := wasi -# CONFIG := msys2-32 -# CONFIG := msys2-64 - -# features (the more the better) -ENABLE_TCL := 1 -ENABLE_ABC := 1 -ENABLE_GLOB := 1 -ENABLE_PLUGINS := 1 -ENABLE_READLINE := 1 -ENABLE_EDITLINE := 0 -ENABLE_GHDL := 0 -ENABLE_VERIFIC := 0 -ENABLE_VERIFIC_SYSTEMVERILOG := 1 -ENABLE_VERIFIC_VHDL := 1 -ENABLE_VERIFIC_HIER_TREE := 1 -ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0 -ENABLE_VERIFIC_EDIF := 0 -ENABLE_VERIFIC_LIBERTY := 0 -ENABLE_LIBYOSYS := 0 -ENABLE_LIBYOSYS_STATIC := 0 -ENABLE_ZLIB := 1 -ENABLE_HELP_SOURCE := 0 - -# python wrappers -ENABLE_PYOSYS := 0 -PYOSYS_USE_UV := 1 - -# other configuration flags -ENABLE_GCOV := 0 -ENABLE_GPROF := 0 -ENABLE_DEBUG := 0 -ENABLE_LTO := 0 -ENABLE_CCACHE := 0 -# sccache is not always a drop-in replacement for ccache in practice -ENABLE_SCCACHE := 0 -ENABLE_FUNCTIONAL_TESTS := 0 -LINK_CURSES := 0 -LINK_TERMCAP := 0 -LINK_ABC := 0 -# Needed for environments that can't run executables (i.e. emscripten, wasm) -DISABLE_SPAWN := 0 -# Needed for environments that don't have proper thread support (i.e. emscripten, wasm--for now) -ENABLE_THREADS := 1 -ifeq ($(ENABLE_THREADS),1) -DISABLE_ABC_THREADS := 0 -else -DISABLE_ABC_THREADS := 1 -endif - -# clang sanitizers -SANITIZER = -# SANITIZER = address -# SANITIZER = memory -# SANITIZER = undefined -# SANITIZER = cfi - -# Prefer using ENABLE_DEBUG over setting these -OPT_LEVEL := -O3 -GCC_LTO := -CLANG_LTO := -flto=thin - -PROGRAM_PREFIX := - -OS := $(shell uname -s) -PREFIX ?= /usr/local -INSTALL_SUDO := -ifneq ($(filter MINGW%,$(OS)),) -OS := MINGW -endif - -ifneq ($(wildcard Makefile.conf),) -include Makefile.conf -endif - -ifeq ($(ENABLE_PYOSYS),1) -ENABLE_LIBYOSYS := 1 -endif - -BINDIR := $(PREFIX)/bin -LIBDIR := $(PREFIX)/lib/$(PROGRAM_PREFIX)yosys -DATDIR := $(PREFIX)/share/$(PROGRAM_PREFIX)yosys - -EXE = -OBJS = -GENFILES = -EXTRA_OBJS = -EXTRA_TARGETS = -TARGETS = $(PROGRAM_PREFIX)yosys$(EXE) $(PROGRAM_PREFIX)yosys-config - -PRETTY = 1 -SMALL = 0 - -all: top-all - -YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) -VPATH := $(YOSYS_SRC) - -# Unit test -UNITESTPATH := $(YOSYS_SRC)/tests/unit - -export CXXSTD ?= c++20 -CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -Werror=unused -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include -LIBS := $(LIBS) -lstdc++ -lm -PLUGIN_LINKFLAGS := -PLUGIN_LIBS := -EXE_LINKFLAGS := -EXE_LIBS := -ifeq ($(OS), MINGW) -EXE_LINKFLAGS := -Wl,--export-all-symbols -Wl,--out-implib,libyosys_exe.a -PLUGIN_LINKFLAGS += -L"$(LIBDIR)" -PLUGIN_LIBS := -lyosys_exe -endif - -ifeq ($(ENABLE_HELP_SOURCE),1) -CXXFLAGS += -DYOSYS_ENABLE_HELP_SOURCE -endif - -PKG_CONFIG ?= pkg-config -SED ?= sed -BISON ?= bison -STRIP ?= strip -AWK ?= awk - -ifeq ($(OS), Darwin) -PLUGIN_LINKFLAGS += -undefined dynamic_lookup -LINKFLAGS += -rdynamic - -# homebrew search paths -ifneq ($(shell :; command -v brew),) -BREW_PREFIX := $(shell brew --prefix)/opt -$(info $$BREW_PREFIX is [${BREW_PREFIX}]) -CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include -LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib -PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) -PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH) -export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) - -# macports search paths -else ifneq ($(shell :; command -v port),) -PORT_PREFIX := $(patsubst %/bin/port,%,$(shell :; command -v port)) -CXXFLAGS += -I$(PORT_PREFIX)/include -LINKFLAGS += -L$(PORT_PREFIX)/lib -PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH) -export PATH := $(PORT_PREFIX)/bin:$(PATH) -endif - -else -LINKFLAGS += -rdynamic -ifneq ($(OS), OpenBSD) -LIBS += -lrt -endif -endif - -ifeq ($(OS), Haiku) -# Allow usage of non-posix vasprintf, mkstemps functions -CXXFLAGS += -D_DEFAULT_SOURCE -endif - -YOSYS_VER := 0.66 - -ifneq (, $(shell command -v git 2>/dev/null)) -ifneq (, $(shell git rev-parse --git-dir 2>/dev/null)) - GIT_COMMIT_COUNT := $(or $(shell git rev-list --count v$(YOSYS_VER)..HEAD 2>/dev/null),0) - ifneq ($(GIT_COMMIT_COUNT),0) - YOSYS_VER := $(YOSYS_VER)+$(GIT_COMMIT_COUNT) - endif -else - YOSYS_VER := $(YOSYS_VER)+post -endif -endif - -YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) -YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) -YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) -CXXFLAGS += -DYOSYS_VER=\\"$(YOSYS_VER)\\" \ - -DYOSYS_MAJOR=$(YOSYS_MAJOR) \ - -DYOSYS_MINOR=$(YOSYS_MINOR) \ - -DYOSYS_COMMIT=$(YOSYS_COMMIT) - -# Note: We arrange for .gitcommit to contain the (short) commit hash in -# tarballs generated with git-archive(1) using .gitattributes. The git repo -# will have this file in its unexpanded form tough, in which case we fall -# back to calling git directly. -TARBALL_GIT_REV := $(shell cat $(YOSYS_SRC)/.gitcommit) -ifneq ($(findstring Format:,$(TARBALL_GIT_REV)),) -GIT_REV := $(shell GIT_DIR=$(YOSYS_SRC)/.git git rev-parse --short=9 HEAD || echo UNKNOWN) -GIT_DIRTY := $(shell GIT_DIR=$(YOSYS_SRC)/.git git diff --exit-code --quiet 2>/dev/null; if [ $$? -ne 0 ]; then echo "-dirty"; fi) -else -GIT_REV := $(TARBALL_GIT_REV) -GIT_DIRTY := "" -endif - -OBJS = kernel/version_$(GIT_REV).o - -ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) - -# set ABCEXTERNAL = to use an external ABC instance -# Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set. -ABCEXTERNAL ?= - -define newline - - -endef - -ifneq ($(wildcard Makefile.conf),) -# don't echo Makefile.conf contents when invoked to print source versions -ifeq ($(findstring echo-,$(MAKECMDGOALS)),) -$(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$,;' < Makefile.conf | tr -d '\n' | sed 's,\$$--\$$$$,,'))) -endif -include Makefile.conf -endif - -PYTHON_EXECUTABLE ?= $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) -ifeq ($(ENABLE_PYOSYS),1) -PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" -PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") -PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.) - -PYTHON_CONFIG := $(PYTHON_EXECUTABLE)-config -PYTHON_CONFIG_FOR_EXE := $(PYTHON_CONFIG) -PYTHON_CONFIG_EMBED_AVAILABLE ?= $(shell $(PYTHON_EXECUTABLE)-config --embed --libs > /dev/null && echo 1) -ifeq ($(PYTHON_CONFIG_EMBED_AVAILABLE),1) -PYTHON_CONFIG_FOR_EXE := $(PYTHON_CONFIG) --embed -endif - -PYTHON_DESTDIR := $(shell $(PYTHON_EXECUTABLE) -c "import site; print(site.getsitepackages()[-1]);") - -# Reload Makefile.conf to override python specific variables if defined -ifneq ($(wildcard Makefile.conf),) -include Makefile.conf -endif - -endif - -ABC_ARCHFLAGS = "" -ifeq ($(OS), OpenBSD) -ABC_ARCHFLAGS += "-DABC_NO_RLIMIT" -endif - -# This gets overridden later. -LTOFLAGS := $(GCC_LTO) - -ifeq ($(CONFIG),clang) -CXX = clang++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ifeq ($(ENABLE_LTO),1) -LINKFLAGS += -fuse-ld=lld -endif -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)" -LTOFLAGS := $(CLANG_LTO) - -ifneq ($(SANITIZER),) -$(info [Clang Sanitizer] $(SANITIZER)) -CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER) -LINKFLAGS += -g -fsanitize=$(SANITIZER) -ifneq ($(findstring memory,$(SANITIZER)),) -CXXFLAGS += -fPIE -fsanitize-memory-track-origins -LINKFLAGS += -fPIE -fsanitize-memory-track-origins -endif -ifneq ($(findstring cfi,$(SANITIZER)),) -CXXFLAGS += -flto -LINKFLAGS += -flto -LTOFLAGS = -endif -endif - -else ifeq ($(CONFIG),gcc) -CXX = g++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)" - -else ifeq ($(CONFIG),gcc-static) -LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -static -LIBS := $(filter-out -lrt,$(LIBS)) -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(CXX)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \ - ARCHFLAGS="-DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING=1 -Wno-unused-but-set-variable $(ARCHFLAGS)" ABC_USE_NO_READLINE=1 -ifeq ($(DISABLE_ABC_THREADS),1) -ABCMKARGS += "ABC_USE_NO_PTHREADS=1" -endif - -else ifeq ($(CONFIG),wasi) -ifeq ($(WASI_SDK),) -CXX = clang++ -AR = llvm-ar -RANLIB = llvm-ranlib -WASIFLAGS := -target wasm32-wasip1 $(WASIFLAGS) -else -CXX = $(WASI_SDK)/bin/clang++ -AR = $(WASI_SDK)/bin/ar -RANLIB = $(WASI_SDK)/bin/ranlib -endif -CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) $(OPT_LEVEL) -D_WASI_EMULATED_PROCESS_CLOCKS -fwasm-exceptions -mllvm -wasm-use-legacy-eh=false $(filter-out -fPIC,$(CXXFLAGS)) -LINKFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LINKFLAGS)) -fwasm-exceptions -lunwind -LIBS := -lwasi-emulated-process-clocks $(filter-out -lrt,$(LIBS)) -ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)" -ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -D_WASI_EMULATED_PROCESS_CLOCKS -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING -DABC_NO_RLIMIT" -ABCMKARGS += OPTFLAGS="-Os" -LTOFLAGS = -EXE = .wasm - -DISABLE_SPAWN := 1 - -ifeq ($(ENABLE_ABC),1) -LINK_ABC := 1 -ENABLE_THREADS := 0 -DISABLE_ABC_THREADS := 1 -endif - -else ifeq ($(CONFIG),msys2-32) -CXX = i686-w64-mingw32-g++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s -LIBS := $(filter-out -lrt,$(LIBS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DWIN32 -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" -EXE = .exe - -else ifeq ($(CONFIG),msys2-64) -CXX = x86_64-w64-mingw32-g++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s -LIBS := $(filter-out -lrt,$(LIBS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DWIN32 -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" -EXE = .exe - -else ifeq ($(CONFIG),none) -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)" -LTOFLAGS = - -else -$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, msys2-32, msys2-64, none) -endif - - -ifeq ($(ENABLE_LTO),1) -CXXFLAGS += $(LTOFLAGS) -LINKFLAGS += $(LTOFLAGS) -endif - -ifeq ($(ENABLE_LIBYOSYS),1) -TARGETS += libyosys.so -ifeq ($(ENABLE_LIBYOSYS_STATIC),1) -TARGETS += libyosys.a -endif -endif - -PY_WRAPPER_FILE = pyosys/wrappers - -# running make clean on just those and then recompiling saves a lot of -# time when running cibuildwheel -PYTHON_OBJECTS = pyosys/wrappers.o kernel/drivers.o kernel/yosys.o passes/cmds/plugin.o - -ifeq ($(ENABLE_PYOSYS),1) -# python-config --ldflags includes -l and -L, but LINKFLAGS is only -L - -UV_ENV := -ifeq ($(PYOSYS_USE_UV),1) -UV_ENV := uv run --no-project --with 'pybind11>3,<4' --with 'cxxheaderparser' -endif - -LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags)) -LIBS += $(shell $(PYTHON_CONFIG) --libs) -EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs)) -PYBIND11_INCLUDE ?= $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) -m pybind11 --includes) -CXXFLAGS += -I$(PYBIND11_INCLUDE) -DYOSYS_ENABLE_PYTHON -CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DYOSYS_ENABLE_PYTHON - -OBJS += $(PY_WRAPPER_FILE).o -PY_GEN_SCRIPT = $(YOSYS_SRC)/pyosys/generator.py -PY_WRAP_INCLUDES := $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes) -endif # ENABLE_PYOSYS - -ifeq ($(ENABLE_READLINE),1) -CXXFLAGS += -DYOSYS_ENABLE_READLINE -ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) -CXXFLAGS += -I/usr/local/include -endif -LIBS += -lreadline -ifeq ($(LINK_CURSES),1) -LIBS += -lcurses -ABCMKARGS += "ABC_READLINE_LIBRARIES=-lcurses -lreadline" -endif -ifeq ($(LINK_TERMCAP),1) -LIBS += -ltermcap -ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap" -endif -else -ifeq ($(ENABLE_EDITLINE),1) -CXXFLAGS += -DYOSYS_ENABLE_EDITLINE -LIBS += -ledit -endif -ABCMKARGS += "ABC_USE_NO_READLINE=1" -endif - -ifeq ($(DISABLE_ABC_THREADS),1) -ABCMKARGS += "ABC_USE_NO_PTHREADS=1" -endif - -ifeq ($(LINK_ABC),1) -ABCMKARGS += "ABC_USE_PIC=1" -endif - -ifeq ($(DISABLE_SPAWN),1) -CXXFLAGS += -DYOSYS_DISABLE_SPAWN -endif - -ifeq ($(ENABLE_PLUGINS),1) -CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS -ifeq ($(OS), MINGW) -CXXFLAGS += -Ilibs/dlfcn-win32 -endif -LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ifneq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD MINGW)) -LIBS += -ldl -endif -endif - -ifeq ($(ENABLE_GLOB),1) -CXXFLAGS += -DYOSYS_ENABLE_GLOB -endif - -ifeq ($(ENABLE_ZLIB),1) -CXXFLAGS += -DYOSYS_ENABLE_ZLIB -LIBS += -lz -endif - - -ifeq ($(ENABLE_TCL),1) -TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") -ifeq ($(OS), $(filter $(OS),FreeBSD OpenBSD NetBSD)) -# BSDs usually use tcl8.6, but the lib is named "libtcl86" -TCL_INCLUDE ?= /usr/local/include/$(TCL_VERSION) -TCL_LIBS ?= -l$(subst .,,$(TCL_VERSION)) -else -TCL_INCLUDE ?= /usr/include/$(TCL_VERSION) -TCL_LIBS ?= -l$(TCL_VERSION) -endif - -CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL -LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo $(TCL_LIBS)) -ifneq (,$(findstring TCL_WITH_EXTERNAL_TOMMATH,$(CXXFLAGS))) -LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libtommath || echo) -endif -endif - -ifeq ($(ENABLE_GCOV),1) -LLVM_PROFILE_FILE ?= $(realpath $(YOSYS_SRC))/coverage/coverage_%p.profraw -export LLVM_PROFILE_FILE -export LLVM_PROFILE_FILE_BUFFER_SIZE=0 -CXXFLAGS += -fprofile-instr-generate -fcoverage-mapping -LINKFLAGS+= -fprofile-instr-generate -endif - -ifeq ($(ENABLE_GPROF),1) -CXXFLAGS += -pg -LINKFLAGS += -pg -endif - -ifeq ($(ENABLE_DEBUG),1) -CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS)) -STRIP := -endif - -ifeq ($(ENABLE_THREADS),1) -CXXFLAGS += -DYOSYS_ENABLE_THREADS -LIBS += -lpthread -endif - -ifeq ($(ENABLE_ABC),1) -CXXFLAGS += -DYOSYS_ENABLE_ABC -ifeq ($(LINK_ABC),1) -CXXFLAGS += -DYOSYS_LINK_ABC -ifeq ($(DISABLE_ABC_THREADS),0) -LIBS += -lpthread -endif -else -ifeq ($(ABCEXTERNAL),) -TARGETS := $(PROGRAM_PREFIX)yosys-abc$(EXE) $(TARGETS) -endif -ifeq ($(DISABLE_SPAWN),1) -$(error ENABLE_ABC=1 requires either LINK_ABC=1 or DISABLE_SPAWN=0) -endif -endif -endif - -ifeq ($(ENABLE_GHDL),1) -GHDL_PREFIX ?= $(PREFIX) -GHDL_INCLUDE_DIR ?= $(GHDL_PREFIX)/include -GHDL_LIB_DIR ?= $(GHDL_PREFIX)/lib -CXXFLAGS += -I$(GHDL_INCLUDE_DIR) -DYOSYS_ENABLE_GHDL -LIBS += $(GHDL_LIB_DIR)/libghdl.a $(file <$(GHDL_LIB_DIR)/libghdl.link) -endif - -LIBS_VERIFIC = -ifeq ($(ENABLE_VERIFIC),1) -VERIFIC_DIR ?= /usr/local/src/verific_lib -VERIFIC_COMPONENTS ?= database util containers -ifeq ($(ENABLE_VERIFIC_HIER_TREE),1) -VERIFIC_COMPONENTS += hier_tree -CXXFLAGS += -DVERIFIC_HIER_TREE_SUPPORT -else -ifneq ($(wildcard $(VERIFIC_DIR)/hier_tree),) -VERIFIC_COMPONENTS += hier_tree -endif -endif -ifeq ($(ENABLE_VERIFIC_SYSTEMVERILOG),1) -VERIFIC_COMPONENTS += verilog -CXXFLAGS += -DVERIFIC_SYSTEMVERILOG_SUPPORT -else -ifneq ($(wildcard $(VERIFIC_DIR)/verilog),) -VERIFIC_COMPONENTS += verilog -endif -endif -ifeq ($(ENABLE_VERIFIC_VHDL),1) -VERIFIC_COMPONENTS += vhdl -CXXFLAGS += -DVERIFIC_VHDL_SUPPORT -else -ifneq ($(wildcard $(VERIFIC_DIR)/vhdl),) -VERIFIC_COMPONENTS += vhdl -endif -endif -ifeq ($(ENABLE_VERIFIC_EDIF),1) -VERIFIC_COMPONENTS += edif -CXXFLAGS += -DVERIFIC_EDIF_SUPPORT -endif -ifeq ($(ENABLE_VERIFIC_LIBERTY),1) -VERIFIC_COMPONENTS += synlib -CXXFLAGS += -DVERIFIC_LIBERTY_SUPPORT -endif -ifeq ($(ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS),1) -VERIFIC_COMPONENTS += extensions -CXXFLAGS += -DYOSYSHQ_VERIFIC_EXTENSIONS -else -# YosysHQ flavor of Verific always needs extensions linked -# if disabled it will just not be invoked but parts -# are required for it to initialize properly -ifneq ($(wildcard $(VERIFIC_DIR)/extensions),) -VERIFIC_COMPONENTS += extensions -OBJS += kernel/log_compat.o -endif -endif -CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC -ifeq ($(OS), Darwin) -LIBS_VERIFIC += $(foreach comp,$(patsubst %,$(VERIFIC_DIR)/%/*-mac.a,$(VERIFIC_COMPONENTS)),-Wl,-force_load $(comp)) -lz -else -LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -Wl,--no-whole-archive -lz -endif -endif - -ifeq ($(ENABLE_CCACHE),1) -CXX := ccache $(CXX) -else -ifeq ($(ENABLE_SCCACHE),1) -CXX := sccache $(CXX) -endif -endif - -define add_share_file -EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) -$(subst //,/,$(1)/$(notdir $(2))): $(2) - $$(P) mkdir -p $(1) - $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(notdir $(2))) -endef - -define add_share_file_and_rename -EXTRA_TARGETS += $(subst //,/,$(1)/$(3)) -$(subst //,/,$(1)/$(3)): $(2) - $$(P) mkdir -p $(1) - $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(3)) -endef - -define add_gen_share_file -EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) -$(subst //,/,$(1)/$(notdir $(2))): $(2) - $$(P) mkdir -p $(1) - $$(Q) cp $(2) $(subst //,/,$(1)/$(notdir $(2))) -endef - -define add_include_file -$(eval $(call add_share_file,$(dir share/include/$(1)),$(1))) -endef - -define add_extra_objs -EXTRA_OBJS += $(1) -.SECONDARY: $(1) -endef - -ifeq ($(PRETTY), 1) -P_STATUS = 0 -P_OFFSET = 0 -P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) $(PROGRAM_PREFIX)yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }')) -P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) $(PROGRAM_PREFIX)yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%] -P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@"; -Q = @ -S = -s -else -P_SHOW = -> -P = -Q = -S = -endif - -$(eval $(call add_include_file,kernel/binding.h)) -$(eval $(call add_include_file,kernel/bitpattern.h)) -$(eval $(call add_include_file,kernel/cellaigs.h)) -$(eval $(call add_include_file,kernel/celledges.h)) -$(eval $(call add_include_file,kernel/celltypes.h)) -$(eval $(call add_include_file,kernel/newcelltypes.h)) -$(eval $(call add_include_file,kernel/consteval.h)) -$(eval $(call add_include_file,kernel/constids.inc)) -$(eval $(call add_include_file,kernel/cost.h)) -$(eval $(call add_include_file,kernel/drivertools.h)) -$(eval $(call add_include_file,kernel/ff.h)) -$(eval $(call add_include_file,kernel/ffinit.h)) -$(eval $(call add_include_file,kernel/ffmerge.h)) -$(eval $(call add_include_file,kernel/fmt.h)) -ifeq ($(ENABLE_ZLIB),1) -$(eval $(call add_include_file,kernel/fstdata.h)) -endif -$(eval $(call add_include_file,kernel/gzip.h)) -$(eval $(call add_include_file,kernel/hashlib.h)) -$(eval $(call add_include_file,kernel/io.h)) -$(eval $(call add_include_file,kernel/json.h)) -$(eval $(call add_include_file,kernel/log.h)) -$(eval $(call add_include_file,kernel/macc.h)) -$(eval $(call add_include_file,kernel/modtools.h)) -$(eval $(call add_include_file,kernel/mem.h)) -$(eval $(call add_include_file,kernel/qcsat.h)) -$(eval $(call add_include_file,kernel/register.h)) -$(eval $(call add_include_file,kernel/rtlil.h)) -$(eval $(call add_include_file,kernel/satgen.h)) -$(eval $(call add_include_file,kernel/scopeinfo.h)) -$(eval $(call add_include_file,kernel/sexpr.h)) -$(eval $(call add_include_file,kernel/sigtools.h)) -$(eval $(call add_include_file,kernel/threading.h)) -$(eval $(call add_include_file,kernel/timinginfo.h)) -$(eval $(call add_include_file,kernel/utils.h)) -$(eval $(call add_include_file,kernel/yosys.h)) -$(eval $(call add_include_file,kernel/yosys_common.h)) -$(eval $(call add_include_file,kernel/yw.h)) -$(eval $(call add_include_file,libs/ezsat/ezsat.h)) -$(eval $(call add_include_file,libs/ezsat/ezminisat.h)) -$(eval $(call add_include_file,libs/ezsat/ezcmdline.h)) -ifeq ($(ENABLE_ZLIB),1) -$(eval $(call add_include_file,libs/fst/fstapi.h)) -endif -$(eval $(call add_include_file,libs/sha1/sha1.h)) -$(eval $(call add_include_file,libs/json11/json11.hpp)) -$(eval $(call add_include_file,passes/fsm/fsmdata.h)) -$(eval $(call add_include_file,passes/techmap/libparse.h)) -$(eval $(call add_include_file,frontends/blif/blifparse.h)) -$(eval $(call add_include_file,backends/rtlil/rtlil_backend.h)) - -OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o kernel/io.o kernel/gzip.o -OBJS += kernel/rtlil_bufnorm.o -OBJS += kernel/log_help.o -ifeq ($(ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS),1) -OBJS += kernel/log_compat.o -endif -OBJS += kernel/binding.o kernel/tclapi.o -OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o -OBJS += kernel/drivertools.o kernel/functional.o kernel/threading.o -ifeq ($(ENABLE_ZLIB),1) -OBJS += kernel/fstdata.o -endif -ifeq ($(ENABLE_PLUGINS),1) -ifeq ($(OS), MINGW) -OBJS += libs/dlfcn-win32/dlfcn.o -endif -endif - -kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' -kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"' -ifeq ($(ENABLE_ABC),1) -ifneq ($(ABCEXTERNAL),) -kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' -endif -endif - -OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o -OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o - -OBJS += libs/sha1/sha1.o - -OBJS += libs/json11/json11.o - -OBJS += libs/ezsat/ezsat.o -OBJS += libs/ezsat/ezminisat.o -OBJS += libs/ezsat/ezcmdline.o - -OBJS += libs/minisat/Options.o -OBJS += libs/minisat/SimpSolver.o -OBJS += libs/minisat/Solver.o -OBJS += libs/minisat/System.o - -ifeq ($(ENABLE_ZLIB),1) -OBJS += libs/fst/fstapi.o -OBJS += libs/fst/fastlz.o -OBJS += libs/fst/lz4.o -endif - -techlibs/%_pm.h: passes/pmgen/pmgen.py techlibs/%.pmg - $(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p $(notdir $*) $(filter-out $<,$^) - -ifneq ($(SMALL),1) - -OBJS += libs/subcircuit/subcircuit.o - -include $(YOSYS_SRC)/frontends/*/Makefile.inc -include $(YOSYS_SRC)/passes/*/Makefile.inc -include $(YOSYS_SRC)/backends/*/Makefile.inc -include $(YOSYS_SRC)/techlibs/*/Makefile.inc - -else - -include $(YOSYS_SRC)/frontends/verilog/Makefile.inc -ifeq ($(ENABLE_VERIFIC),1) -include $(YOSYS_SRC)/frontends/verific/Makefile.inc -endif -include $(YOSYS_SRC)/frontends/rtlil/Makefile.inc -include $(YOSYS_SRC)/frontends/ast/Makefile.inc -include $(YOSYS_SRC)/frontends/blif/Makefile.inc - -OBJS += passes/hierarchy/hierarchy.o -OBJS += passes/cmds/select.o -OBJS += passes/cmds/show.o -OBJS += passes/cmds/stat.o -OBJS += passes/cmds/design.o -OBJS += passes/cmds/plugin.o - -include $(YOSYS_SRC)/passes/proc/Makefile.inc -include $(YOSYS_SRC)/passes/opt/Makefile.inc -include $(YOSYS_SRC)/passes/techmap/Makefile.inc - -include $(YOSYS_SRC)/backends/verilog/Makefile.inc -include $(YOSYS_SRC)/backends/rtlil/Makefile.inc - -include $(YOSYS_SRC)/techlibs/common/Makefile.inc - -endif - -ifeq ($(LINK_ABC),1) -OBJS += $(PROGRAM_PREFIX)yosys-libabc.a -endif - -# prevent the CXXFLAGS set by this Makefile from reaching abc/Makefile, -# especially the -MD flag which will break the build when CXX is clang -unexport CXXFLAGS - -top-all: $(TARGETS) $(EXTRA_TARGETS) - @echo "" - @echo " Build successful." - @echo "" - -.PHONY: compile-only -compile-only: $(OBJS) $(GENFILES) $(EXTRA_TARGETS) - @echo "" - @echo " Compile successful." - @echo "" - -.PHONY: share -share: $(EXTRA_TARGETS) - @echo "" - @echo " Share directory created." - @echo "" - -$(PROGRAM_PREFIX)yosys$(EXE): $(OBJS) - $(P) $(CXX) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LINKFLAGS) $(LINKFLAGS) $(OBJS) $(EXE_LIBS) $(LIBS) $(LIBS_VERIFIC) - -libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) -ifeq ($(OS), Darwin) - $(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) -else - $(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) -endif - -libyosys.a: $(filter-out kernel/driver.o,$(OBJS)) - $(P) $(AR) rcs $@ $^ - -%.o: %.cc - $(Q) mkdir -p $(dir $@) - $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< - -%.pyh: %.h - $(Q) mkdir -p $(dir $@) - $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(CXX) $(CXXFLAGS) -x c++ -o $@ -E -P - - -ifeq ($(ENABLE_PYOSYS),1) -$(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT) pyosys/wrappers_tpl.cc $(PY_WRAP_INCLUDES) pyosys/hashlib.h - $(Q) mkdir -p $(dir $@) - $(P) $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) $(PY_WRAPPER_FILE).cc -endif - -%.o: %.cpp - $(Q) mkdir -p $(dir $@) - $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< - -YOSYS_REPO := -ifneq (, $(shell command -v git 2>/dev/null)) -ifneq (, $(shell git rev-parse --git-dir 2>/dev/null)) - GIT_REMOTE := $(strip $(shell git config --get remote.origin.url 2>/dev/null | $(AWK) '{print tolower($$0)}')) - ifneq ($(strip $(GIT_REMOTE)),) - YOSYS_REPO := $(strip $(shell echo $(GIT_REMOTE) | $(AWK) -F '[:/]' '{gsub(/\.git$$/, "", $$NF); printf "%s/%s", $$(NF-1), $$NF}')) - endif - ifeq ($(strip $(YOSYS_REPO)),yosyshq/yosys) - YOSYS_REPO := - endif - GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) - ifeq ($(filter main HEAD release/v%,$(GIT_BRANCH)),) - YOSYS_REPO := $(YOSYS_REPO) at $(GIT_BRANCH) - endif - YOSYS_REPO := $(strip $(YOSYS_REPO)) -endif -endif - -YOSYS_GIT_STR := $(GIT_REV)$(GIT_DIRTY) -YOSYS_COMPILER := $(notdir $(CXX)) $(shell $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)) -YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(YOSYS_GIT_STR), $(YOSYS_COMPILER)) -ifneq ($(strip $(YOSYS_REPO)),) - YOSYS_VER_STR := $(YOSYS_VER_STR) [$(YOSYS_REPO)] -endif - -kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile - $(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc - $(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; const char *yosys_git_hash_str=\"$(YOSYS_GIT_STR)\"; }" > kernel/version_$(GIT_REV).cc - -ifeq ($(ENABLE_VERIFIC),1) -CXXFLAGS_NOVERIFIC = $(foreach v,$(CXXFLAGS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v))) -LIBS_NOVERIFIC = $(foreach v,$(LIBS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v))) -else -CXXFLAGS_NOVERIFIC = $(CXXFLAGS) -LIBS_NOVERIFIC = $(LIBS) -endif - -$(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in $(YOSYS_SRC)/Makefile - $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -Ilibs/dlfcn-win32,,$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(strip $(CXXFLAGS_NOVERIFIC))))#;' \ - -e 's#@CXX@#$(strip $(CXX))#;' -e 's#@LINKFLAGS@#$(strip $(LINKFLAGS) $(PLUGIN_LINKFLAGS))#;' -e 's#@LIBS@#$(strip $(LIBS_NOVERIFIC) $(PLUGIN_LIBS))#;' \ - -e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > $(PROGRAM_PREFIX)yosys-config - $(Q) chmod +x $(PROGRAM_PREFIX)yosys-config - -.PHONY: check-git-abc - -check-git-abc: - @if [ ! -d "$(YOSYS_SRC)/abc" ] && git -C "$(YOSYS_SRC)" status >/dev/null 2>&1; then \ - echo "Error: The 'abc' directory does not exist."; \ - echo "Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \ - exit 1; \ - elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^ '; then \ - exit 0; \ - elif [ -f "$(YOSYS_SRC)/abc/.gitcommit" ] && ! grep -q '\$$Format:%[hH]\$$' "$(YOSYS_SRC)/abc/.gitcommit"; then \ - echo "'abc' comes from a tarball. Continuing."; \ - exit 0; \ - elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^+'; then \ - echo "'abc' submodule does not match expected commit."; \ - echo "Run 'git submodule update' to check out the correct version."; \ - echo "Note: If testing a different version of abc, call 'git commit abc' in the Yosys source directory to update the expected commit."; \ - exit 1; \ - elif git -C "$(YOSYS_SRC)" submodule status abc 2>/dev/null | grep -q '^U'; then \ - echo "'abc' submodule has merge conflicts."; \ - echo "Please resolve merge conflicts before continuing."; \ - exit 1; \ - elif [ -f "$(YOSYS_SRC)/abc/.gitcommit" ] && grep -q '\$$Format:%[hH]\$$' "$(YOSYS_SRC)/abc/.gitcommit"; then \ - echo "Error: 'abc' is not configured as a git submodule."; \ - echo "To resolve this:"; \ - echo "1. Back up your changes: Save any modifications from the 'abc' directory to another location."; \ - echo "2. Remove the existing 'abc' directory: Delete the 'abc' directory and all its contents."; \ - echo "3. Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \ - echo "4. Reapply your changes: Move your saved changes back to the 'abc' directory, if necessary."; \ - exit 1; \ - elif ! git -C "$(YOSYS_SRC)" status >/dev/null 2>&1; then \ - echo "$(realpath $(YOSYS_SRC)) is not configured as a git repository, and 'abc' folder is missing."; \ - echo "If you already have ABC, set 'ABCEXTERNAL' make variable to point to ABC executable."; \ - echo "Otherwise, download release archive 'yosys.tar.gz' from https://github.com/YosysHQ/yosys/releases."; \ - echo " ('Source code' archive does not contain submodules.)"; \ - exit 1; \ - else \ - echo "Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule."; \ - exit 1; \ - fi - -.git-abc-submodule-hash: FORCE - @new=$$(cd abc 2>/dev/null && git rev-parse HEAD 2>/dev/null || echo none); \ - old=$$(cat .git-abc-submodule-hash 2>/dev/null || echo none); \ - if [ "$$new" != "$$old" ]; then \ - echo "$$new" > .git-abc-submodule-hash; \ - fi - -abc/abc$(EXE) abc/libabc.a: .git-abc-submodule-hash | check-git-abc - @if [ "$$(cd abc 2>/dev/null && git rev-parse HEAD 2>/dev/null)" != "$$(cat ../.git-abc-submodule-hash 2>/dev/null || echo none)" ]; then \ - rm -f abc/abc$(EXE); \ - fi - $(P) - $(Q) mkdir -p abc && $(MAKE) -C $(PROGRAM_PREFIX)abc -f "$(realpath $(YOSYS_SRC)/abc/Makefile)" ABCSRC="$(realpath $(YOSYS_SRC)/abc/)" $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc",PROG="abc$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc.a) - -$(PROGRAM_PREFIX)yosys-abc$(EXE): abc/abc$(EXE) - $(P) cp $< $(PROGRAM_PREFIX)yosys-abc$(EXE) - -$(PROGRAM_PREFIX)yosys-libabc.a: abc/libabc.a - $(P) cp $< $(PROGRAM_PREFIX)yosys-libabc.a - -ifneq ($(SEED),) -SEEDOPT="-S $(SEED)" -else -SEEDOPT="" -endif - -ifneq ($(ABCEXTERNAL),) -ABCOPT="-A $(ABCEXTERNAL)" -else -ABCOPT="" -endif - -test: vanilla-test unit-test - -.PHONY: vanilla-test - -vanilla-test: $(TARGETS) $(EXTRA_TARGETS) - @$(MAKE) -C tests vanilla-test \ - $(if $(ENABLE_VERIFIC),ENABLE_VERIFIC=$(ENABLE_VERIFIC)) \ - $(if $(YOSYS_NOVERIFIC),YOSYS_NOVERIFIC=$(YOSYS_NOVERIFIC)) \ - SEEDOPT=$(SEEDOPT) ABCOPT=$(ABCOPT) - -VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all - -vgtest: $(TARGETS) $(EXTRA_TARGETS) - $(VALGRIND) ./yosys -p 'setattr -mod -unset top; synth' $$( ls tests/simple/*.v | grep -v repwhile.v ) - @echo "" - @echo " Passed \"make vgtest\"." - @echo "" - -vloghtb: $(TARGETS) $(EXTRA_TARGETS) - +cd tests/vloghtb && bash run-test.sh - @echo "" - @echo " Passed \"make vloghtb\"." - @echo "" - -ystests: $(TARGETS) $(EXTRA_TARGETS) - rm -rf tests/ystests - git clone https://github.com/YosysHQ/yosys-tests.git tests/ystests - +$(MAKE) PATH="$$PWD:$$PATH" -C tests/ystests - @echo "" - @echo " Finished \"make ystests\"." - @echo "" - -# Unit test -unit-test: libyosys.so - @$(MAKE) -f $(UNITESTPATH)/Makefile CXX="$(CXX)" CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" \ - CXXFLAGS="$(CXXFLAGS)" LINKFLAGS="$(LINKFLAGS)" LIBS="$(LIBS)" ROOTPATH="$(CURDIR)" - -clean-unit-test: - @$(MAKE) -f $(UNITESTPATH)/Makefile clean - -install-dev: $(PROGRAM_PREFIX)yosys-config share - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) - $(INSTALL_SUDO) cp $(PROGRAM_PREFIX)yosys-config $(DESTDIR)$(BINDIR) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) - $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. - -install: $(TARGETS) $(EXTRA_TARGETS) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) - $(INSTALL_SUDO) cp $(filter-out libyosys.so libyosys.a,$(TARGETS)) $(DESTDIR)$(BINDIR) -ifneq ($(filter $(PROGRAM_PREFIX)yosys$(EXE),$(TARGETS)),) - if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys$(EXE); fi -endif -ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc$(EXE),$(TARGETS)),) - if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc$(EXE); fi -endif -ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib$(EXE),$(TARGETS)),) - if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib$(EXE); fi -endif - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) - $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. -ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) - $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/ - if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so; fi -ifeq ($(ENABLE_LIBYOSYS_STATIC),1) - $(INSTALL_SUDO) cp libyosys.a $(DESTDIR)$(LIBDIR)/ -endif -ifeq ($(ENABLE_PYOSYS),1) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys - $(INSTALL_SUDO) cp $(YOSYS_SRC)/pyosys/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py - $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so - $(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys -ifeq ($(ENABLE_ABC),1) -ifeq ($(ABCEXTERNAL),) - $(INSTALL_SUDO) cp $(PROGRAM_PREFIX)yosys-abc$(EXE) $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc$(EXE) -endif -endif -endif -endif -ifeq ($(ENABLE_PLUGINS),1) -ifeq ($(OS), MINGW) - $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) - $(INSTALL_SUDO) cp libyosys_exe.a $(DESTDIR)$(LIBDIR)/ -endif -endif - -uninstall: - $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR)/,$(notdir $(TARGETS))) - $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) -ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so -ifeq ($(ENABLE_LIBYOSYS_STATIC),1) - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.a -endif -ifeq ($(ENABLE_PYOSYS),1) - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so - $(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py - $(INSTALL_SUDO) rmdir $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys -endif -endif - -docs/source/generated/cmds.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) - $(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cmds-json $@' - -docs/source/generated/cells.json: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) - $(Q) ./$(PROGRAM_PREFIX)yosys -p 'help -dump-cells-json $@' - -docs/source/generated/%.cc: backends/%.cc - $(Q) mkdir -p $(@D) - $(Q) cp $< $@ - -# diff returns exit code 1 if the files are different, but it's not an error -docs/source/generated/functional/rosette.diff: backends/functional/smtlib.cc backends/functional/smtlib_rosette.cc - $(Q) mkdir -p $(@D) - $(Q) diff -U 20 $^ > $@ || exit 0 - -PHONY: docs/gen/functional_ir -docs/gen/functional_ir: docs/source/generated/functional/smtlib.cc docs/source/generated/functional/rosette.diff - -docs/source/generated/%.log: docs/source/generated $(TARGETS) $(EXTRA_TARGETS) - $(Q) ./$(PROGRAM_PREFIX)yosys -qQT -h '$*' -l $@ - -docs/source/generated/chformal.cc: passes/cmds/chformal.cc docs/source/generated - $(Q) cp $< $@ - -PHONY: docs/gen/chformal -docs/gen/chformal: docs/source/generated/chformal.log docs/source/generated/chformal.cc - -PHONY: docs/gen docs/usage docs/reqs -docs/gen: $(TARGETS) - $(Q) $(MAKE) -C docs gen - -docs/source/generated: - $(Q) mkdir -p docs/source/generated - -# some commands return an error and print the usage text to stderr -define DOC_USAGE_STDERR -docs/source/generated/$(1): $(TARGETS) docs/source/generated FORCE - -$(Q) ./$(PROGRAM_PREFIX)$(1) --help 2> $$@ -endef -DOCS_USAGE_STDERR := yosys-filterlib - -# The in-tree ABC (yosys-abc) is only built when ABCEXTERNAL is not set. -ifeq ($(ABCEXTERNAL),) -DOCS_USAGE_STDERR += yosys-abc -endif - -$(foreach usage,$(DOCS_USAGE_STDERR),$(eval $(call DOC_USAGE_STDERR,$(usage)))) - -# others print to stdout -define DOC_USAGE_STDOUT -docs/source/generated/$(1): $(TARGETS) docs/source/generated - $(Q) ./$(PROGRAM_PREFIX)$(1) --help > $$@ || rm $$@ -endef -DOCS_USAGE_STDOUT := yosys yosys-smtbmc yosys-witness yosys-config -$(foreach usage,$(DOCS_USAGE_STDOUT),$(eval $(call DOC_USAGE_STDOUT,$(usage)))) - -docs/usage: $(addprefix docs/source/generated/,$(DOCS_USAGE_STDOUT) $(DOCS_USAGE_STDERR)) - -docs/reqs: - $(Q) $(MAKE) -C docs reqs - -.PHONY: docs/prep -docs/prep: docs/source/generated/cells.json docs/source/generated/cmds.json docs/gen docs/usage docs/gen/functional_ir docs/gen/chformal - -DOC_TARGET ?= html -docs: docs/prep - $(Q) $(MAKE) -C docs $(DOC_TARGET) - -clean: clean-py clean-unit-test - rm -rf share - rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) - rm -f kernel/version_*.o kernel/version_*.cc - rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d - rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_* - -$(MAKE) -C $(YOSYS_SRC)/tests clean - -$(MAKE) -C $(YOSYS_SRC)/docs clean - rm -rf docs/util/__pycache__ - rm -f libyosys.so - -clean-py: - rm -f $(PY_WRAPPER_FILE).inc.cc $(PY_WRAPPER_FILE).cc - rm -f $(PYTHON_OBJECTS) - rm -f *.whl - rm -f libyosys.so libyosys.a - rm -rf kernel/*.pyh - -clean-abc: - $(MAKE) -C $(YOSYS_SRC)/abc DEP= clean - rm -f $(PROGRAM_PREFIX)yosys-abc$(EXE) $(PROGRAM_PREFIX)yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a .git-abc-submodule-hash - -mrproper: clean - git clean -xdf - -coverage: - ./$(PROGRAM_PREFIX)yosys -qp 'help; help -all' - rm -rf coverage_html - llvm-profdata merge -sparse coverage/coverage_*.profraw -o yosys.profdata - llvm-cov show ./$(PROGRAM_PREFIX)yosys -instr-profile=yosys.profdata -format=html -output-dir=coverage_html --compilation-dir=. -ignore-filename-regex='(^|.*/)libs/.*|/usr/include/.*|$(subst /,\/,$(VERIFIC_DIR))/.*' - -clean_coverage: - rm -rf coverage - rm -f yosys.profdata - -FUNC_KERNEL := functional.cc functional.h sexpr.cc sexpr.h compute_graph.h -FUNC_INCLUDES := $(addprefix --include *,functional/* $(FUNC_KERNEL)) -coverage_functional: - rm -rf coverage.info coverage_html - lcov --capture -d backends/functional -d kernel $(FUNC_INCLUDES) --no-external -o coverage.info - genhtml coverage.info --output-directory coverage_html - -qtcreator: - echo "$(CXXFLAGS)" | grep -o '\-D[^ ]*' | tr ' ' '\n' | sed 's/-D/#define /' | sed 's/=/ /'> qtcreator.config - { for file in $(basename $(OBJS)); do \ - for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \ - done; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \); } > qtcreator.files - { echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes - touch qtcreator.creator - -VCX_DIR_NAME := yosys-win32-vcxsrc-$(YOSYS_VER) -vcxsrc: $(GENFILES) $(EXTRA_TARGETS) kernel/version_$(GIT_REV).cc - rm -rf $(VCX_DIR_NAME){,.zip} - cp -f kernel/version_$(GIT_REV).cc kernel/version.cc - set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \ - echo "Analyse: $$f" >&2; cpp -std=c++20 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt - echo "libs/fst/fst_win_unistd.h" >> srcfiles.txt - echo "kernel/version.cc" >> srcfiles.txt - bash misc/create_vcxsrc.sh $(VCX_DIR_NAME) $(YOSYS_VER) - zip $(VCX_DIR_NAME)/genfiles.zip $(GENFILES) kernel/version.cc - zip -r $(VCX_DIR_NAME).zip $(VCX_DIR_NAME)/ - rm -f srcfiles.txt kernel/version.cc - -config-clean: clean - rm -f Makefile.conf - -config-clang: clean - echo 'CONFIG := clang' > Makefile.conf - -config-gcc: clean - echo 'CONFIG := gcc' > Makefile.conf - -config-gcc-static: clean - echo 'CONFIG := gcc-static' > Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - echo 'ENABLE_READLINE := 0' >> Makefile.conf - echo 'ENABLE_TCL := 0' >> Makefile.conf - -config-wasi: clean - echo 'CONFIG := wasi' > Makefile.conf - echo 'ENABLE_TCL := 0' >> Makefile.conf - echo 'ENABLE_ABC := 0' >> Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - echo 'ENABLE_READLINE := 0' >> Makefile.conf - echo 'ENABLE_ZLIB := 0' >> Makefile.conf - -config-msys2-32: clean - echo 'CONFIG := msys2-32' > Makefile.conf - echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf - -config-msys2-64: clean - echo 'CONFIG := msys2-64' > Makefile.conf - echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf - -config-gcov: clean - echo 'CONFIG := clang' > Makefile.conf - echo 'ENABLE_GCOV := 1' >> Makefile.conf - echo 'ENABLE_DEBUG := 1' >> Makefile.conf - -config-gprof: clean - echo 'CONFIG := gcc' > Makefile.conf - echo 'ENABLE_GPROF := 1' >> Makefile.conf - -config-sudo: - echo "INSTALL_SUDO := sudo" >> Makefile.conf - -echo-yosys-ver: - @echo "$(YOSYS_VER)" - -echo-git-rev: - @echo "$(GIT_REV)" - -echo-cxx: - @echo "$(CXX)" - --include libs/*/*.d --include frontends/*/*.d --include passes/*/*.d --include backends/*/*.d --include kernel/*.d --include techlibs/*/*.d - -FORCE: - -.PHONY: all top-all abc test install-dev install install-abc docs clean mrproper qtcreator coverage vcxsrc -.PHONY: config-clean config-clang config-gcc config-gcc-static config-gprof config-sudo diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt new file mode 100644 index 000000000..a38c2ec94 --- /dev/null +++ b/backends/CMakeLists.txt @@ -0,0 +1,18 @@ +add_subdirectory(aiger) +add_subdirectory(aiger2) +add_subdirectory(blif) +add_subdirectory(btor) +add_subdirectory(cxxrtl) +add_subdirectory(edif) +add_subdirectory(firrtl) +add_subdirectory(functional) +add_subdirectory(intersynth) +add_subdirectory(jny) +add_subdirectory(json) +add_subdirectory(rtlil) +add_subdirectory(simplec) +add_subdirectory(smt2) +add_subdirectory(smv) +add_subdirectory(spice) +add_subdirectory(table) +add_subdirectory(verilog) diff --git a/backends/aiger/CMakeLists.txt b/backends/aiger/CMakeLists.txt new file mode 100644 index 000000000..4cf940196 --- /dev/null +++ b/backends/aiger/CMakeLists.txt @@ -0,0 +1,8 @@ +yosys_backend(aiger + aiger.cc + REQUIRES + json11 +) +yosys_backend(xaiger + xaiger.cc +) diff --git a/backends/aiger/Makefile.inc b/backends/aiger/Makefile.inc deleted file mode 100644 index 4a4cf30bd..000000000 --- a/backends/aiger/Makefile.inc +++ /dev/null @@ -1,4 +0,0 @@ - -OBJS += backends/aiger/aiger.o -OBJS += backends/aiger/xaiger.o - diff --git a/backends/aiger2/CMakeLists.txt b/backends/aiger2/CMakeLists.txt new file mode 100644 index 000000000..f77b8d9ee --- /dev/null +++ b/backends/aiger2/CMakeLists.txt @@ -0,0 +1,5 @@ +yosys_backend(aiger2 + aiger.cc + PROVIDES + write_xaiger2 +) diff --git a/backends/aiger2/Makefile.inc b/backends/aiger2/Makefile.inc deleted file mode 100644 index 494b8d6c6..000000000 --- a/backends/aiger2/Makefile.inc +++ /dev/null @@ -1 +0,0 @@ -OBJS += backends/aiger2/aiger.o diff --git a/backends/blif/CMakeLists.txt b/backends/blif/CMakeLists.txt new file mode 100644 index 000000000..06b177513 --- /dev/null +++ b/backends/blif/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(blif + blif.cc +) diff --git a/backends/blif/Makefile.inc b/backends/blif/Makefile.inc deleted file mode 100644 index 517dabaf2..000000000 --- a/backends/blif/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/blif/blif.o - diff --git a/backends/btor/CMakeLists.txt b/backends/btor/CMakeLists.txt new file mode 100644 index 000000000..ca40d538e --- /dev/null +++ b/backends/btor/CMakeLists.txt @@ -0,0 +1,7 @@ +yosys_backend(btor + btor.cc + REQUIRES + bmuxmap + demuxmap + bwmuxmap +) diff --git a/backends/btor/Makefile.inc b/backends/btor/Makefile.inc deleted file mode 100644 index af7ab14dc..000000000 --- a/backends/btor/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/btor/btor.o - diff --git a/backends/cxxrtl/CMakeLists.txt b/backends/cxxrtl/CMakeLists.txt new file mode 100644 index 000000000..f5d10539a --- /dev/null +++ b/backends/cxxrtl/CMakeLists.txt @@ -0,0 +1,19 @@ +yosys_backend(cxxrtl + cxxrtl_backend.cc + DATA_DIR + include/backends/cxxrtl + DATA_FILES + runtime/README.txt + runtime/cxxrtl/cxxrtl.h + runtime/cxxrtl/cxxrtl_vcd.h + runtime/cxxrtl/cxxrtl_time.h + runtime/cxxrtl/cxxrtl_replay.h + runtime/cxxrtl/capi/cxxrtl_capi.cc + runtime/cxxrtl/capi/cxxrtl_capi.h + runtime/cxxrtl/capi/cxxrtl_capi_vcd.cc + runtime/cxxrtl/capi/cxxrtl_capi_vcd.h + REQUIRES + hierarchy + flatten + proc +) diff --git a/backends/cxxrtl/Makefile.inc b/backends/cxxrtl/Makefile.inc deleted file mode 100644 index dd77d2ad3..000000000 --- a/backends/cxxrtl/Makefile.inc +++ /dev/null @@ -1,11 +0,0 @@ - -OBJS += backends/cxxrtl/cxxrtl_backend.o - -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/cxxrtl.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/cxxrtl_vcd.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/cxxrtl_time.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/cxxrtl_replay.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/capi/cxxrtl_capi.cc)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/capi/cxxrtl_capi.h)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/capi/cxxrtl_capi_vcd.cc)) -$(eval $(call add_include_file,backends/cxxrtl/runtime/cxxrtl/capi/cxxrtl_capi_vcd.h)) diff --git a/backends/edif/CMakeLists.txt b/backends/edif/CMakeLists.txt new file mode 100644 index 000000000..126d09f07 --- /dev/null +++ b/backends/edif/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(edif + edif.cc +) diff --git a/backends/edif/Makefile.inc b/backends/edif/Makefile.inc deleted file mode 100644 index 93de0e24f..000000000 --- a/backends/edif/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/edif/edif.o - diff --git a/backends/firrtl/CMakeLists.txt b/backends/firrtl/CMakeLists.txt new file mode 100644 index 000000000..2f38cd208 --- /dev/null +++ b/backends/firrtl/CMakeLists.txt @@ -0,0 +1,8 @@ +yosys_backend(firrtl + firrtl.cc + REQUIRES + pmuxtree + bmuxmap + demuxmap + bwmuxmap +) diff --git a/backends/firrtl/Makefile.inc b/backends/firrtl/Makefile.inc deleted file mode 100644 index fdf100d34..000000000 --- a/backends/firrtl/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/firrtl/firrtl.o - diff --git a/backends/functional/CMakeLists.txt b/backends/functional/CMakeLists.txt new file mode 100644 index 000000000..5e7a6e92f --- /dev/null +++ b/backends/functional/CMakeLists.txt @@ -0,0 +1,12 @@ +yosys_backend(functional_cxx + cxx.cc +) +yosys_backend(functional_smt2 + smtlib.cc +) +yosys_backend(functional_rosette + smtlib_rosette.cc +) +yosys_test_pass(generic + test_generic.cc +) diff --git a/backends/functional/Makefile.inc b/backends/functional/Makefile.inc deleted file mode 100644 index 16d1c0542..000000000 --- a/backends/functional/Makefile.inc +++ /dev/null @@ -1,4 +0,0 @@ -OBJS += backends/functional/cxx.o -OBJS += backends/functional/smtlib.o -OBJS += backends/functional/smtlib_rosette.o -OBJS += backends/functional/test_generic.o diff --git a/backends/intersynth/CMakeLists.txt b/backends/intersynth/CMakeLists.txt new file mode 100644 index 000000000..e34bab4e1 --- /dev/null +++ b/backends/intersynth/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(intersynth + intersynth.cc +) diff --git a/backends/intersynth/Makefile.inc b/backends/intersynth/Makefile.inc deleted file mode 100644 index 85df1b393..000000000 --- a/backends/intersynth/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/intersynth/intersynth.o - diff --git a/backends/jny/CMakeLists.txt b/backends/jny/CMakeLists.txt new file mode 100644 index 000000000..e76a74e97 --- /dev/null +++ b/backends/jny/CMakeLists.txt @@ -0,0 +1,5 @@ +yosys_backend(jny + jny.cc + PROVIDES + jny +) diff --git a/backends/jny/Makefile.inc b/backends/jny/Makefile.inc deleted file mode 100644 index 5e417128e..000000000 --- a/backends/jny/Makefile.inc +++ /dev/null @@ -1,2 +0,0 @@ - -OBJS += backends/jny/jny.o diff --git a/backends/json/CMakeLists.txt b/backends/json/CMakeLists.txt new file mode 100644 index 000000000..99c404d92 --- /dev/null +++ b/backends/json/CMakeLists.txt @@ -0,0 +1,5 @@ +yosys_backend(json + json.cc + PROVIDES + json +) diff --git a/backends/json/Makefile.inc b/backends/json/Makefile.inc deleted file mode 100644 index a463daf91..000000000 --- a/backends/json/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/json/json.o - diff --git a/backends/rtlil/CMakeLists.txt b/backends/rtlil/CMakeLists.txt new file mode 100644 index 000000000..40b3cffe0 --- /dev/null +++ b/backends/rtlil/CMakeLists.txt @@ -0,0 +1,11 @@ +yosys_backend(rtlil + rtlil_backend.cc + rtlil_backend.h + PROVIDES + dump + DATA_DIR + include/backends/rtlil + DATA_FILES + rtlil_backend.h + ESSENTIAL +) diff --git a/backends/rtlil/Makefile.inc b/backends/rtlil/Makefile.inc deleted file mode 100644 index f691282ca..000000000 --- a/backends/rtlil/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/rtlil/rtlil_backend.o - diff --git a/backends/simplec/CMakeLists.txt b/backends/simplec/CMakeLists.txt new file mode 100644 index 000000000..1a9feed9f --- /dev/null +++ b/backends/simplec/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(simplec + simplec.cc +) diff --git a/backends/simplec/Makefile.inc b/backends/simplec/Makefile.inc deleted file mode 100644 index fee1376c5..000000000 --- a/backends/simplec/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/simplec/simplec.o - diff --git a/backends/smt2/CMakeLists.txt b/backends/smt2/CMakeLists.txt new file mode 100644 index 000000000..c60bace7b --- /dev/null +++ b/backends/smt2/CMakeLists.txt @@ -0,0 +1,20 @@ +yosys_backend(smt2 + smt2.cc + REQUIRES + json11 + DATA_DIR + python3 + DATA_FILES + smtio.py + ywio.py + REQUIRES + bmuxmap + demuxmap +) + +yosys_python_executable(yosys-smtbmc smtbmc.py + INSTALL_IF YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY +) +yosys_python_executable(yosys-witness witness.py + INSTALL_IF YOSYS_INSTALL_DRIVER OR YOSYS_INSTALL_LIBRARY +) diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc deleted file mode 100644 index 3afe990e7..000000000 --- a/backends/smt2/Makefile.inc +++ /dev/null @@ -1,46 +0,0 @@ - -OBJS += backends/smt2/smt2.o - -ifneq ($(CONFIG),mxe) -ifneq ($(CONFIG),emcc) - -# MSYS targets support yosys-smtbmc, but require a launcher script -ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64)) -TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc.exe $(PROGRAM_PREFIX)yosys-smtbmc-script.py -TARGETS += $(PROGRAM_PREFIX)yosys-witness.exe $(PROGRAM_PREFIX)yosys-witness-script.py -# Needed to find the Python interpreter for yosys-smtbmc scripts. -# Override if necessary, it is only used for msys2 targets. -PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3) - -$(PROGRAM_PREFIX)yosys-smtbmc-script.py: backends/smt2/smtbmc.py - $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' \ - -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ - -$(PROGRAM_PREFIX)yosys-witness-script.py: backends/smt2/witness.py - $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' \ - -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ - -$(PROGRAM_PREFIX)yosys-smtbmc.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-smtbmc-script.py - $(P) $(CXX) -DGUI=0 -O -s -o $@ $< - -$(PROGRAM_PREFIX)yosys-witness.exe: misc/launcher.c $(PROGRAM_PREFIX)yosys-witness-script.py - $(P) $(CXX) -DGUI=0 -O -s -o $@ $< -# Other targets -else -TARGETS += $(PROGRAM_PREFIX)yosys-smtbmc $(PROGRAM_PREFIX)yosys-witness - -$(PROGRAM_PREFIX)yosys-smtbmc: backends/smt2/smtbmc.py - $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new - $(Q) chmod +x $@.new - $(Q) mv $@.new $@ - -$(PROGRAM_PREFIX)yosys-witness: backends/smt2/witness.py - $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/$(PROGRAM_PREFIX)yosys/python3"]]|;' < $< > $@.new - $(Q) chmod +x $@.new - $(Q) mv $@.new $@ -endif - -$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py)) -$(eval $(call add_share_file,share/python3,backends/smt2/ywio.py)) -endif -endif diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py old mode 100644 new mode 100755 index 9dfbd2a25..60fa97e36 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!@PYTHON_SHEBANG@ # # yosys -- Yosys Open SYnthesis Suite # @@ -18,7 +18,7 @@ # import os, sys, getopt, re, bisect, json -##yosys-sys-path## +sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/@YOSYS_PROGRAM_PREFIX@yosys/python3"]] from smtio import SmtIo, SmtOpts, MkVcd from ywio import ReadWitness, WriteWitness, WitnessValues from collections import defaultdict diff --git a/backends/smt2/witness.py b/backends/smt2/witness.py old mode 100644 new mode 100755 index b7e25851c..83416c695 --- a/backends/smt2/witness.py +++ b/backends/smt2/witness.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!@PYTHON_SHEBANG@ # # yosys -- Yosys Open SYnthesis Suite # @@ -18,7 +18,7 @@ # import os, sys, itertools, re -##yosys-sys-path## +sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/@YOSYS_PROGRAM_PREFIX@yosys/python3"]] import json import click diff --git a/backends/smv/CMakeLists.txt b/backends/smv/CMakeLists.txt new file mode 100644 index 000000000..ea9e85f28 --- /dev/null +++ b/backends/smv/CMakeLists.txt @@ -0,0 +1,7 @@ +yosys_backend(smv + smv.cc + REQUIRES + bmuxmap + demuxmap + bwmuxmap +) diff --git a/backends/smv/Makefile.inc b/backends/smv/Makefile.inc deleted file mode 100644 index 66c192d80..000000000 --- a/backends/smv/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/smv/smv.o - diff --git a/backends/spice/CMakeLists.txt b/backends/spice/CMakeLists.txt new file mode 100644 index 000000000..efbfc84d0 --- /dev/null +++ b/backends/spice/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(spice + spice.cc +) diff --git a/backends/spice/Makefile.inc b/backends/spice/Makefile.inc deleted file mode 100644 index 9c8530cb2..000000000 --- a/backends/spice/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/spice/spice.o - diff --git a/backends/table/CMakeLists.txt b/backends/table/CMakeLists.txt new file mode 100644 index 000000000..371d1e8f0 --- /dev/null +++ b/backends/table/CMakeLists.txt @@ -0,0 +1,3 @@ +yosys_backend(table + table.cc +) diff --git a/backends/table/Makefile.inc b/backends/table/Makefile.inc deleted file mode 100644 index 8cd1dc619..000000000 --- a/backends/table/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/table/table.o - diff --git a/backends/verilog/CMakeLists.txt b/backends/verilog/CMakeLists.txt new file mode 100644 index 000000000..6de8dd1f6 --- /dev/null +++ b/backends/verilog/CMakeLists.txt @@ -0,0 +1,8 @@ +yosys_backend(verilog + verilog_backend.cc + verilog_backend.h + REQUIRES + bmuxmap + demuxmap + clean_zerowidth +) diff --git a/backends/verilog/Makefile.inc b/backends/verilog/Makefile.inc deleted file mode 100644 index c2dffef7a..000000000 --- a/backends/verilog/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -OBJS += backends/verilog/verilog_backend.o - diff --git a/cmake/CheckLibcFeatures.cmake b/cmake/CheckLibcFeatures.cmake new file mode 100644 index 000000000..3fc32afe3 --- /dev/null +++ b/cmake/CheckLibcFeatures.cmake @@ -0,0 +1,40 @@ +include(CMakePushCheckState) +include(CheckSourceCompiles) +include(CheckCXXSymbolExists) + +function(check_glob) + check_cxx_symbol_exists(glob "glob.h" HAVE_GLOB) + return (PROPAGATE HAVE_BLOB) +endfunction() + +function(check_pthread_create) + if (Threads_FOUND) + # On WASI, `pthread_create()` is always available, but always fails on triples without threading + # support. Probe for it while requesting the stub implementation to be hidden, otherwise we will + # end up always crashing at runtime on thread creation. + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_DEFINITIONS -D_WASI_STRICT_PTHREAD) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) + check_source_compiles(CXX [[ + #include + int main() { + pthread_create(0, 0, 0, 0); + } + ]] HAVE_PTHREAD_CREATE) + cmake_pop_check_state() + endif() + return (PROPAGATE HAVE_PTHREAD_CREATE) +endfunction() + +function(check_system) + check_cxx_symbol_exists(system "stdlib.h" HAVE_SYSTEM) +endfunction() + +function(check_popen) + check_cxx_symbol_exists(popen "stdio.h" HAVE_POPEN) + if (NOT HAVE_POPEN) + unset(HAVE_POPEN CACHE) + # https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/popen-wpopen + check_cxx_symbol_exists(_popen "stdio.h" HAVE_POPEN) + endif() +endfunction() diff --git a/cmake/Condition.cmake b/cmake/Condition.cmake new file mode 100644 index 000000000..6ef400a32 --- /dev/null +++ b/cmake/Condition.cmake @@ -0,0 +1,35 @@ +# Syntax: +# +# condition( ...) +# +# If `...` is truthful (evaluated as in `if()`) then assigns 1 to ``, else assigns 0. +# The assigned value is `0`/`1` rather than `TRUE`/`FALSE` for ease of use in generator expressions. +# Note that `...` *must* be unquoted. +# +# To understand how a certain outcome is reached, reconfigure the project with `--log-level VERBOSE`. +# +# Believe it or not, CMake doesn't have this built in! +# +macro(condition var) + if (${ARGN}) + set(${var} 1) + else() + set(${var} 0) + endif() + + set(_debug_expr) + foreach (token ${ARGN}) + if (DEFINED ${token}) + if (${${token}}) + list(APPEND _debug_expr "${token}:1") + else() + list(APPEND _debug_expr "${token}:0") + endif() + else() + list(APPEND _debug_expr "${token}") + endif() + endforeach() + string(JOIN " " _debug_expr ${_debug_expr}) + message(VERBOSE " ${var} = ${${var}} (${_debug_expr})") + unset(_debug_expr) +endmacro() diff --git a/cmake/FindDlfcn.cmake b/cmake/FindDlfcn.cmake new file mode 100644 index 000000000..201745a3f --- /dev/null +++ b/cmake/FindDlfcn.cmake @@ -0,0 +1,24 @@ +include(CMakePushCheckState) +include(CheckCXXSymbolExists) +include(FindPackageHandleStandardArgs) + +if (WIN32 OR MSYS) + # Windows; dlopen is available via a polyfill `libs/dlfcn-win32`. + set(Dlfcn_LIBRARIES dlfcn) +else() + # Unix and Wasm; dlopen may or may not be available depending on platform. + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS}) + check_cxx_symbol_exists(dlopen "dlfcn.h" HAVE_DLOPEN) + cmake_pop_check_state() + + if (HAVE_DLOPEN) + add_library(dlfcn INTERFACE) + target_link_libraries(dlfcn INTERFACE ${CMAKE_DL_LIBS}) + set(Dlfcn_LIBRARIES dlfcn) + endif() +endif() + +find_package_handle_standard_args(Dlfcn + REQUIRED_VARS Dlfcn_LIBRARIES +) diff --git a/cmake/FindPyosysEnv.cmake b/cmake/FindPyosysEnv.cmake new file mode 100644 index 000000000..be4672ef7 --- /dev/null +++ b/cmake/FindPyosysEnv.cmake @@ -0,0 +1,42 @@ +# We need a *third* `FindPython`-style call in this codebase because the host +# `Python3_EXECUTABLE` may not have pybind11 and cxxheaderparser installed, +# and installing it can be onerous. To work around this problem we try to detect +# whether the host interpreter has the necessary dependencies first, and if it +# does not, fall back to using `uv`. + +foreach (strategy host uv fail) + if (strategy STREQUAL "host") + set(PyosysEnv_PYTHON ${Python3_EXECUTABLE}) + elseif (strategy STREQUAL "uv") + set(PyosysEnv_PYTHON uv run --no-project --with pybind11>3,<4 --with cxxheaderparser python) + else() + set(PyosysEnv_PYTHON) + break() + endif() + + execute_process( + COMMAND ${PyosysEnv_PYTHON} -m pybind11 --includes + RESULT_VARIABLE result + OUTPUT_VARIABLE output + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + if (result EQUAL 0) + string(REGEX REPLACE " ?-I" ";" pybind11_INCLUDE_DIR "${output}") + list(FILTER pybind11_INCLUDE_DIR INCLUDE REGEX "/pybind11/") + + execute_process( + COMMAND ${PyosysEnv_PYTHON} ${CMAKE_SOURCE_DIR}/pyosys/generator.py --help + RESULT_VARIABLE result + OUTPUT_QUIET + ERROR_QUIET + ) + if (result EQUAL 0) + break() + endif() + endif() +endforeach() + +find_package_handle_standard_args(PyosysEnv + REQUIRED_VARS PyosysEnv_PYTHON pybind11_INCLUDE_DIR +) diff --git a/cmake/FindPython3Embed.cmake b/cmake/FindPython3Embed.cmake new file mode 100644 index 000000000..f3fda9070 --- /dev/null +++ b/cmake/FindPython3Embed.cmake @@ -0,0 +1,16 @@ +# Wrapper to improve behavior of `FindPython3` during cross-compilation. +# Does not entirely fix the problem; CMake 4.0 introduces `Python_ARTIFACTS_PREFIX`, which will. + +# Stash the package found status +get_property(packages_found GLOBAL PROPERTY PACKAGES_FOUND) +get_property(packages_not_found GLOBAL PROPERTY PACKAGES_NOT_FOUND) +get_property(required_version GLOBAL PROPERTY _CMAKE_Python3_REQUIRED_VERSION) + +# The `EXACT` specifier prevents the situation of `FindPython3` discovering a newer libpython-dev +# than the interpreter found in the past, rejecting it because it is too new, and giving up. +find_package(Python3 EXACT ${Python3_VERSION} COMPONENTS Development.Embed) +set(Python3Embed_FOUND ${Python3_Development.Embed_FOUND}) + +set_property(GLOBAL PROPERTY PACKAGES_FOUND "${packages_found}") +set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND "${packages_not_found}") +set_property(GLOBAL PROPERTY _CMAKE_Python3_REQUIRED_VERSION "${required_version}") diff --git a/cmake/PkgConfig.cmake b/cmake/PkgConfig.cmake new file mode 100644 index 000000000..b37d74622 --- /dev/null +++ b/cmake/PkgConfig.cmake @@ -0,0 +1,43 @@ +# Syntax: +# +# pkg_config_import() +# +# To use this command, `find_package(PkgConfig)` must be used beforehand, but it does +# not have to succeed. If the `PkgConfig` package is not found, all imports silently fail. +# +# Imports `` as a CMake `IMPORTED` target `PkgConfig::`. +# Updates the global `PACKAGES_FOUND` and `PACKAGES_NOT_FOUND` properties and defines +# the `_FOUND` variable. +# +function(pkg_config_import arg_PREFIX) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "MODULES") + if (NOT arg_MODULES) + set(arg_MODULES ${arg_PREFIX}) + endif() + + if (PkgConfig_FOUND) + # Once CMake 4.1 is available, this call should be replaced with `cmake_pkg_config()`. + pkg_check_modules(${arg_PREFIX} IMPORTED_TARGET ${arg_MODULES}) + if (${arg_PREFIX}_FOUND) + # We found the pkgconfig file, but is it actually a usable package? + # The main cause of failure here would be cross-compiling, which pkg-config does not + # handle very well (especially pre-`cmake_pkg_config()`). + try_compile(is_usable + SOURCE_FROM_CONTENT "main.cc" "int main() {}" + LINK_LIBRARIES PkgConfig::${arg_PREFIX} + LOG_DESCRIPTION "Checking if PkgConfig::${arg_PREFIX} is usable" + ) + if (NOT is_usable) + message(STATUS "Modules '${arg_MODULES}' unusable (bad \$PKG_CONFIG_LIBDIR?)") + set(${arg_PREFIX}_FOUND 0) + endif() + endif() + endif() + + if (${arg_PREFIX}_FOUND) + set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND ${arg_PREFIX}) + else() + set_property(GLOBAL APPEND PROPERTY PACKAGES_NOT_FOUND ${arg_PREFIX}) + endif() + return (PROPAGATE ${arg_PREFIX}_FOUND) +endfunction() diff --git a/cmake/PmgenCommand.cmake b/cmake/PmgenCommand.cmake new file mode 100644 index 000000000..889d7653e --- /dev/null +++ b/cmake/PmgenCommand.cmake @@ -0,0 +1,60 @@ +# Syntax: +# +# pmgen_command( +# [...] +# [PREFIX ] +# [DEBUG] +# ) +# +# Builds `_pm.h` in the current binary directory from pmgen source files ``, which must have +# the `*.pmg` extension. If `...` contains more than one file, `` must be provided. +# +# Defines the following variables: +# - `PMGEN__DEFINED`: Boolean indicating whether this command was successfully invoked. +# - `PMGEN__OUTPUT`: The header file generated by `pmgen`. +# +# Usage example: +# +# pmgen_command(my_dsp +# my_dsp.pmg +# ) +# yosys_pass(my_dsp +# my_dsp.cc +# ${PMGEN_my_dsp_OUTPUT} +# ) +# +# Usage example with multiple files: +# +# pmgen_command(my_dsp +# my_dsp_macc.pmg +# my_dsp_carry.pmg +# PREFIX +# my_dsp +# ) +# +function(pmgen_command arg_NAME) + cmake_parse_arguments(PARSE_ARGV 1 arg "DEBUG" "PREFIX" "") + set(arg_INPUTS ${arg_UNPARSED_ARGUMENTS}) + + set(pmgen_script ${CMAKE_SOURCE_DIR}/passes/pmgen/pmgen.py) + set(pmgen_output ${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}_pm.h) + cmake_path(RELATIVE_PATH pmgen_output BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE pmgen_output_rel) + add_custom_command( + DEPENDS ${pmgen_script} ${arg_INPUTS} + OUTPUT ${pmgen_output} + COMMAND ${Python3_EXECUTABLE} + ${pmgen_script} + "$<$:-g>" + "$<$:-p;${arg_PREFIX}>" + -o ${pmgen_output} + ${arg_INPUTS} + COMMAND_EXPAND_LISTS + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM + COMMENT "Compiling pattern matcher ${pmgen_output_rel}" + ) + + # The usage of this command is somewhat inspired by `flex_target()` and `bison_target()`. + set(PMGEN_${arg_NAME}_DEFINED TRUE) + set(PMGEN_${arg_NAME}_OUTPUT ${pmgen_output} PARENT_SCOPE) +endfunction() diff --git a/cmake/YosysAbc.cmake b/cmake/YosysAbc.cmake new file mode 100644 index 000000000..3b2267504 --- /dev/null +++ b/cmake/YosysAbc.cmake @@ -0,0 +1,96 @@ +include(CheckCompilerFlag) + +define_property(TARGET PROPERTY YOSYS_IS_ABC) + +function(target_safe_compile_options target scope) + foreach (lang C CXX) + foreach (flag ${ARGN}) + check_compiler_flag(${lang} ${flag} HAVE_${lang}_${flag}) + if (HAVE_${lang}_${flag}) + target_compile_options(${target} ${scope} $<$:${flag}>) + endif() + endforeach() + endforeach() +endfunction() + +function(_yosys_abc_extract_makefile result vardecl filename) + # Parse a Makefile fragment and extracts the first matching variable assignment into + # a list of values. + file(READ ${filename} contents) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filename}) + if ("${contents}" MATCHES "${vardecl}(\\\\\n|[ \t])*(([^\\\\\n]|\\\\\n)+)") + string(REGEX REPLACE "(\\\\\n|[ \t])+" ";" ${result} "${CMAKE_MATCH_2}") + endif() + return (PROPAGATE ${result}) +endfunction() + +function(yosys_abc_target arg_LIBNAME arg_EXENAME) + cmake_parse_arguments(PARSE_ARGV 2 arg "" "INSTALL_IF" "") + + # Instead of using either the ABC Make or CMake build system, we parse the source + # of truth: ABC's `module.make` files. This turns out to be quite trivial. + # This way, no assumptions about the environment are made, and Yosys can be compiled + # on Windows without MSYS as a result (while benefitting other platforms as well). + set(all_sources) + _yosys_abc_extract_makefile(module_files "MODULES :=" ${CMAKE_SOURCE_DIR}/abc/Makefile) + _yosys_abc_extract_makefile(module_files_cudd "MODULES \\+=" ${CMAKE_SOURCE_DIR}/abc/Makefile) + list(REMOVE_ITEM module_files "$(wildcard" "src/ext*)") + foreach (module_file ${module_files} ${module_files_cudd}) + _yosys_abc_extract_makefile(module_sources "SRC \\+=" ${CMAKE_SOURCE_DIR}/abc/${module_file}/module.make) + list(APPEND all_sources ${module_sources}) + endforeach() + list(TRANSFORM all_sources PREPEND abc/) + + # Required to get `-DABC_NAMESPACE` below to work consistently. + set_source_files_properties(${all_sources} PROPERTIES LANGUAGE CXX) + + set(main_source abc/src/base/main/main.c) + list(REMOVE_ITEM all_sources ${main_source}) + + find_package(Threads) + yosys_cxx_library(${arg_LIBNAME} STATIC + OUTPUT_NAME ${arg_LIBNAME} + ) + target_sources(${arg_LIBNAME} PRIVATE ${all_sources}) + target_include_directories(${arg_LIBNAME} PRIVATE abc/src) + target_compile_definitions(${arg_LIBNAME} PUBLIC + WIN32_NO_DLL + ABC_NAMESPACE=abc + ABC_USE_STDINT_H=1 + ABC_USE_CUDD=1 + ABC_NO_DYNAMIC_LINKING + $<${YOSYS_ENABLE_THREADS}:ABC_USE_PTHREADS> + $<${YOSYS_ENABLE_READLINE}:ABC_USE_READLINE> + ABC_NO_RLIMIT + ) + target_safe_compile_options(${arg_LIBNAME} PRIVATE + -fpermissive + -fno-exceptions + -Wno-write-strings + -Wno-changes-meaning + -Wno-attributes + -Wno-deprecated-declarations + -Wno-deprecated-comma-subscript + -Wno-format + -Wno-constant-logical-operand + ) + target_link_libraries(${arg_LIBNAME} PUBLIC + $<${YOSYS_ENABLE_THREADS}:Threads::Threads> + $<${YOSYS_ENABLE_READLINE}:PkgConfig::readline> + $<$:-lshlwapi> + ) + set_target_properties(${arg_LIBNAME} PROPERTIES + YOSYS_IS_ABC ON + ) + + yosys_cxx_executable(${arg_EXENAME} + OUTPUT_NAME ${arg_EXENAME} + INSTALL_IF "${arg_INSTALL_IF}" + ) + target_sources(${arg_EXENAME} PRIVATE ${main_source}) + target_include_directories(${arg_EXENAME} PRIVATE abc/src) + target_link_libraries(${arg_EXENAME} PRIVATE ${arg_LIBNAME}) + set_target_properties(${arg_EXENAME} PROPERTIES + YOSYS_IS_ABC ON + ) +endfunction() diff --git a/cmake/YosysAbcSubmodule.cmake b/cmake/YosysAbcSubmodule.cmake new file mode 100644 index 000000000..2a648a7e0 --- /dev/null +++ b/cmake/YosysAbcSubmodule.cmake @@ -0,0 +1,64 @@ +# depends on YosysVersion.cmake + +function(yosys_check_abc_submodule) + yosys_call_git(status) + set(yosys_status "tarball") + if (git_result EQUAL 0) + set(yosys_status "git") + endif() + + yosys_call_git(submodule status abc) + set(git_commit) + if (EXISTS "${CMAKE_SOURCE_DIR}/abc/.gitcommit") + file(READ "${CMAKE_SOURCE_DIR}/abc/.gitcommit" git_commit) + string(STRIP "${git_commit}" git_commit) + endif() + set(abc_status "none") + if (git_result EQUAL 0 AND git_output MATCHES "^ ") + set(abc_status "git") + elseif (git_result EQUAL 0 AND git_output MATCHES "^\\+") + set(abc_status "git-changed") + elseif (git_result EQUAL 0 AND git_output MATCHES "^U") + set(abc_status "git-conflict") + elseif (git_commit MATCHES "^[0-9a-fA-F]+$") + set(abc_status "tarball") + elseif (git_commit MATCHES "\\$Format:%[hH]\\$") + set(abc_status "unknown") + endif() + + if (abc_status STREQUAL "git" OR abc_status STREQUAL "tarball") + # Normal submodule or a tarball. + elseif (abc_status STREQUAL "git-changed") + message(FATAL_ERROR + "'abc' submodule does not match expected commit.\n" + "Run 'git submodule update' to check out the correct version.\n" + "Note: If testing a different version of ABC, call 'git commit abc' " + "in the Yosys source directory to update the expected commit.\n" + ) + elseif (abc_status STREQUAL "git-conflict") + message(FATAL_ERROR + "'abc' submodule has merge conflicts.\n" + "Please resolve merge conflicts before continuing.\n" + ) + elseif (abc_status STREQUAL "unknown") # OK + message(FATAL_ERROR + "Error: 'abc' is not configured as a git submodule.\n" + "To resolve this:\n" + "1. Back up your changes: Save any modifications from the 'abc' directory to another location.\n" + "2. Remove the existing 'abc' directory: Delete the 'abc' directory and all its contents.\n" + "3. Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule.\n" + "4. Reapply your changes: Move your saved changes back to the 'abc' directory, if necessary.\n" + ) + elseif (yosys_status STREQUAL "git") # OK + message(FATAL_ERROR + "Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule.\n" + ) + else() # + message(FATAL_ERROR + "${CMAKE_SOURCE_DIR} is not configured as a git repository, and 'abc' folder is missing.\n" + "If you already have ABC, set 'ABCEXTERNAL' make variable to point to ABC executable.\n" + "Otherwise, download release archive 'yosys.tar.gz' from https://github.com/YosysHQ/yosys/releases.\n" + " ('Source code' archive does not contain submodules.)\n" + ) + endif() +endfunction() diff --git a/cmake/YosysComponent.cmake b/cmake/YosysComponent.cmake new file mode 100644 index 000000000..9786ba156 --- /dev/null +++ b/cmake/YosysComponent.cmake @@ -0,0 +1,321 @@ +set(namespace "yosys") + +# Properties internal to the component system. +define_property(TARGET PROPERTY YOSYS_COMPONENT) +define_property(TARGET PROPERTY YOSYS_PROVIDES) +define_property(TARGET PROPERTY YOSYS_REQUIRES) +define_property(TARGET PROPERTY YOSYS_DATA_FILES) +define_property(TARGET PROPERTY YOSYS_ENABLE_IF) + +# Syntax: +# +# yosys_component( [INTERFACE] +# [...] +# [DEFINITIONS ...] +# [INCLUDE_DIRS ...] +# [LIBRARIES ...] +# [PROVIDES ...] +# [REQUIRES ...] +# [DATA_DIR ] +# [DATA_FILES ...] +# [DATA_EXPLICIT [ ]...] +# [ESSENTIAL] +# [ENABLE_IF ""] +# ) +# +# Creates a target `yosys_` (if `` is empty) or `yosys__` (if `` is not empty). +# This target is an library target with some Yosys-specific behavior that simplifies partitioning the compiler +# into small pieces with explicitly defined compile-time and run-time dependency metadata. Circular dependencies +# between compilation units in different components are allowed. +# +# Parameter description: +# - `INTERFACE` should be specified for header-only libraries. +# - `...` is a shortcut for `target_sources(PRIVATE)`. +# - `DEFINITIONS ...` is a shortcut for `target_compile_definitions(PRIVATE)`. +# - `INCLUDE_DIRS ...` is a shortcut for `target_include_directories(PRIVATE)`. +# - `LIBRARIES ...` is a shortcut for `target_link_libraries(PRIVATE)`. +# - `PROVIDES ...` creates aliases to each `` component name. +# - `REQUIRES ...` ensures that if this target is linked into the Yosys binary, then every +# `` component is also linked in. +# - `DATA_DIR ` configures a base directory for installing data files; this directory +# is (relative to the root build directory or the installation prefix) `share/` if +# `DATA_DIR` is provided, and `share` if not. +# - `DATA_FILES ...` installs each of `` as `share///`, +# where `` is the directory name of `` and `` is the filename of ``. +# - `DATA_EXPLICIT [ ]...` installs each `` as `share//`. +# Where possible, `DATA_FILES` should be used instead. +# - `ESSENTIAL` ensures that this target is always linked into the Yosys binary. +# - `ENABLE_IF ""` marks the component as available only when `if()` would run. +# +# Avoid using this function directly. Instead, use one of the wrappers below as follows: +# - to define a normal pass, use `yosys_pass()` to add a component called ``. +# - to define a test pass, use `yosys_test_pass()` to add a component called `test_`. +# - to define a frontend, use `yosys_frontend()` to add a component called `read_`. +# - to define a backend, use `yosys_backend()` to add a component called `write_`. +# - if the component sources define more than one pass, use `PROVIDES` with names of the other passes. +# - if the component uses `Pass::call()`, `Frontend::frontend_call()`, `Backend::backend_call()`, or other +# similar functions, use `REQUIRES` with names of all possibly needed passes. +# - if the component needs an essential pass, add the latter to `REQUIRES` anyway for completeness. +# - if the component subclasses a `ScriptPass`, build Yosys, then run `misc/script_pass_depends.py ` +# to extract the names of all referenced passes. +# - in general, component names should be the same as corresponding pass names (as used in the REPL), +# but this is not a hard requirement and any suitable name can be used if desired. +# +function(yosys_component arg_PREFIX arg_NAME) + cmake_parse_arguments(PARSE_ARGV 2 arg + "INTERFACE;ESSENTIAL;BOOTSTRAP" + "DATA_DIR;ENABLE_IF" + "DEFINITIONS;INCLUDE_DIRS;LIBRARIES;DATA_FILES;DATA_EXPLICIT;PROVIDES;REQUIRES" + ) + set(arg_SOURCES ${arg_UNPARSED_ARGUMENTS}) + if ("${arg_ENABLE_IF}" STREQUAL "") + set(arg_ENABLE_IF TRUE) + endif() + + if (arg_PREFIX STREQUAL "") + set(component "${arg_NAME}") + else() + set(component "${arg_PREFIX}_${arg_NAME}") + endif() + set(target "${namespace}_${component}") + list(TRANSFORM arg_PROVIDES PREPEND ${namespace}_ OUTPUT_VARIABLE provides_targets) + + # An OBJECT library is used to allow for circular symbol dependencies between any source files. + # Unfortunately, public dependencies between OBJECT libraries aren't handled correctly, so we have + # to do it ourselves. + if (arg_SOURCES AND NOT arg_INTERFACE) + add_library(${target} EXCLUDE_FROM_ALL OBJECT) + target_sources(${target} PRIVATE ${arg_SOURCES}) + target_include_directories(${target} PRIVATE ${arg_INCLUDE_DIRS}) + target_compile_definitions(${target} PRIVATE ${arg_DEFINITIONS}) + target_link_libraries(${target} PUBLIC yosys_common ${arg_LIBRARIES}) + foreach (alias ${provides_targets}) + add_library(${alias} ALIAS ${target}) + endforeach() + else() + add_library(${target} EXCLUDE_FROM_ALL INTERFACE) + endif() + set_target_properties(${target} PROPERTIES + YOSYS_COMPONENT YES + YOSYS_PROVIDES "${arg_PROVIDES}" + YOSYS_REQUIRES "${arg_REQUIRES}" + YOSYS_DATA_FILES "" + YOSYS_ENABLE_IF "${arg_ENABLE_IF}" + ) + + set(share_file_pairs) + foreach (share_file ${arg_DATA_FILES}) + list(APPEND share_file_pairs ${share_file} ${share_file}) + endforeach() + list(APPEND share_file_pairs ${arg_DATA_EXPLICIT}) + if (share_file_pairs) + set(data_depends) + set(share_root ${CMAKE_BINARY_DIR}/share) + while (share_file_pairs) + list(LENGTH share_file_pairs share_file_unpaired) + if (share_file_unpaired EQUAL 1) + message(FATAL_ERROR "Unpaired DATA_EXPLICIT argument: ${share_file_pairs}") + endif() + list(POP_FRONT share_file_pairs dst_file src_file) + cmake_path(ABSOLUTE_PATH src_file BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + set(out_dir ${arg_DATA_DIR}) + cmake_path(GET dst_file PARENT_PATH dst_parent) + cmake_path(APPEND out_dir ${dst_parent}) + cmake_path(GET dst_file FILENAME dst_filename) + cmake_path(APPEND out_dir ${dst_filename} OUTPUT_VARIABLE out_file) + file(MAKE_DIRECTORY ${share_root}/${out_dir}) + add_custom_command( + DEPENDS ${src_file} + OUTPUT ${share_root}/${out_file} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${share_root}/${out_file} + VERBATIM + COMMENT "Copying share/${out_file}" + ) + set_property(TARGET ${target} APPEND PROPERTY YOSYS_DATA_FILES ${out_file}) + list(APPEND data_depends ${share_root}/${out_file}) + endwhile() + add_custom_target(${target}-data DEPENDS ${data_depends}) + add_dependencies(${target} ${target}-data) + endif() + + if (NOT arg_BOOTSTRAP) + set_property(TARGET yosys_everything APPEND PROPERTY YOSYS_REQUIRES ${component}) + if (arg_ESSENTIAL) + set_property(TARGET yosys_essentials APPEND PROPERTY YOSYS_REQUIRES ${component}) + endif() + endif() +endfunction() + +# Syntax: +# +# yosys_core( [