From 95a2099c906feaa808345a01390afe3c83a41ae0 Mon Sep 17 00:00:00 2001 From: "Mike A." Date: Sun, 29 Sep 2024 17:15:59 +0200 Subject: [PATCH 01/58] Allow whitespace in `tee` command paths --- passes/cmds/tee.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc index 39ed4a7a8..853f1bad3 100644 --- a/passes/cmds/tee.cc +++ b/passes/cmds/tee.cc @@ -72,7 +72,9 @@ struct TeePass : public Pass { } if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) { const char *open_mode = args[argidx] == "-o" ? "w" : "a+"; - FILE *f = fopen(args[++argidx].c_str(), open_mode); + auto path = args[++argidx]; + rewrite_filename(path); + FILE *f = fopen(path.c_str(), open_mode); yosys_input_files.insert(args[argidx]); if (f == NULL) { for (auto cf : files_to_close) From 80dc94649953205134c5486a5c3ba370db949302 Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 29 Mar 2025 12:29:55 +1300 Subject: [PATCH 02/58] Makefile: Test yosys git status in check-git-abc As in #4986, `check-git-abc` is misleading if Yosys itself isn't a git repository. So check `git status` before suggesting `git` based solutions, providing alternative suggestions for using ABCEXTERNAL (which bypasses `check-git-abc`), or downloading release tar (noting that the 'Source code' archives won't work, which is probably how they ended up in this situtation). --- Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5745d1d0c..2e4db2456 100644 --- a/Makefile +++ b/Makefile @@ -785,7 +785,7 @@ $(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in $(YOSYS_SRC)/Makefile .PHONY: check-git-abc check-git-abc: - @if [ ! -d "$(YOSYS_SRC)/abc" ]; then \ + @if [ ! -d "$(YOSYS_SRC)/abc" ] && git -C "$(YOSYS_SRC)" status 2>/dev/null; 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; \ @@ -811,6 +811,12 @@ check-git-abc: 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 2>/dev/null; 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; \ From 2b3a148fc41f77e6933a97c964fb610d9dc313ab Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Sat, 5 Apr 2025 13:46:38 +0300 Subject: [PATCH 03/58] ice40_dsp: fix const handling --- techlibs/ice40/ice40_dsp.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/ice40/ice40_dsp.pmg b/techlibs/ice40/ice40_dsp.pmg index 63bc8de4b..2cfb97b2a 100644 --- a/techlibs/ice40/ice40_dsp.pmg +++ b/techlibs/ice40/ice40_dsp.pmg @@ -32,8 +32,8 @@ code sigA sigB sigH ++i; return sig.extract(0, i); }; - sigA = unextend(port(mul, \A)); - sigB = unextend(port(mul, \B)); + sigA = port(mul, \A).is_fully_const() ? port(mul, \A) : unextend(port(mul, \A)); + sigB = port(mul, \B).is_fully_const() ? port(mul, \B) : unextend(port(mul, \B)); SigSpec O; if (mul->type == $mul) From 41a7d4bb819c715cc428a482b938315f68c6b358 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Wed, 9 Apr 2025 21:21:46 +0300 Subject: [PATCH 04/58] ice40_dsp: add test --- tests/arch/ice40/ice40_dsp_const.ys | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/arch/ice40/ice40_dsp_const.ys diff --git a/tests/arch/ice40/ice40_dsp_const.ys b/tests/arch/ice40/ice40_dsp_const.ys new file mode 100644 index 000000000..c9c76a1ac --- /dev/null +++ b/tests/arch/ice40/ice40_dsp_const.ys @@ -0,0 +1,80 @@ +read_verilog << EOT +module top(input wire [14:0] a, output wire [18:0] b); +assign b = a*$unsigned(5'b01111); +endmodule +EOT + +prep +ice40_dsp + +read_verilog << EOT +module ref(a, b); + wire _0_; + wire _1_; + wire _2_; + wire [12:0] _3_; + (* src = "< Date: Thu, 10 Apr 2025 17:42:39 +0300 Subject: [PATCH 05/58] ice40_dsp: change unextend call condition --- techlibs/ice40/ice40_dsp.pmg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/ice40/ice40_dsp.pmg b/techlibs/ice40/ice40_dsp.pmg index 2cfb97b2a..ff7c5cb65 100644 --- a/techlibs/ice40/ice40_dsp.pmg +++ b/techlibs/ice40/ice40_dsp.pmg @@ -32,8 +32,8 @@ code sigA sigB sigH ++i; return sig.extract(0, i); }; - sigA = port(mul, \A).is_fully_const() ? port(mul, \A) : unextend(port(mul, \A)); - sigB = port(mul, \B).is_fully_const() ? port(mul, \B) : unextend(port(mul, \B)); + sigA = param(mul, \A_SIGNED).as_bool() ? unextend(port(mul, \A)) : port(mul, \A); + sigB = param(mul, \B_SIGNED).as_bool() ? unextend(port(mul, \B)) : port(mul, \B); SigSpec O; if (mul->type == $mul) From 163e339c692494133a4648fb157fabed8da9753b Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Fri, 11 Apr 2025 19:41:35 +0300 Subject: [PATCH 06/58] ice40_dsp: add unextend_unsigned function --- techlibs/ice40/ice40_dsp.pmg | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/techlibs/ice40/ice40_dsp.pmg b/techlibs/ice40/ice40_dsp.pmg index ff7c5cb65..7e4c3ace2 100644 --- a/techlibs/ice40/ice40_dsp.pmg +++ b/techlibs/ice40/ice40_dsp.pmg @@ -23,7 +23,7 @@ match mul endmatch code sigA sigB sigH - auto unextend = [](const SigSpec &sig) { + auto unextend_signed = [](const SigSpec &sig) { int i; for (i = GetSize(sig)-1; i > 0; i--) if (sig[i] != sig[i-1]) @@ -32,8 +32,16 @@ code sigA sigB sigH ++i; return sig.extract(0, i); }; - sigA = param(mul, \A_SIGNED).as_bool() ? unextend(port(mul, \A)) : port(mul, \A); - sigB = param(mul, \B_SIGNED).as_bool() ? unextend(port(mul, \B)) : port(mul, \B); + auto unextend_unsigned = [](const SigSpec &sig) { + int i; + for (i = GetSize(sig)-1; i > 0; i--) + if (sig[i] != SigBit(State::S0)) + break; + ++i; + return sig.extract(0, i); + }; + sigA = param(mul, \A_SIGNED).as_bool() ? unextend_signed(port(mul, \A)) : unextend_unsigned(port(mul, \A)); + sigB = param(mul, \B_SIGNED).as_bool() ? unextend_signed(port(mul, \B)) : unextend_unsigned(port(mul, \B)); SigSpec O; if (mul->type == $mul) From 22e6ce428229897837bd5d88287820ffe8f5c8b3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 14 Apr 2025 15:24:11 +0200 Subject: [PATCH 07/58] verific: bit blast RAM if using mem2reg attribute --- frontends/verific/verific.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 3418ebe50..95bede420 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1446,6 +1446,25 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma module_name = "\\" + sha1_if_contain_spaces(module_name); } + { + Array ram_nets ; + MapIter mem_mi; + Net *mem_net; + FOREACH_NET_OF_NETLIST(nl, mem_mi, mem_net) + { + if (!mem_net->IsRamNet()) continue ; + + if (mem_net->GetAtt("mem2reg")) + ram_nets.Insert(mem_net) ; + } + unsigned i ; + FOREACH_ARRAY_ITEM(&ram_nets, i, mem_net) { + log("Bit blasting RAM for identifier '%s'\n", mem_net->Name()); + mem_net->BlastNet(); + } + nl->RemoveDanglingLogic(0); + } + netlist = nl; if (design->has(module_name)) { From 21b93ee1fb36c25d240ea1146c3f4b7d9239881c Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 15 Apr 2025 09:38:04 +0200 Subject: [PATCH 08/58] fix sequential area not being included in addition/multiplication Fixes a bug where the sequential area isn't part of the Stat_numeric_members that are used to automatically add/mul the statdata_t members. --- passes/cmds/stat.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 7e51b6cb1..d68eda70a 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -40,7 +40,7 @@ struct statdata_t X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \ X(num_processes) - #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) + #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) X(sequential_area) #define X(_name) unsigned int _name; STAT_INT_MEMBERS From f8e67c7a081f2eaf3500b13e6f071e463da5bf8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 15 Apr 2025 10:31:42 +0200 Subject: [PATCH 09/58] satgen: Fix $macc_v2 x-prop --- kernel/satgen.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/satgen.cc b/kernel/satgen.cc index 9e5fa9111..a161adb5b 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -788,12 +788,18 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) { std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_c; + + if (cell->type == ID($macc_v2)) + undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep); int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + int undef_any_c = ez->expression(ezSAT::OpOr, undef_c); + int undef_any = ez->OR(undef_any_a, ez->OR(undef_any_b, undef_any_c)); std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - ez->assume(ez->vec_eq(undef_y, std::vector(GetSize(y), ez->OR(undef_any_a, undef_any_b)))); + ez->assume(ez->vec_eq(undef_y, std::vector(GetSize(y), undef_any))); undefGating(y, tmp, undef_y); } From 7191b9ad1fc1e999ffa377aaa2d04d4f87eb4c14 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 16 Apr 2025 22:24:55 +0200 Subject: [PATCH 10/58] liberty: fix tests --- tests/liberty/run-test.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh index 8fa99d419..1688b8df2 100755 --- a/tests/liberty/run-test.sh +++ b/tests/liberty/run-test.sh @@ -1,16 +1,17 @@ #!/usr/bin/env bash -set -e +set -eo pipefail for x in *.lib; do echo "Testing on $x.." ../../yosys -p "read_verilog small.v; synth -top small; dfflibmap -info -liberty ${x}" -ql ${x%.lib}.log ../../yosys-filterlib - $x 2>/dev/null > $x.filtered ../../yosys-filterlib -verilogsim $x > $x.verilogsim - diff $x.filtered $x.filtered.ok && diff $x.verilogsim $x.verilogsim.ok -done || exit 1 + diff $x.filtered $x.filtered.ok + diff $x.verilogsim $x.verilogsim.ok +done for x in *.ys; do echo "Running $x.." ../../yosys -q -s $x -l ${x%.ys}.log -done || exit 1 +done From 5db1765bee29f7f55fadba52ee86cf8f59583b3a Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Thu, 17 Apr 2025 18:17:42 +0200 Subject: [PATCH 11/58] add flatten -nocleanup option --- passes/techmap/flatten.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index 3425509b1..6363b3432 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -349,6 +349,10 @@ struct FlattenPass : public Pass { log(" -separator \n"); log(" Use this separator char instead of '.' when concatenating design levels.\n"); log("\n"); + log(" -nocleanup\n"); + log(" Don't remove unused submodules, leave a flattened version of each\n"); + log(" submodule in the design.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { @@ -360,6 +364,8 @@ struct FlattenPass : public Pass { if (design->scratchpad.count("flatten.separator")) worker.separator = design->scratchpad_get_string("flatten.separator"); + bool cleanup = true; + size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-wb") { @@ -378,6 +384,10 @@ struct FlattenPass : public Pass { worker.separator = args[++argidx]; continue; } + if (args[argidx] == "-nocleanup") { + cleanup = false; + continue; + } break; } extra_args(args, argidx, design); @@ -414,7 +424,7 @@ struct FlattenPass : public Pass { for (auto module : topo_modules.sorted) worker.flatten_module(design, module, used_modules, worker.separator); - if (top != nullptr) + if (cleanup && top != nullptr) for (auto module : design->modules().to_vector()) if (!used_modules[module] && !module->get_blackbox_attribute(worker.ignore_wb)) { log("Deleting now unused module %s.\n", log_id(module)); From c343462c16e9bebc6dd3d487121173d89c7ceb6e Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 18 Apr 2025 14:16:02 +0200 Subject: [PATCH 12/58] gatemate: WRITE_THROUGH mode change --- techlibs/gatemate/brams.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/techlibs/gatemate/brams.txt b/techlibs/gatemate/brams.txt index be22856ac..d39aafcbf 100644 --- a/techlibs/gatemate/brams.txt +++ b/techlibs/gatemate/brams.txt @@ -34,7 +34,6 @@ ram block $__CC_BRAM_TDP_ { } portoption "WR_MODE" "WRITE_THROUGH" { rdwr new; - wrtrans all new; } wrbe_separate; optional_rw; From bd154a71889b67a71b1d788ad81d15d79ea1334a Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 26 Nov 2024 17:20:34 +0100 Subject: [PATCH 13/58] formalff: Add -declockgate option --- passes/sat/formalff.cc | 214 +++++++++++++++++++++++++- tests/various/formalff_declockgate.ys | 79 ++++++++++ 2 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 tests/various/formalff_declockgate.ys diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc index f81d492c8..3ebae4bc4 100644 --- a/passes/sat/formalff.cc +++ b/passes/sat/formalff.cc @@ -22,6 +22,7 @@ #include "kernel/ffinit.h" #include "kernel/ff.h" #include "kernel/modtools.h" +#include "kernel/mem.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -549,6 +550,7 @@ struct FormalFfPass : public Pass { bool flag_setundef = false; bool flag_hierarchy = false; bool flag_assume = false; + bool flag_declockgate = false; log_header(design, "Executing FORMALFF pass.\n"); @@ -583,22 +585,232 @@ struct FormalFfPass : public Pass { flag_assume = true; continue; } + if (args[argidx] == "-declockgate") { + flag_declockgate = true; + continue; + } break; } extra_args(args, argidx, design); - if (!(flag_clk2ff || flag_ff2anyinit || flag_anyinit2ff || flag_hierarchy || flag_assume)) + if (!(flag_clk2ff || flag_ff2anyinit || flag_anyinit2ff || flag_hierarchy || flag_assume || flag_declockgate)) log_cmd_error("One of the options -clk2ff, -ff2anyinit, -anyinit2ff, -hierarchy or -assume must be specified.\n"); if (flag_ff2anyinit && flag_anyinit2ff) log_cmd_error("The options -ff2anyinit and -anyinit2ff are exclusive.\n"); + if (flag_ff2anyinit && flag_declockgate) + log_cmd_error("The options -ff2anyinit and -declockgate are exclusive.\n"); + if (flag_fine && !flag_anyinit2ff) log_cmd_error("The option -fine requries the -anyinit2ff option.\n"); if (flag_fine && flag_clk2ff) log_cmd_error("The options -fine and -clk2ff are exclusive.\n"); + if (flag_declockgate) + { + for (auto module : design->selected_modules()) + { + ModWalker modwalker(design); + modwalker.setup(module); + SigMap &sigmap = modwalker.sigmap; + FfInitVals initvals(&modwalker.sigmap, module); + + dict memories; + + for (auto mem : Mem::get_selected_memories(module)) { + if (!mem.packed) + continue; + memories.emplace(mem.cell->name, std::move(mem)); + } + + dict, vector> clk_bits; + pool input_bits; + pool> input_clk_bits; + for (auto cell : module->selected_cells()) { + if (RTLIL::builtin_ff_cell_types().count(cell->type)) { + FfData ff(&initvals, cell); + if (!ff.has_clk) + continue; + SigBit clk = sigmap(ff.sig_clk); + clk_bits[{clk, ff.pol_clk}].push_back(cell); + } else if (cell->type == ID($mem_v2)) { + auto const &mem = memories.at(cell->name); + for (auto &rd_port : mem.rd_ports) + if (rd_port.clk_enable) + clk_bits[{rd_port.clk, rd_port.clk_polarity}].push_back(mem.cell); + for (auto &wr_port : mem.wr_ports) + if (wr_port.clk_enable) + clk_bits[{wr_port.clk, wr_port.clk_polarity}].push_back(mem.cell); + } + // XXX $check $print + } + + log_debug("%s has %d clk bits\n", log_id(module), GetSize(clk_bits)); + + for (auto port : module->ports) { + Wire *wire = module->wire(port); + if (!wire->port_input) + continue; + for (auto bit : SigSpec(wire)) { + input_bits.insert(bit); + for (bool pol : {false, true}) { + if (clk_bits.count({bit, pol})) { + input_clk_bits.insert({bit, pol}); + clk_bits.erase({bit, pol}); + } + } + } + } + log_debug("%s has %d non-input clk bits\n", log_id(module), GetSize(clk_bits)); + + if (clk_bits.empty()) + continue; + + for (auto &clk_bit : clk_bits) + { + SigBit clk = clk_bit.first.first; + bool pol_clk = clk_bit.first.second; + vector &clocked_cells = clk_bit.second; + + if (!clk.is_wire()) { + log_debug("constant clk bit %s.%s\n", log_id(module), log_signal(SigSpec(clk))); + continue; + } + if (input_bits.count(clk)) { + log_debug("input clk bit %s.%s\n", log_id(module), log_signal(SigSpec(clk))); + continue; + } + auto found = modwalker.signal_drivers.find(clk); + if (found == modwalker.signal_drivers.end() || found->second.empty()) { + log_debug("undriven clk bit %s.%s\n", log_id(module), log_signal(SigSpec(clk))); + continue; + } + + if (found->second.size() > 1) { + log_debug("multiple drivers for clk bit %s.%s\n", log_id(module), log_signal(SigSpec(clk))); + continue; + } + + auto driver = *found->second.begin(); + + bool is_gate = + pol_clk ? driver.cell->type.in(ID($and), ID($_AND_)) : driver.cell->type.in(ID($or), ID($_OR_)); + + if (!is_gate) { + log_debug("unsupported gating logic %s.%s (%s) for clock %s %s.%s\n", log_id(module), + log_id(driver.cell), log_id(driver.cell->type), pol_clk ? "posedge" : "negedge", + log_id(module), log_signal(SigSpec(clk))); + + continue; + } + SigBit gate_clock = sigmap(driver.cell->getPort(ID::A)[driver.offset]); + SigBit gate_enable = sigmap(driver.cell->getPort(ID::B)[driver.offset]); + + std::swap(gate_clock, gate_enable); + for (int i = 0; i < 2; i++) { + std::swap(gate_clock, gate_enable); + + log_debug("clock %s.%s for gated clk bit %s.%s\n", log_id(module), log_signal(SigSpec(gate_clock)), + log_id(module), log_signal(SigSpec(clk))); + log_debug("enable %s.%s for gated clk bit %s.%s\n", log_id(module), log_signal(SigSpec(gate_enable)), + log_id(module), log_signal(SigSpec(clk))); + + found = modwalker.signal_drivers.find(gate_enable); + if (found == modwalker.signal_drivers.end() || found->second.empty()) { + log_debug("undriven gate enable %s.%s of gated clk bit %s.%s\n", log_id(module), + log_signal(SigSpec(gate_enable)), log_id(module), log_signal(SigSpec(clk))); + continue; + } + if (found->second.size() > 1) { + log_debug("multiple drivers for gate enable %s.%s of gated clk bit %s.%s\n", log_id(module), + log_signal(SigSpec(gate_enable)), log_id(module), log_signal(SigSpec(clk))); + continue; + } + + auto gate_driver = *found->second.begin(); + + if (!RTLIL::builtin_ff_cell_types().count(gate_driver.cell->type)) { + log_debug("non FF driver for gate enable %s.%s of gated clk bit %s.%s\n", log_id(module), + log_signal(SigSpec(gate_enable)), log_id(module), log_signal(SigSpec(clk))); + continue; + } + + FfData ff(&initvals, gate_driver.cell); + if (ff.has_gclk || ff.has_ce || ff.has_sr || ff.has_srst || ff.has_arst || (ff.has_aload && ff.has_clk)) { + log_debug( + "FF driver for gate enable %s.%s of gated clk bit %s.%s has incompatible type: %s\n", + log_id(module), log_signal(SigSpec(gate_enable)), log_id(module), log_signal(SigSpec(clk)), + log_id(gate_driver.cell->type)); + continue; + } + + if (ff.has_aload) { + // this ff is intentionally not emitted! + ff.has_aload = false; + ff.has_clk = true; + ff.pol_clk = !ff.pol_arst; + ff.sig_clk = ff.sig_aload; + ff.sig_d = ff.sig_ad; + } + + if (!ff.has_clk || sigmap(ff.sig_clk) != gate_clock || ff.pol_clk != pol_clk) { + log_debug("FF driver for gate enable %s.%s of gated clk bit %s.%s has incompatible clocking: " + "%s %s.%s\n", + log_id(module), log_signal(SigSpec(gate_enable)), log_id(module), + log_signal(SigSpec(clk)), ff.pol_clk ? "posedge" : "negedge", log_id(module), + log_signal(SigSpec(ff.sig_clk))); + continue; + } + + SigBit sig_gate = ff.sig_d[gate_driver.offset]; + + log_debug("found clock gate, rewriting %d cells\n", GetSize(clocked_cells)); + + for (auto clocked_cell : clocked_cells) { + log_debug("rewriting cell %s.%s (%s)\n", log_id(module), log_id(clocked_cell), + log_id(clocked_cell->type)); + + if (RTLIL::builtin_ff_cell_types().count(clocked_cell->type)) { + + FfData ff(&initvals, clocked_cell); + log_assert(ff.has_clk); + ff.unmap_ce(); + ff.pol_ce = pol_clk; + ff.sig_ce = sig_gate; + ff.has_ce = true; + ff.sig_clk = gate_clock; + ff.emit(); + } else if (clocked_cell->type == ID($mem_v2)) { + auto &mem = memories.at(clocked_cell->name); + for (auto &rd_port : mem.rd_ports) { + if (rd_port.clk_enable && rd_port.clk == clk && rd_port.clk_polarity == pol_clk) { + log_warning("patching rd port\n"); + rd_port.clk = gate_clock; + SigBit en_bit = pol_clk ? sig_gate : SigBit(module->Not(NEW_ID, sig_gate)); + SigSpec en_mask = SigSpec(en_bit, GetSize(rd_port.en)); + rd_port.en = module->And(NEW_ID, rd_port.en, en_mask); + } + } + for (auto &wr_port : mem.wr_ports) { + if (wr_port.clk_enable && wr_port.clk == clk && wr_port.clk_polarity == pol_clk) { + log_warning("patching wr port\n"); + wr_port.clk = gate_clock; + SigBit en_bit = pol_clk ? sig_gate : SigBit(module->Not(NEW_ID, sig_gate)); + SigSpec en_mask = SigSpec(en_bit, GetSize(wr_port.en)); + wr_port.en = module->And(NEW_ID, wr_port.en, en_mask); + } + } + } + } + + break; + } + } + } + } + for (auto module : design->selected_modules()) { if (flag_setundef) diff --git a/tests/various/formalff_declockgate.ys b/tests/various/formalff_declockgate.ys new file mode 100644 index 000000000..30067b9d5 --- /dev/null +++ b/tests/various/formalff_declockgate.ys @@ -0,0 +1,79 @@ +# based on the peepopt_formal.ys test +read_verilog -sv < Date: Wed, 12 Feb 2025 17:45:02 +0100 Subject: [PATCH 14/58] formalff: Document -declockgate option --- passes/sat/formalff.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc index 3ebae4bc4..a04ab064c 100644 --- a/passes/sat/formalff.cc +++ b/passes/sat/formalff.cc @@ -538,6 +538,12 @@ struct FormalFfPass : public Pass { log(" Add assumptions that constrain wires with the 'replaced_by_gclk'\n"); log(" attribute to the value they would have before an active clock edge.\n"); log("\n"); + log(" -declockgate\n"); + log(" Detect clock-gating patterns and modify any FFs clocked by the gated\n"); + log(" clock to use the ungated clock with the gate signal as clock enable.\n"); + log(" This doesn't affect the design's behavior during FV but can enable the\n"); + log(" use of formal verification methods that only support a single global\n"); + log(" clock.\n"); // TODO: An option to check whether all FFs use the same clock before changing it to the global clock } From 31d6d0ac173903d8909d318924b8872e0235f5db Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 18 Apr 2025 18:57:59 +0200 Subject: [PATCH 15/58] formalff: Fix -declockgate test and missing emit for memories --- passes/sat/formalff.cc | 9 +++++++-- tests/various/formalff_declockgate.ys | 12 ++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/passes/sat/formalff.cc b/passes/sat/formalff.cc index a04ab064c..1d87fcc3b 100644 --- a/passes/sat/formalff.cc +++ b/passes/sat/formalff.cc @@ -790,9 +790,11 @@ struct FormalFfPass : public Pass { ff.emit(); } else if (clocked_cell->type == ID($mem_v2)) { auto &mem = memories.at(clocked_cell->name); + bool changed = false; for (auto &rd_port : mem.rd_ports) { if (rd_port.clk_enable && rd_port.clk == clk && rd_port.clk_polarity == pol_clk) { - log_warning("patching rd port\n"); + log_debug("patching rd port\n"); + changed = true; rd_port.clk = gate_clock; SigBit en_bit = pol_clk ? sig_gate : SigBit(module->Not(NEW_ID, sig_gate)); SigSpec en_mask = SigSpec(en_bit, GetSize(rd_port.en)); @@ -801,13 +803,16 @@ struct FormalFfPass : public Pass { } for (auto &wr_port : mem.wr_ports) { if (wr_port.clk_enable && wr_port.clk == clk && wr_port.clk_polarity == pol_clk) { - log_warning("patching wr port\n"); + log_debug("patching wr port\n"); + changed = true; wr_port.clk = gate_clock; SigBit en_bit = pol_clk ? sig_gate : SigBit(module->Not(NEW_ID, sig_gate)); SigSpec en_mask = SigSpec(en_bit, GetSize(wr_port.en)); wr_port.en = module->And(NEW_ID, wr_port.en, en_mask); } } + if (changed) + mem.emit(); } } diff --git a/tests/various/formalff_declockgate.ys b/tests/various/formalff_declockgate.ys index 30067b9d5..3dd47ea78 100644 --- a/tests/various/formalff_declockgate.ys +++ b/tests/various/formalff_declockgate.ys @@ -58,16 +58,20 @@ EOT prep -auto-top opt_dff select -assert-count 1 t:$dlatch -select -assert-count 1 t:$dff -select -assert-count 1 t:$dffe # Manually execute equiv_opt like pattern so clk2fflogic is called with # -nopeepopt, otherwise this doesn't test everything design -save preopt check -assert formalff -declockgate -check -assert -design -stash postopt + +design -save postopt + +delete -output */clk_o +clean -purge +select -assert-count 0 t:$dlatch + +design -reset # Create miter and clk2fflogic without peepopt design -copy-from preopt -as gold A:top From 01d80c74038dfb727e2ee19af53b813c4de364ef Mon Sep 17 00:00:00 2001 From: clemens Date: Sat, 19 Apr 2025 20:41:10 +0200 Subject: [PATCH 16/58] add testcase --- tests/various/stat.ys | 49 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/tests/various/stat.ys b/tests/various/stat.ys index ad96fe8d4..7c8700494 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -1,4 +1,4 @@ -read_rtlil << EOF +read_rtlil << EOT module \top wire input 1 \A wire output 2 \Y @@ -8,7 +8,52 @@ module \top connect \Y \Y end end -EOF +EOT logger -expect log "Chip area for module '\\top': 9.072000" 1 logger -expect-no-warnings stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz + + +design -reset +read_rtlil < Date: Sun, 20 Apr 2025 16:44:22 +0200 Subject: [PATCH 17/58] create testcase to check correct addition of areas. --- tests/various/stat.ys | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/tests/various/stat.ys b/tests/various/stat.ys index 7c8700494..cf084a986 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -15,20 +15,35 @@ stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib. design -reset -read_rtlil < Date: Tue, 22 Apr 2025 00:54:51 +0800 Subject: [PATCH 18/58] Fixed the problem of not calling abc correctly when using libyosys.so library (it will try to call yosys-abc as command line instead of calling abc::Abc_RealMain) --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 76ac4bb18..94dfe3993 100644 --- a/Makefile +++ b/Makefile @@ -396,6 +396,10 @@ 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 From 1788ffcaf7ba4bbdc7be8614dec30ad7ebc97384 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 00:23:01 +0000 Subject: [PATCH 19/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 76ac4bb18..e1483dbfe 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+63 +YOSYS_VER := 0.52+75 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) From 7f8d0e31f69601534d5680e5f78832cd57210ffb Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 22 Apr 2025 17:42:52 +1200 Subject: [PATCH 20/58] Fix #5046 `clean_zerowidth` had skipped $macc, but not $macc_v2 --- passes/cmds/clean_zerowidth.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/clean_zerowidth.cc b/passes/cmds/clean_zerowidth.cc index a15be8a39..48a8864c0 100644 --- a/passes/cmds/clean_zerowidth.cc +++ b/passes/cmds/clean_zerowidth.cc @@ -128,7 +128,7 @@ struct CleanZeroWidthPass : public Pass { // A and B to 1-bit if their width is 0. if (cell->getParam(ID::Y_WIDTH).as_int() == 0) { module->remove(cell); - } else if (cell->type == ID($macc)) { + } else if (cell->type.in(ID($macc), ID($macc_v2))) { // TODO: fixing zero-width A and B not supported. } else { if (cell->getParam(ID::A_WIDTH).as_int() == 0) { From 386b33d192902210144b8a5a7c4cf9fe543c7458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 31 May 2024 18:51:18 +0200 Subject: [PATCH 21/58] timeest: Add command for critical path estimation --- passes/cmds/Makefile.inc | 1 + passes/cmds/timeest.cc | 361 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 362 insertions(+) create mode 100644 passes/cmds/timeest.cc diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index af7e1bca6..4ecaea7dd 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -55,3 +55,4 @@ OBJS += passes/cmds/wrapcell.o OBJS += passes/cmds/setenv.o OBJS += passes/cmds/abstract.o OBJS += passes/cmds/test_select.o +OBJS += passes/cmds/timeest.o diff --git a/passes/cmds/timeest.cc b/passes/cmds/timeest.cc new file mode 100644 index 000000000..1a54360cc --- /dev/null +++ b/passes/cmds/timeest.cc @@ -0,0 +1,361 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Martin Povišer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/sigtools.h" +#include "kernel/register.h" +#include "kernel/cellaigs.h" +#include "kernel/utils.h" +#include "kernel/ff.h" +#include "kernel/mem.h" + +#include + +USING_YOSYS_NAMESPACE +template<> struct hash_ops : hash_ptr_ops {}; + +PRIVATE_NAMESPACE_BEGIN + +typedef long int arrivalint; +const arrivalint INF_PAST = std::numeric_limits::min(); + +// each clock domain must have its own EstimateSta structure +struct EstimateSta { + SigMap sigmap; + Module *m; + SigBit clk; + + dict>, Aig> aigs; + dict cell_aigs; + + std::vector> launchers; + std::vector> samplers; + bool all_paths = false; + + void add_seq(Cell *cell, SigSpec launch, SigSpec sample) + { + sigmap.apply(launch); + sigmap.apply(sample); + launch.sort_and_unify(); + sample.sort_and_unify(); + for (auto bit : launch) + launchers.push_back(std::make_pair(cell, bit)); + for (auto bit : sample) + samplers.push_back(std::make_pair(cell, bit)); + } + + int cell_type_factor(IdString type) + { + if (type.in(ID($gt), ID($ge), ID($lt), ID($le), ID($add), ID($sub), + ID($logic_not), ID($reduce_and), ID($reduce_or), ID($eq))) + return 1; + else + return 2; + } + + // TODO: ignores clock polarity + EstimateSta(Module *m, SigBit clk) + : sigmap(m), m(m), clk(clk) + { + sigmap.apply(clk); + } + + void run() + { + log("Domain %s\n", log_signal(clk)); + + std::vector combinational; + + for (auto cell : m->cells()) { + SigSpec launch, sample; + if (RTLIL::builtin_ff_cell_types().count(cell->type)) { + FfData ff(nullptr, cell); + if (!ff.has_clk) { + log_warning("Ignoring unsupported storage element '%s' (%s)\n", + log_id(cell), log_id(cell->type)); + continue; + } + if (ff.sig_clk != clk) + continue; + launch.append(ff.sig_q); + sample.append(ff.sig_d); + if (ff.has_ce) + sample.append(ff.sig_ce); + if (ff.has_srst) + sample.append(ff.sig_srst); + add_seq(cell, launch, sample); + } else if (cell->is_mem_cell()) { + // memories handled separately + continue; + } else if (cell->type == ID($scopeinfo)) { + continue; + } else { + auto fingerprint = std::make_pair(cell->type, cell->parameters); + if (!aigs.count(fingerprint)) { + aigs.emplace(fingerprint, Aig(cell)); + if (aigs.at(fingerprint).name.empty()) { + log_error("Unsupported cell '%s' in module '%s'", + log_id(cell->type), log_id(m)); + } + } + + combinational.push_back(cell); + continue; + } + } + + for (auto cell : combinational) { + auto fingerprint = std::make_pair(cell->type, cell->parameters); + cell_aigs.emplace(cell, &aigs.at(fingerprint)); + } + + for (auto &mem : Mem::get_all_memories(m)) { + for (auto &rd : mem.rd_ports) { + if (!rd.clk_enable) { + log_error("Unsupported async memory port '%s'\n", log_id(rd.cell)); + continue; + } + if (sigmap(rd.clk) != clk) + continue; + add_seq(rd.cell, rd.data, {rd.addr, rd.srst, rd.en}); + } + for (auto &wr : mem.wr_ports) { + if (sigmap(wr.clk) != clk) + continue; + add_seq(wr.cell, {}, {wr.en, wr.addr, wr.data}); + } + } + + TopoSort> topo; + + auto desc_aig = [&](Cell *cell, AigNode &node) { + return std::make_tuple(RTLIL::S0, cell, &node); + }; + auto desc_sig = [&](SigBit bit) { + return std::make_tuple(sigmap(bit), (Cell *) NULL, (AigNode *) NULL); + }; + + for (auto cell : combinational) { + assert(cell_aigs.count(cell)); + Aig &aig = *cell_aigs.at(cell); + for (auto &node : aig.nodes) { + if (!node.portname.empty()) { + topo.edge( + desc_sig(cell->getPort(node.portname)[node.portbit]), + desc_aig(cell, node) + ); + } else if (node.left_parent < 0 && node.right_parent < 0) { + // constant, nothing to do + } else { + topo.edge( + desc_aig(cell, aig.nodes[node.left_parent]), + desc_aig(cell, node) + ); + topo.edge( + desc_aig(cell, aig.nodes[node.right_parent]), + desc_aig(cell, node) + ); + } + + for (auto &oport : node.outports) { + topo.edge( + desc_aig(cell, node), + desc_sig(cell->getPort(oport.first)[oport.second]) + ); + } + } + } + + if (!topo.sort()) + log_error("Module '%s' contains combinational loops", log_id(m)); + + dict, arrivalint> levels; + + for (auto node : topo.sorted) + levels[node] = INF_PAST; + + for (auto pair : launchers) + levels[desc_sig(pair.second)] = 0; + + for (auto node : topo.sorted) { + AigNode *aig_node = std::get<2>(node); + if (aig_node) { + Cell *cell = std::get<1>(node); + Aig &aig = *cell_aigs.at(cell); + if (!aig_node->portname.empty()) { + SigBit bit = cell->getPort(aig_node->portname)[aig_node->portbit]; + levels[node] = levels[desc_sig(bit)]; + } else if (aig_node->left_parent < 0 && aig_node->right_parent < 0) { + // constant, nothing to do + } else { + int left = levels[desc_aig(cell, aig.nodes[aig_node->left_parent])]; + int right = levels[desc_aig(cell, aig.nodes[aig_node->right_parent])]; + levels[node] = (std::max(left, right) + cell_type_factor(cell->type)); + } + + for (auto &oport : aig_node->outports) { + levels[desc_sig(cell->getPort(oport.first)[oport.second])] = levels[node]; + } + } + } + + arrivalint crit = INF_PAST; + for (auto pair : samplers) + if (levels[desc_sig(pair.second)] > crit) + crit = levels[desc_sig(pair.second)]; + + if (crit < 0) { + log("No paths found\n"); + return; + } + + log("Critical path is %ld nodes long:\n\n", crit); + + // we use dict instead of pool because dict gives us + // some compile-time errors related to hashing + dict, bool> critical; + + for (auto pair : samplers) { + if (levels[desc_sig(pair.second)] == crit) { + critical[desc_sig(pair.second)] = true; + if (!all_paths) + break; + } + } + + for (auto it = topo.sorted.rbegin(); it != topo.sorted.rend(); it++) { + auto node = *it; + AigNode *aig_node = std::get<2>(node); + if (aig_node) { + Cell *cell = std::get<1>(node); + Aig &aig = *cell_aigs.at(cell); + + for (auto &oport : aig_node->outports) { + //levels[desc_sig(cell->getPort(oport.first)[oport.second])] = levels[node]; + if (critical.count(desc_sig(cell->getPort(oport.first)[oport.second]))) + critical[node] = true; + } + + if (!aig_node->portname.empty()) { + SigBit bit = cell->getPort(aig_node->portname)[aig_node->portbit]; + //levels[node] = levels[desc_sig(bit)]; + if (critical.count(node)) + critical[desc_sig(bit)] = true; + } else if (aig_node->left_parent < 0 && aig_node->right_parent < 0) { + // constant, nothing to do + } else { + auto left = desc_aig(cell, aig.nodes[aig_node->left_parent]); + auto right = desc_aig(cell, aig.nodes[aig_node->right_parent]); + //levels[node] = (std::max(left, right) + 1); + int crit_input_lvl = levels[node] - cell_type_factor(cell->type); + if (critical.count(node)) { + bool left_critical = (levels[left] == crit_input_lvl); + bool right_critical = (levels[right] == crit_input_lvl); + if (all_paths) { + if (left_critical) + critical[left] = true; + if (right_critical) + critical[right] = true; + } else { + if (left_critical) + critical[left] = true; + else if (right_critical) + critical[right] = true; + } + } + } + } + } + + pool printed; + for (auto node : topo.sorted) { + if (!critical.count(node)) + continue; + AigNode *aig_node = std::get<2>(node); + if (aig_node) { + Cell *cell = std::get<1>(node); + if (!printed.count(cell)) { + std::string cell_src; + if (cell->has_attribute(ID::src)) { + std::string src_attr = cell->get_src_attribute(); + cell_src = stringf(" source: %s", src_attr.c_str()); + } + log(" cell %s (%s)%s\n", log_id(cell), log_id(cell->type), cell_src.c_str()); + printed.insert(cell); + } + } else { + SigBit bit = std::get<0>(node); + std::string wire_src; + if (bit.wire && bit.wire->has_attribute(ID::src)) { + std::string src_attr = bit.wire->get_src_attribute(); + wire_src = stringf(" source: %s", src_attr.c_str()); + } + log(" wire %s%s (level %ld)\n", log_signal(bit), wire_src.c_str(), levels[node]); + } + } + } +}; + +struct TimeestPass : Pass { + TimeestPass() : Pass("timeest", "estimate timing") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" timeest [-clk ] [selection]\n"); + log("\n"); + log("Estimate the critical path in clock domain by counting AIG nodes.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *d) override + { + log_header(d, "Executing TIMEEST pass. (estimate timing)\n"); + + std::string clk; + bool all_paths = false; + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-all_paths") { + all_paths = true; + continue; + } + if (args[argidx] == "-clk" && argidx + 1 < args.size()) { + clk = args[++argidx]; + continue; + } + break; + } + extra_args(args, argidx, d); + + if (clk.empty()) + log_cmd_error("No -clk argument provided\n"); + + for (auto m : d->selected_modules()) { + if (!m->wire(RTLIL::escape_id(clk))) { + log_warning("No domain '%s' in module %s\n", clk.c_str(), log_id(m)); + continue; + } + + EstimateSta sta(m, SigBit(m->wire(RTLIL::escape_id(clk)), 0)); + sta.all_paths = all_paths; + sta.run(); + } + } +} TimeestPass; + +PRIVATE_NAMESPACE_END From 4323d56b9e286f2b0cf4c7742f0ed27c8513af2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 31 May 2024 18:55:29 +0200 Subject: [PATCH 22/58] timeest: Fill missing header --- passes/cmds/timeest.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/cmds/timeest.cc b/passes/cmds/timeest.cc index 1a54360cc..dec7f5237 100644 --- a/passes/cmds/timeest.cc +++ b/passes/cmds/timeest.cc @@ -25,6 +25,7 @@ #include "kernel/mem.h" #include +#include USING_YOSYS_NAMESPACE template<> struct hash_ops : hash_ptr_ops {}; From c5e154e941094924846e1ed53a4861c5419f6f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 31 May 2024 19:07:10 +0200 Subject: [PATCH 23/58] timeest: Fix templating --- passes/cmds/timeest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/timeest.cc b/passes/cmds/timeest.cc index dec7f5237..e815e32f7 100644 --- a/passes/cmds/timeest.cc +++ b/passes/cmds/timeest.cc @@ -28,7 +28,7 @@ #include USING_YOSYS_NAMESPACE -template<> struct hash_ops : hash_ptr_ops {}; +template<> struct ::Yosys::hashlib::hash_ops : Yosys::hashlib::hash_ptr_ops {}; PRIVATE_NAMESPACE_BEGIN From e8196b1dda5b454d1c117fbfd98ececaf2c22f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 22 Aug 2024 10:21:10 +0200 Subject: [PATCH 24/58] timeest: Update help --- passes/cmds/timeest.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/passes/cmds/timeest.cc b/passes/cmds/timeest.cc index e815e32f7..82867d84c 100644 --- a/passes/cmds/timeest.cc +++ b/passes/cmds/timeest.cc @@ -318,10 +318,14 @@ struct TimeestPass : Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" timeest [-clk ] [selection]\n"); + log(" timeest [-clk ] [options] [selection]\n"); log("\n"); log("Estimate the critical path in clock domain by counting AIG nodes.\n"); log("\n"); + log(" -all_paths\n"); + log(" Print or select nodes from all critical paths instead of focusing on\n"); + log(" a single illustratory path.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *d) override { From 28c7f202caa22041f3a0fe002b089e42a264facd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 22 Aug 2024 10:48:42 +0200 Subject: [PATCH 25/58] timeest: Add `-select` --- passes/cmds/timeest.cc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/passes/cmds/timeest.cc b/passes/cmds/timeest.cc index 82867d84c..020e4347c 100644 --- a/passes/cmds/timeest.cc +++ b/passes/cmds/timeest.cc @@ -47,6 +47,7 @@ struct EstimateSta { std::vector> launchers; std::vector> samplers; bool all_paths = false; + bool select = false; void add_seq(Cell *cell, SigSpec launch, SigSpec sample) { @@ -283,6 +284,9 @@ struct EstimateSta { } } + SigPool bits_to_select; + pool to_select; + pool printed; for (auto node : topo.sorted) { if (!critical.count(node)) @@ -291,6 +295,7 @@ struct EstimateSta { if (aig_node) { Cell *cell = std::get<1>(node); if (!printed.count(cell)) { + to_select.insert(cell->name); std::string cell_src; if (cell->has_attribute(ID::src)) { std::string src_attr = cell->get_src_attribute(); @@ -301,6 +306,7 @@ struct EstimateSta { } } else { SigBit bit = std::get<0>(node); + bits_to_select.add(bit); std::string wire_src; if (bit.wire && bit.wire->has_attribute(ID::src)) { std::string src_attr = bit.wire->get_src_attribute(); @@ -309,6 +315,19 @@ struct EstimateSta { log(" wire %s%s (level %ld)\n", log_signal(bit), wire_src.c_str(), levels[node]); } } + + for (auto wire : m->wires()) { + if (bits_to_select.check_any(sigmap(wire))) + to_select.insert(wire->name); + } + + if (select) { + RTLIL::Selection sel(false); + for (auto member : to_select) + sel.selected_members[m->name].insert(member); + m->design->selection_stack.back() = sel; + m->design->selection_stack.back().optimize(m->design); + } } }; @@ -326,6 +345,9 @@ struct TimeestPass : Pass { log(" Print or select nodes from all critical paths instead of focusing on\n"); log(" a single illustratory path.\n"); log("\n"); + log(" -select\n"); + log(" Select the nodes of a critical path\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *d) override { @@ -333,12 +355,17 @@ struct TimeestPass : Pass { std::string clk; bool all_paths = false; + bool select = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-all_paths") { all_paths = true; continue; } + if (args[argidx] == "-select") { + select = true; + continue; + } if (args[argidx] == "-clk" && argidx + 1 < args.size()) { clk = args[++argidx]; continue; @@ -350,6 +377,9 @@ struct TimeestPass : Pass { if (clk.empty()) log_cmd_error("No -clk argument provided\n"); + if (select && d->selected_modules().size() > 1) + log_cmd_error("The -select option operates on a single selected module\n"); + for (auto m : d->selected_modules()) { if (!m->wire(RTLIL::escape_id(clk))) { log_warning("No domain '%s' in module %s\n", clk.c_str(), log_id(m)); @@ -358,6 +388,7 @@ struct TimeestPass : Pass { EstimateSta sta(m, SigBit(m->wire(RTLIL::escape_id(clk)), 0)); sta.all_paths = all_paths; + sta.select = select; sta.run(); } } From 9c9a0e3e45a856aa40a98b8b81b24e14592920ec Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Tue, 22 Apr 2025 12:21:32 +0100 Subject: [PATCH 26/58] add some comments to timeest --- passes/cmds/timeest.cc | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/passes/cmds/timeest.cc b/passes/cmds/timeest.cc index 020e4347c..2987d6927 100644 --- a/passes/cmds/timeest.cc +++ b/passes/cmds/timeest.cc @@ -61,6 +61,8 @@ struct EstimateSta { samplers.push_back(std::make_pair(cell, bit)); } + // we include a discount factor for cells that can be implemented using carry chain logic + // and to account for the AIG model not being balanced int cell_type_factor(IdString type) { if (type.in(ID($gt), ID($ge), ID($lt), ID($le), ID($add), ID($sub), @@ -81,11 +83,13 @@ struct EstimateSta { { log("Domain %s\n", log_signal(clk)); + // first, we collect launch and sample points and convert the combinational logic to AIG std::vector combinational; for (auto cell : m->cells()) { SigSpec launch, sample; if (RTLIL::builtin_ff_cell_types().count(cell->type)) { + // collect launch and sample points for FF cell FfData ff(nullptr, cell); if (!ff.has_clk) { log_warning("Ignoring unsupported storage element '%s' (%s)\n", @@ -107,6 +111,7 @@ struct EstimateSta { } else if (cell->type == ID($scopeinfo)) { continue; } else { + // find or build AIG model of combinational cell auto fingerprint = std::make_pair(cell->type, cell->parameters); if (!aigs.count(fingerprint)) { aigs.emplace(fingerprint, Aig(cell)); @@ -121,11 +126,14 @@ struct EstimateSta { } } + // since we're now taking reference into `aigs`, we can no longer modify it + // and thus have to fill `cell_aigs` in a separate loop for (auto cell : combinational) { auto fingerprint = std::make_pair(cell->type, cell->parameters); cell_aigs.emplace(cell, &aigs.at(fingerprint)); } + // collect launch and sample points for memory cells for (auto &mem : Mem::get_all_memories(m)) { for (auto &rd : mem.rd_ports) { if (!rd.clk_enable) { @@ -143,6 +151,9 @@ struct EstimateSta { } } + // now we toposort the combinational logic + + // each toposort node is either a SigBit or a pair of Cell * / AigNode * TopoSort> topo; auto desc_aig = [&](Cell *cell, AigNode &node) { @@ -152,6 +163,7 @@ struct EstimateSta { return std::make_tuple(sigmap(bit), (Cell *) NULL, (AigNode *) NULL); }; + // collect edges of the AIG graph for (auto cell : combinational) { assert(cell_aigs.count(cell)); Aig &aig = *cell_aigs.at(cell); @@ -185,12 +197,16 @@ struct EstimateSta { if (!topo.sort()) log_error("Module '%s' contains combinational loops", log_id(m)); - + + // now we determine how long it takes for signals to stabilize + + // `levels` records the time after a clock edge after which a signal is stable dict, arrivalint> levels; for (auto node : topo.sorted) levels[node] = INF_PAST; + // launch points are at 0 by definition for (auto pair : launchers) levels[desc_sig(pair.second)] = 0; @@ -200,22 +216,26 @@ struct EstimateSta { Cell *cell = std::get<1>(node); Aig &aig = *cell_aigs.at(cell); if (!aig_node->portname.empty()) { + // for a cell port, copy `levels` value from port bit SigBit bit = cell->getPort(aig_node->portname)[aig_node->portbit]; levels[node] = levels[desc_sig(bit)]; } else if (aig_node->left_parent < 0 && aig_node->right_parent < 0) { // constant, nothing to do } else { + // for each AIG node, find maximum of parents and add a cell-specific delay int left = levels[desc_aig(cell, aig.nodes[aig_node->left_parent])]; int right = levels[desc_aig(cell, aig.nodes[aig_node->right_parent])]; levels[node] = (std::max(left, right) + cell_type_factor(cell->type)); } + // copy `levels` value to any output ports for (auto &oport : aig_node->outports) { levels[desc_sig(cell->getPort(oport.first)[oport.second])] = levels[node]; } } } + // now find the length of the critical path (slowest path in the design) arrivalint crit = INF_PAST; for (auto pair : samplers) if (levels[desc_sig(pair.second)] > crit) @@ -232,6 +252,7 @@ struct EstimateSta { // some compile-time errors related to hashing dict, bool> critical; + // actually find one critical path, or all such paths if requested for (auto pair : samplers) { if (levels[desc_sig(pair.second)] == crit) { critical[desc_sig(pair.second)] = true; @@ -240,6 +261,7 @@ struct EstimateSta { } } + // walk backwards through toposorted nodes and set critical flag on nodes in critical path for (auto it = topo.sorted.rbegin(); it != topo.sorted.rend(); it++) { auto node = *it; AigNode *aig_node = std::get<2>(node); @@ -248,22 +270,20 @@ struct EstimateSta { Aig &aig = *cell_aigs.at(cell); for (auto &oport : aig_node->outports) { - //levels[desc_sig(cell->getPort(oport.first)[oport.second])] = levels[node]; if (critical.count(desc_sig(cell->getPort(oport.first)[oport.second]))) critical[node] = true; } if (!aig_node->portname.empty()) { SigBit bit = cell->getPort(aig_node->portname)[aig_node->portbit]; - //levels[node] = levels[desc_sig(bit)]; if (critical.count(node)) critical[desc_sig(bit)] = true; } else if (aig_node->left_parent < 0 && aig_node->right_parent < 0) { // constant, nothing to do } else { + // figure out which parent is on the critical path auto left = desc_aig(cell, aig.nodes[aig_node->left_parent]); auto right = desc_aig(cell, aig.nodes[aig_node->right_parent]); - //levels[node] = (std::max(left, right) + 1); int crit_input_lvl = levels[node] - cell_type_factor(cell->type); if (critical.count(node)) { bool left_critical = (levels[left] == crit_input_lvl); @@ -284,6 +304,7 @@ struct EstimateSta { } } + // finally print the path we found SigPool bits_to_select; pool to_select; From 4b4cdf75b829fafb0db665ad82a860c768366be1 Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Tue, 22 Apr 2025 13:19:28 +0100 Subject: [PATCH 27/58] timeest: gcc refuses to parse "struct ::Yosys:..." --- passes/cmds/timeest.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/timeest.cc b/passes/cmds/timeest.cc index 2987d6927..05dd2a4b3 100644 --- a/passes/cmds/timeest.cc +++ b/passes/cmds/timeest.cc @@ -28,7 +28,7 @@ #include USING_YOSYS_NAMESPACE -template<> struct ::Yosys::hashlib::hash_ops : Yosys::hashlib::hash_ptr_ops {}; +template<> struct Yosys::hashlib::hash_ops : Yosys::hashlib::hash_ptr_ops {}; PRIVATE_NAMESPACE_BEGIN From b7d7b377fd8fbc414c01b3554f82ddf2db8deeac Mon Sep 17 00:00:00 2001 From: Mike Inouye Date: Tue, 22 Apr 2025 23:26:55 +0000 Subject: [PATCH 28/58] Detect FF functions that use parentheses. Signed-off-by: Mike Inouye --- passes/techmap/dfflibmap.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 84db7f157..ae13a6ddd 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -102,6 +102,9 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std } else if (expr[0] == '!') { data_name = expr.substr(1, expr.size()-1); data_not_inverted = false; + } else if (expr[0] == '(' && expr[expr.size() - 1] == ')') { + data_name = expr.substr(1, expr.size() - 2); + data_not_inverted = true; } else { data_name = expr; data_not_inverted = true; From bf20bc0848e2089a4ca814c60471e82c7b666986 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 00:23:08 +0000 Subject: [PATCH 29/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7076e949d..8b50fcb98 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+75 +YOSYS_VER := 0.52+89 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) From e4d6781088d601828fb2eb7ec4a43727b3893692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Stro=CC=88mbergson?= Date: Wed, 23 Apr 2025 16:59:53 +0200 Subject: [PATCH 30/58] Changing non clocked alway assignment to blocking. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Joachim Strömbergson --- techlibs/ecp5/cells_sim.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 950d12c91..eec211d6b 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -386,7 +386,7 @@ module TRELLIS_IO( ); parameter DIR = "INPUT"; reg T_pd; - always @(*) if (T === 1'bz) T_pd <= 1'b0; else T_pd <= T; + always @(*) if (T === 1'bz) T_pd = 1'b0; else T_pd = T; generate if (DIR == "INPUT") begin From 90f50722ab358d36f2dacccc21b510be25153a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Stro=CC=88mbergson?= Date: Wed, 23 Apr 2025 17:13:37 +0200 Subject: [PATCH 31/58] Change to blocking assignments in non-clocked process. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Joachim Strömbergson --- techlibs/gatemate/cells_sim.v | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/techlibs/gatemate/cells_sim.v b/techlibs/gatemate/cells_sim.v index e05ce811c..d930b83f8 100644 --- a/techlibs/gatemate/cells_sim.v +++ b/techlibs/gatemate/cells_sim.v @@ -292,10 +292,10 @@ module CC_DLT #( always @(*) begin if (sr) begin - Q <= SR_VAL; + Q = SR_VAL; end else if (en) begin - Q <= D; + Q = D; end end @@ -407,7 +407,7 @@ module CC_MULT #( ); always @(*) begin - P <= A * B; + P = A * B; end endmodule From 2fcb61adb5101c2c6539de0d4a8b9000326a928a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Stro=CC=88mbergson?= Date: Wed, 23 Apr 2025 17:21:32 +0200 Subject: [PATCH 32/58] Change to use blocking assignments in non-clocked processes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Joachim Strömbergson --- techlibs/greenpak4/cells_sim_digital.v | 62 +++++++++++++------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/techlibs/greenpak4/cells_sim_digital.v b/techlibs/greenpak4/cells_sim_digital.v index 43d35d08f..f1393be0c 100644 --- a/techlibs/greenpak4/cells_sim_digital.v +++ b/techlibs/greenpak4/cells_sim_digital.v @@ -48,7 +48,7 @@ module GP_COUNT14(input CLK, input wire RST, output reg OUT); //Combinatorially output underflow flag whenever we wrap low always @(*) begin - OUT <= (count == 14'h0); + OUT = (count == 14'h0); end //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. @@ -133,10 +133,10 @@ module GP_COUNT14_ADV(input CLK, input RST, output reg OUT, //Combinatorially output underflow flag whenever we wrap low always @(*) begin if(UP) - OUT <= (count == 14'h3fff); + OUT = (count == 14'h3fff); else - OUT <= (count == 14'h0); - POUT <= count[7:0]; + OUT = (count == 14'h0); + POUT = count[7:0]; end //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. @@ -272,10 +272,10 @@ module GP_COUNT8_ADV(input CLK, input RST, output reg OUT, //Combinatorially output underflow flag whenever we wrap low always @(*) begin if(UP) - OUT <= (count == 8'hff); + OUT = (count == 8'hff); else - OUT <= (count == 8'h0); - POUT <= count; + OUT = (count == 8'h0); + POUT = count; end //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. @@ -413,8 +413,8 @@ module GP_COUNT8( //Combinatorially output underflow flag whenever we wrap low always @(*) begin - OUT <= (count == 8'h0); - POUT <= count; + OUT = (count == 8'h0); + POUT = count; end //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. @@ -488,23 +488,23 @@ module GP_DCMPMUX(input[1:0] SEL, input[7:0] IN0, input[7:0] IN1, input[7:0] IN2 always @(*) begin case(SEL) 2'd00: begin - OUTA <= IN0; - OUTB <= IN3; + OUTA = IN0; + OUTB = IN3; end 2'd01: begin - OUTA <= IN1; - OUTB <= IN2; + OUTA = IN1; + OUTB = IN2; end 2'd02: begin - OUTA <= IN2; - OUTB <= IN1; + OUTA = IN2; + OUTB = IN1; end 2'd03: begin - OUTA <= IN3; - OUTB <= IN0; + OUTA = IN3; + OUTB = IN0; end endcase @@ -635,7 +635,7 @@ module GP_DLATCH(input D, input nCLK, output reg Q); initial Q = INIT; always @(*) begin if(!nCLK) - Q <= D; + Q = D; end endmodule @@ -644,7 +644,7 @@ module GP_DLATCHI(input D, input nCLK, output reg nQ); initial nQ = INIT; always @(*) begin if(!nCLK) - nQ <= ~D; + nQ = ~D; end endmodule @@ -653,9 +653,9 @@ module GP_DLATCHR(input D, input nCLK, input nRST, output reg Q); initial Q = INIT; always @(*) begin if(!nRST) - Q <= 1'b0; + Q = 1'b0; else if(!nCLK) - Q <= D; + Q = D; end endmodule @@ -664,9 +664,9 @@ module GP_DLATCHRI(input D, input nCLK, input nRST, output reg nQ); initial nQ = INIT; always @(*) begin if(!nRST) - nQ <= 1'b1; + nQ = 1'b1; else if(!nCLK) - nQ <= ~D; + nQ = ~D; end endmodule @@ -675,9 +675,9 @@ module GP_DLATCHS(input D, input nCLK, input nSET, output reg Q); initial Q = INIT; always @(*) begin if(!nSET) - Q <= 1'b1; + Q = 1'b1; else if(!nCLK) - Q <= D; + Q = D; end endmodule @@ -686,9 +686,9 @@ module GP_DLATCHSI(input D, input nCLK, input nSET, output reg nQ); initial nQ = INIT; always @(*) begin if(!nSET) - nQ <= 1'b0; + nQ = 1'b0; else if(!nCLK) - nQ <= ~D; + nQ = ~D; end endmodule @@ -698,9 +698,9 @@ module GP_DLATCHSR(input D, input nCLK, input nSR, output reg Q); initial Q = INIT; always @(*) begin if(!nSR) - Q <= SRMODE; + Q = SRMODE; else if(!nCLK) - Q <= D; + Q = D; end endmodule @@ -710,9 +710,9 @@ module GP_DLATCHSRI(input D, input nCLK, input nSR, output reg nQ); initial nQ = INIT; always @(*) begin if(!nSR) - nQ <= ~SRMODE; + nQ = ~SRMODE; else if(!nCLK) - nQ <= ~D; + nQ = ~D; end endmodule From bf8aece4e4ff5c5e34fe56f1d1575d1c5a9ad85f Mon Sep 17 00:00:00 2001 From: Mike Inouye Date: Wed, 23 Apr 2025 18:40:35 +0000 Subject: [PATCH 33/58] Add test to verify that the liberty format is properly parsed. --- tests/liberty/dff.lib | 22 ++++++++++++++++++++++ tests/liberty/dff.lib.filtered.ok | 19 +++++++++++++++++++ tests/liberty/dff.lib.verilogsim.ok | 12 ++++++++++++ tests/liberty/dff.log.ok | 29 +++++++++++++++++++++++++++++ tests/liberty/run-test.sh | 4 ++++ 5 files changed, 86 insertions(+) create mode 100644 tests/liberty/dff.lib create mode 100644 tests/liberty/dff.lib.filtered.ok create mode 100644 tests/liberty/dff.lib.verilogsim.ok create mode 100644 tests/liberty/dff.log.ok diff --git a/tests/liberty/dff.lib b/tests/liberty/dff.lib new file mode 100644 index 000000000..61f5966f5 --- /dev/null +++ b/tests/liberty/dff.lib @@ -0,0 +1,22 @@ +// Test library for different DFF function expressions + +library(dff) { + cell (dff) { + area : 1; + ff("IQ", "IQN") { + next_state : "(D)"; + clocked_on : "CLK"; + } + pin(D) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(Q) { + direction: output; + function : "IQ"; + } + } + +} /* end */ diff --git a/tests/liberty/dff.lib.filtered.ok b/tests/liberty/dff.lib.filtered.ok new file mode 100644 index 000000000..b7dcb96be --- /dev/null +++ b/tests/liberty/dff.lib.filtered.ok @@ -0,0 +1,19 @@ +library(dff) { + cell(dff) { + area : 1 ; + ff("IQ", "IQN") { + next_state : "(D)" ; + clocked_on : "CLK" ; + } + pin(D) { + direction : input ; + } + pin(CLK) { + direction : input ; + } + pin(Q) { + direction : output ; + function : "IQ" ; + } + } +} diff --git a/tests/liberty/dff.lib.verilogsim.ok b/tests/liberty/dff.lib.verilogsim.ok new file mode 100644 index 000000000..46441d0fc --- /dev/null +++ b/tests/liberty/dff.lib.verilogsim.ok @@ -0,0 +1,12 @@ +module dff (D, CLK, Q); + reg "IQ", "IQN"; + input D; + input CLK; + output Q; + assign Q = IQ; // "IQ" + always @(posedge CLK) begin + // "(D)" + "IQ" <= (D); + "IQN" <= ~((D)); + end +endmodule diff --git a/tests/liberty/dff.log.ok b/tests/liberty/dff.log.ok new file mode 100644 index 000000000..be187181d --- /dev/null +++ b/tests/liberty/dff.log.ok @@ -0,0 +1,29 @@ + +-- Running command `dfflibmap -info -liberty dff.lib' -- + +1. Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file). + cell dff (noninv, pins=3, area=1.00) is a direct match for cell type $_DFF_P_. + final dff cell mappings: + unmapped dff cell: $_DFF_N_ + \dff _DFF_P_ (.CLK( C), .D( D), .Q( Q)); + unmapped dff cell: $_DFF_NN0_ + unmapped dff cell: $_DFF_NN1_ + unmapped dff cell: $_DFF_NP0_ + unmapped dff cell: $_DFF_NP1_ + unmapped dff cell: $_DFF_PN0_ + unmapped dff cell: $_DFF_PN1_ + unmapped dff cell: $_DFF_PP0_ + unmapped dff cell: $_DFF_PP1_ + unmapped dff cell: $_DFFE_NN_ + unmapped dff cell: $_DFFE_NP_ + unmapped dff cell: $_DFFE_PN_ + unmapped dff cell: $_DFFE_PP_ + unmapped dff cell: $_DFFSR_NNN_ + unmapped dff cell: $_DFFSR_NNP_ + unmapped dff cell: $_DFFSR_NPN_ + unmapped dff cell: $_DFFSR_NPP_ + unmapped dff cell: $_DFFSR_PNN_ + unmapped dff cell: $_DFFSR_PNP_ + unmapped dff cell: $_DFFSR_PPN_ + unmapped dff cell: $_DFFSR_PPP_ +dfflegalize command line: dfflegalize -cell $_DFF_P_ 01 t:$_DFF* t:$_SDFF* diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh index 8fa99d419..f5cffdb18 100755 --- a/tests/liberty/run-test.sh +++ b/tests/liberty/run-test.sh @@ -7,6 +7,10 @@ for x in *.lib; do ../../yosys-filterlib - $x 2>/dev/null > $x.filtered ../../yosys-filterlib -verilogsim $x > $x.verilogsim diff $x.filtered $x.filtered.ok && diff $x.verilogsim $x.verilogsim.ok + if [[ -e ${x%.lib}.log.ok ]]; then + ../../yosys -p "dfflibmap -info -liberty ${x}" -TqqQl ${x%.lib}.log + diff ${x%.lib}.log ${x%.lib}.log.ok + fi done || exit 1 for x in *.ys; do From a0d865c2bf4646bda63309aad54fb4dbd6ca9a2b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 00:23:08 +0000 Subject: [PATCH 34/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7076e949d..8b50fcb98 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+75 +YOSYS_VER := 0.52+89 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) From 9631f6ece568ca8ceaeccb81107ea545f064b70a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 16 Apr 2025 22:24:55 +0200 Subject: [PATCH 35/58] liberty: fix tests --- tests/liberty/run-test.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh index f5cffdb18..5afdb727e 100755 --- a/tests/liberty/run-test.sh +++ b/tests/liberty/run-test.sh @@ -1,20 +1,21 @@ #!/usr/bin/env bash -set -e +set -eo pipefail for x in *.lib; do echo "Testing on $x.." ../../yosys -p "read_verilog small.v; synth -top small; dfflibmap -info -liberty ${x}" -ql ${x%.lib}.log ../../yosys-filterlib - $x 2>/dev/null > $x.filtered ../../yosys-filterlib -verilogsim $x > $x.verilogsim - diff $x.filtered $x.filtered.ok && diff $x.verilogsim $x.verilogsim.ok + diff $x.filtered $x.filtered.ok + diff $x.verilogsim $x.verilogsim.ok if [[ -e ${x%.lib}.log.ok ]]; then ../../yosys -p "dfflibmap -info -liberty ${x}" -TqqQl ${x%.lib}.log diff ${x%.lib}.log ${x%.lib}.log.ok fi -done || exit 1 +done for x in *.ys; do echo "Running $x.." ../../yosys -q -s $x -l ${x%.ys}.log -done || exit 1 +done From c550c301dc8bdf0eed9da6898ccd87646ce14575 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 00:23:08 +0000 Subject: [PATCH 36/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8b50fcb98..1cef095e3 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+89 +YOSYS_VER := 0.52+102 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) From b693947834b183434c428c2af6ee670b2f6206bb Mon Sep 17 00:00:00 2001 From: sdjasj <1594576288@qq.com> Date: Wed, 23 Apr 2025 05:58:57 +0000 Subject: [PATCH 37/58] fix udivmod crashes when operand value exceeds logical width --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 37c84895f..886d033cb 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -2010,7 +2010,7 @@ std::pair, value> divmod_uu(const value &a, const val value quotient; value remainder; value dividend = a.template zext(); - value divisor = b.template zext(); + value divisor = b.template trunc().template zext(); std::tie(quotient, remainder) = dividend.udivmod(divisor); return {quotient.template trunc(), remainder.template trunc()}; } From 3541db8bbbde4d878c78d32fe99b1fd7026d8fa6 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 25 Apr 2025 00:51:10 +0200 Subject: [PATCH 38/58] driver: fix -X xtrace backtrace level --- kernel/driver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index eb1326ce0..b7f0268db 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -314,7 +314,7 @@ int main(int argc, char **argv) auto result = options.parse(argc, argv); if (result.count("M")) memhasher_on(); - if (result.count("X")) yosys_xtrace++; + if (result.count("X")) yosys_xtrace += result.count("X"); if (result.count("A")) call_abort = true; if (result.count("Q")) print_banner = false; if (result.count("T")) print_stats = false; From bdc2597f792a602ec22f98d7cb3fc23710b6659a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 25 Apr 2025 01:00:08 +0200 Subject: [PATCH 39/58] simplify: fix struct wiretype attr memory leak --- frontends/ast/simplify.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d35756d4e..3411d6c03 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1919,6 +1919,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure newNode = make_packed_struct(template_node, str, attributes); + if (newNode->attributes.count(ID::wiretype)) + delete newNode->attributes[ID::wiretype]; newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // add original input/output attribute to resolved wire newNode->is_input = this->is_input; From 94af24c801736bd89a493f4c92dc7b55af928b25 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 00:23:50 +0000 Subject: [PATCH 40/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1cef095e3..72d854212 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+102 +YOSYS_VER := 0.52+104 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) From 1e8adc6bd011487ddcc5a6c6cedd51799c0926f2 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:59:24 +1200 Subject: [PATCH 41/58] Makefile: Redirect all git output For some platforms (Arch Linux, at least), `git status` reports errors on stdout instead of stderr, so we need to redirect that to `/dev/null` too. This also prevents `git status` from logging output when the yosys directory is a git repo, but is missing the abc folder. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2e4db2456..23d91b117 100644 --- a/Makefile +++ b/Makefile @@ -785,7 +785,7 @@ $(PROGRAM_PREFIX)yosys-config: misc/yosys-config.in $(YOSYS_SRC)/Makefile .PHONY: check-git-abc check-git-abc: - @if [ ! -d "$(YOSYS_SRC)/abc" ] && git -C "$(YOSYS_SRC)" status 2>/dev/null; then \ + @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; \ @@ -811,7 +811,7 @@ check-git-abc: 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 2>/dev/null; then \ + 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."; \ From c952ab417f1ac0a5e21aa0ce49e552bb70c1c3fe Mon Sep 17 00:00:00 2001 From: George Rennie Date: Sat, 26 Apr 2025 12:03:50 +0200 Subject: [PATCH 42/58] opt_expr: only sign extend shift arguments for arithmetic right shift --- passes/opt/opt_expr.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index df969daf0..74f5b386a 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1315,13 +1315,14 @@ skip_fine_alu: RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); RTLIL::SigSpec sig_y(cell->type == ID($shiftx) ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam(ID::Y_WIDTH).as_int()); - // Limit indexing to the size of a, which is behaviourally identical (result is all 0) - // and avoids integer overflow of i + shift_bits when e.g. ID::B == INT_MAX - shift_bits = min(shift_bits, GetSize(sig_a)); - if (cell->type != ID($shiftx) && GetSize(sig_a) < GetSize(sig_y)) sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + // Limit indexing to the size of a, which is behaviourally identical (result is all 0) + // and avoids integer overflow of i + shift_bits when e.g. ID::B == INT_MAX. + // We do this after sign-extending a so this accounts for the output size + shift_bits = min(shift_bits, GetSize(sig_a)); + for (int i = 0; i < GetSize(sig_y); i++) { int idx = i + shift_bits; if (0 <= idx && idx < GetSize(sig_a)) From 70a44f035c4152c99f4c8408e562095c58b22676 Mon Sep 17 00:00:00 2001 From: George Rennie Date: Sat, 26 Apr 2025 12:10:53 +0200 Subject: [PATCH 43/58] tests: test opt_expr constant shift edge cases --- tests/opt/opt_expr_shift.ys | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/opt/opt_expr_shift.ys diff --git a/tests/opt/opt_expr_shift.ys b/tests/opt/opt_expr_shift.ys new file mode 100644 index 000000000..aac2e6f62 --- /dev/null +++ b/tests/opt/opt_expr_shift.ys @@ -0,0 +1,50 @@ +# Testing edge cases where ports are signed/have different widths/shift amounts +# greater than the size + +read_verilog <> 20; + assign shr_us = in_u >> 20; + assign shr_su = in_s >> 20; + assign shr_ss = in_s >> 20; + assign sshl_uu = in_u <<< 20; + assign sshl_us = in_u <<< 20; + assign sshl_su = in_s <<< 20; + assign sshl_ss = in_s <<< 20; + assign sshr_uu = in_u >>> 20; + assign sshr_us = in_u >>> 20; + assign sshr_su = in_s >>> 20; + assign sshr_ss = in_s >>> 20; +endmodule +EOT + +equiv_opt opt_expr + +design -load postopt +select -assert-none t:$shl +select -assert-none t:$shr +select -assert-none t:$sshl +select -assert-none t:$sshr From 3d1f2161dcc1bfdc6f1749bbf8c67a3a64d45c7b Mon Sep 17 00:00:00 2001 From: Catherine Date: Thu, 14 Nov 2024 21:49:53 +0000 Subject: [PATCH 44/58] cxxrtl: strip `$paramod` from module name in scope info. --- backends/cxxrtl/cxxrtl_backend.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 052699ad6..819b2c1df 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -2410,7 +2410,12 @@ struct CxxrtlWorker { auto cell_attrs = scopeinfo_attributes(cell, ScopeinfoAttrs::Cell); cell_attrs.erase(ID::module_not_derived); f << indent << "scopes->add(path, " << escape_cxx_string(get_hdl_name(cell)) << ", "; - f << escape_cxx_string(cell->get_string_attribute(ID(module))) << ", "; + if (module_attrs.count(ID(hdlname))) { + f << escape_cxx_string(module_attrs.at(ID(hdlname)).decode_string()); + } else { + f << escape_cxx_string(cell->get_string_attribute(ID(module))); + } + f << ", "; dump_serialized_metadata(module_attrs); f << ", "; dump_serialized_metadata(cell_attrs); From 4fbb2bc1f397846fefbf4e7fa25c96e38b0eb184 Mon Sep 17 00:00:00 2001 From: George Rennie Date: Sat, 26 Apr 2025 18:34:21 +0200 Subject: [PATCH 45/58] celledges: use capped shift width --- kernel/celledges.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/celledges.cc b/kernel/celledges.cc index 8129e6b1b..8e52d0380 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -247,7 +247,7 @@ void shift_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) db->add_edge(cell, ID::A, a_width - 1, ID::Y, i, -1); } - for (int k = 0; k < b_width; k++) { + for (int k = 0; k < b_width_capped; k++) { // left shifts if (cell->type.in(ID($shl), ID($sshl))) { if (a_width == 1 && is_signed) { @@ -268,7 +268,7 @@ void shift_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) bool shift_in_bulk = i < a_width - 1; // can we jump into the zero-padding by toggling B[k]? bool zpad_jump = (((y_width - i) & ((1 << (k + 1)) - 1)) != 0 \ - && (((y_width - i) & ~(1 << k)) < (1 << b_width))); + && (((y_width - i) & ~(1 << k)) < (1 << b_width_capped))); if (shift_in_bulk || (cell->type.in(ID($shr), ID($shift), ID($shiftx)) && zpad_jump)) db->add_edge(cell, ID::B, k, ID::Y, i, -1); @@ -279,7 +279,7 @@ void shift_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) // bidirectional shifts (positive B shifts right, negative left) } else if (cell->type.in(ID($shift), ID($shiftx)) && is_b_signed) { if (is_signed) { - if (k != b_width - 1) { + if (k != b_width_capped - 1) { bool r_shift_in_bulk = i < a_width - 1; // assuming B is positive, can we jump into the upper zero-padding by toggling B[k]? bool r_zpad_jump = (((y_width - i) & ((1 << (k + 1)) - 1)) != 0 \ From 58e7cfa559fac94b8e3503ae6f940d3012004003 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 27 Apr 2025 00:25:27 +0000 Subject: [PATCH 46/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 72d854212..393408603 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+104 +YOSYS_VER := 0.52+117 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) From 6d575918fc2bbaff41efb41e8a98ad872ebeaf13 Mon Sep 17 00:00:00 2001 From: Patrick Urban Date: Mon, 28 Apr 2025 14:42:16 +0200 Subject: [PATCH 47/58] gatemate: Set unused BRAM inputs to 'bx This will reduce the number of CPEs to generate fixed values at the block RAM inputs, if it is not used. --- techlibs/gatemate/brams_map.v | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/techlibs/gatemate/brams_map.v b/techlibs/gatemate/brams_map.v index 171825f49..0b039db35 100644 --- a/techlibs/gatemate/brams_map.v +++ b/techlibs/gatemate/brams_map.v @@ -115,15 +115,15 @@ generate .A_CLK(PORT_A_CLK), .A_EN(PORT_A_CLK_EN), .A_WE(PORT_A_WR_EN), - .A_BM(PORT_A_WR_BE), - .A_DI(PORT_A_WR_DATA), + .A_BM({{(20-PORT_A_WR_BE_WIDTH){1'bx}}, PORT_A_WR_BE}), + .A_DI({{(20-PORT_A_WR_WIDTH){1'bx}}, PORT_A_WR_DATA}), .A_ADDR({PORT_A_ADDR[13:5], 1'b0, PORT_A_ADDR[4:0], 1'b0}), .A_DO(PORT_A_RD_DATA), .B_CLK(PORT_B_CLK), .B_EN(PORT_B_CLK_EN), .B_WE(PORT_B_WR_EN), - .B_BM(PORT_B_WR_BE), - .B_DI(PORT_B_WR_DATA), + .B_BM({{(20-PORT_B_WR_BE_WIDTH){1'bx}}, PORT_B_WR_BE}), + .B_DI({{(20-PORT_B_WR_WIDTH){1'bx}}, PORT_B_WR_DATA}), .B_ADDR({PORT_B_ADDR[13:5], 1'b0, PORT_B_ADDR[4:0], 1'b0}), .B_DO(PORT_B_RD_DATA), ); @@ -270,15 +270,15 @@ generate .A_CLK(PORT_A_CLK), .A_EN(PORT_A_CLK_EN), .A_WE(PORT_A_WR_EN), - .A_BM(PORT_A_WR_BE), - .A_DI(PORT_A_WR_DATA), + .A_BM({{(40-PORT_A_WR_BE_WIDTH){1'bx}}, PORT_A_WR_BE}), + .A_DI({{(40-PORT_A_WR_WIDTH){1'bx}}, PORT_A_WR_DATA}), .A_ADDR({PORT_A_ADDR[14:0], 1'b0}), .A_DO(PORT_A_RD_DATA), .B_CLK(PORT_B_CLK), .B_EN(PORT_B_CLK_EN), .B_WE(PORT_B_WR_EN), - .B_BM(PORT_B_WR_BE), - .B_DI(PORT_B_WR_DATA), + .B_BM({{(40-PORT_B_WR_BE_WIDTH){1'bx}}, PORT_B_WR_BE}), + .B_DI({{(40-PORT_B_WR_WIDTH){1'bx}}, PORT_B_WR_DATA}), .B_ADDR({PORT_B_ADDR[14:0], 1'b0}), .B_DO(PORT_B_RD_DATA), ); @@ -429,14 +429,14 @@ generate .A_CLK(PORT_A_CLK), .A_EN(PORT_A_CLK_EN), .A_WE(PORT_A_WR_EN), - .A_BM(PORT_A_WR_BE), - .A_DI(PORT_A_WR_DATA), + .A_BM({{(40-PORT_A_WR_BE_WIDTH){1'bx}}, PORT_A_WR_BE}), + .A_DI({{(40-PORT_A_WR_WIDTH){1'bx}}, PORT_A_WR_DATA}), .A_ADDR({PORT_A_ADDR[14:0], PORT_A_ADDR[15]}), .B_CLK(PORT_B_CLK), .B_EN(PORT_B_CLK_EN), .B_WE(PORT_B_WR_EN), - .B_BM(PORT_B_WR_BE), - .B_DI(PORT_B_WR_DATA), + .B_BM({{(40-PORT_B_WR_BE_WIDTH){1'bx}}, PORT_B_WR_BE}), + .B_DI({{(40-PORT_B_WR_WIDTH){1'bx}}, PORT_B_WR_DATA}), .B_ADDR({PORT_B_ADDR[14:0], PORT_B_ADDR[15]}), ); CC_BRAM_40K #( @@ -584,15 +584,15 @@ generate .A_CLK(PORT_A_CLK), .A_EN(PORT_A_CLK_EN), .A_WE(PORT_A_WR_EN), - .A_BM(PORT_A_WR_BE), - .A_DI(PORT_A_WR_DATA), + .A_BM({{(40-PORT_A_WR_BE_WIDTH){1'bx}}, PORT_A_WR_BE}), + .A_DI({{(40-PORT_A_WR_WIDTH){1'bx}}, PORT_A_WR_DATA}), .A_DO(PORT_A_RD_DATA), .A_ADDR({PORT_A_ADDR[14:0], PORT_A_ADDR[15]}), .B_CLK(PORT_B_CLK), .B_EN(PORT_B_CLK_EN), .B_WE(PORT_B_WR_EN), - .B_BM(PORT_B_WR_BE), - .B_DI(PORT_B_WR_DATA), + .B_BM({{(40-PORT_B_WR_BE_WIDTH){1'bx}}, PORT_B_WR_BE}), + .B_DI({{(40-PORT_B_WR_WIDTH){1'bx}}, PORT_B_WR_DATA}), .B_DO(PORT_B_RD_DATA), .B_ADDR({PORT_B_ADDR[14:0], PORT_B_ADDR[15]}), ); @@ -710,9 +710,9 @@ generate .A_EN(PORT_W_CLK_EN), .A_WE(PORT_W_WR_EN), .A_BM(PORT_W_WR_BE[19:0]), - .B_BM(PORT_W_WR_BE[39:20]), + .B_BM({{(40-PORT_W_WIDTH){1'bx}}, PORT_W_WR_BE[39:20]}), .A_DI(PORT_W_WR_DATA[19:0]), - .B_DI(PORT_W_WR_DATA[39:20]), + .B_DI({{(40-PORT_W_WIDTH){1'bx}}, PORT_W_WR_DATA[39:20]}), .A_ADDR({PORT_W_ADDR[13:5], 1'b0, PORT_W_ADDR[4:0], 1'b0}), .B_CLK(PORT_R_CLK), .B_EN(PORT_R_CLK_EN), @@ -865,9 +865,9 @@ generate .A_EN(PORT_W_CLK_EN), .A_WE(PORT_W_WR_EN), .A_BM(PORT_W_WR_BE[39:0]), - .B_BM(PORT_W_WR_BE[79:40]), + .B_BM({{(80-PORT_W_WIDTH){1'bx}}, PORT_W_WR_BE[79:40]}), .A_DI(PORT_W_WR_DATA[39:0]), - .B_DI(PORT_W_WR_DATA[79:40]), + .B_DI({{(80-PORT_W_WIDTH){1'bx}}, PORT_W_WR_DATA[79:40]}), .A_ADDR({PORT_W_ADDR[14:0], 1'b0}), .B_CLK(PORT_R_CLK), .B_EN(PORT_R_CLK_EN), From adb1986dc10d19b414971b472497a71bc0d0e052 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 29 Apr 2025 10:37:35 +0200 Subject: [PATCH 48/58] gzip: refactor file open failure errors --- kernel/gzip.cc | 5 +++-- kernel/register.cc | 2 -- passes/cmds/stat.cc | 2 -- passes/techmap/clockgate.cc | 2 -- passes/techmap/dfflibmap.cc | 2 -- 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/kernel/gzip.cc b/kernel/gzip.cc index d44b03517..4567fe03b 100644 --- a/kernel/gzip.cc +++ b/kernel/gzip.cc @@ -100,11 +100,12 @@ gzip_istream::ibuf::~ibuf() { // Takes a successfully opened ifstream. If it's gzipped, returns an istream. Otherwise, // returns the original ifstream, rewound to the start. +// Never returns nullptr or failed state istream* std::istream* uncompressed(const std::string filename, std::ios_base::openmode mode) { std::ifstream* f = new std::ifstream(); f->open(filename, mode); if (f->fail()) - return f; + log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); // Check for gzip magic unsigned char magic[3]; int n = 0; @@ -124,7 +125,7 @@ std::istream* uncompressed(const std::string filename, std::ios_base::openmode m filename.c_str(), unsigned(magic[2])); gzip_istream* s = new gzip_istream(); delete f; - s->open(filename.c_str()); + log_assert(s->open(filename.c_str())); return s; #else log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str()); diff --git a/kernel/register.cc b/kernel/register.cc index c52bfb5b8..a82f93555 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -472,8 +472,6 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector &cell_area, string libert { std::istream* f = uncompressed(liberty_file.c_str()); yosys_input_files.insert(liberty_file); - if (f->fail()) - log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno)); LibertyParser libparser(*f, liberty_file); delete f; diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index 2305cfc94..508e66d23 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -310,8 +310,6 @@ struct ClockgatePass : public Pass { LibertyMergedCells merged; for (auto path : liberty_files) { std::istream* f = uncompressed(path); - if (f->fail()) - log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno)); LibertyParser p(*f, path); merged.merge(p); delete f; diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index ae13a6ddd..d00fee83b 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -635,8 +635,6 @@ struct DfflibmapPass : public Pass { LibertyMergedCells merged; for (auto path : liberty_files) { std::istream* f = uncompressed(path); - if (f->fail()) - log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno)); LibertyParser p(*f, path); merged.merge(p); delete f; From 15cfce061a118111984e013a46fd0bbdc064a9ed Mon Sep 17 00:00:00 2001 From: RonxBulld <526677628@qq.com> Date: Tue, 29 Apr 2025 22:43:10 +0800 Subject: [PATCH 49/58] Change the implementation of log_debug in kernel/log.h from a macro function to a normal function. --- kernel/log.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/log.h b/kernel/log.h index e26ef072c..6c834c6c6 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -148,7 +148,7 @@ static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_d #else static inline bool ys_debug(int = 0) { return false; } #endif -# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) +static inline void log_debug(const char *format, ...) { if (ys_debug(1)) { va_list args; va_start(args, format); logv(format, args); va_end(args); } } static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { From aa30589c123844bc576fc3c9938157b5db35a7c1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 00:26:28 +0000 Subject: [PATCH 50/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e347d1c8c..d2f518d88 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+117 +YOSYS_VER := 0.52+137 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) From da1ac9ae47df62301dcaed05c8679dbb3508fd10 Mon Sep 17 00:00:00 2001 From: sdjasj <89853352+sdjasj@users.noreply.github.com> Date: Sat, 3 May 2025 17:38:16 +0800 Subject: [PATCH 51/58] cxxrtl: fix missing sign extension before shift operation for signed values --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 886d033cb..9b4f5774f 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -1769,7 +1769,7 @@ value shr_uu(const value &a, const value &b) { template CXXRTL_ALWAYS_INLINE value shr_su(const value &a, const value &b) { - return a.shr(b).template scast(); + return a.template scast().shr(b); } template From 765485a375cc766e9f3e4e9c7bd245c730ad7359 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 4 May 2025 00:26:28 +0000 Subject: [PATCH 52/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d2f518d88..aa3624253 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+137 +YOSYS_VER := 0.52+139 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) From 23cb00706812465b3ff2c3ecf02ed9a3a27b40a3 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 5 May 2025 10:04:13 +1200 Subject: [PATCH 53/58] verilog_parser.y: Delete unused TOK_ID Fixes memory leak when parameter has no value. --- frontends/verilog/verilog_parser.y | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index fe86626b8..9d0956c8e 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2249,7 +2249,8 @@ cell_parameter: node->children.push_back($1); } | '.' TOK_ID '(' ')' { - // just ignore empty parameters + // delete unused TOK_ID + delete $2; } | '.' TOK_ID '(' expr ')' { AstNode *node = new AstNode(AST_PARASET); From 7c2b00c448ee37e9af27cf497f24d0526a57c40b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 5 May 2025 10:18:52 +1200 Subject: [PATCH 54/58] tests: Add default param test file Just loads, fails ASAN without fix. --- tests/verilog/param_default.ys | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/verilog/param_default.ys diff --git a/tests/verilog/param_default.ys b/tests/verilog/param_default.ys new file mode 100644 index 000000000..59023c477 --- /dev/null +++ b/tests/verilog/param_default.ys @@ -0,0 +1,24 @@ +logger -expect-no-warnings +read_verilog << EOF +module bar ( + input portname +); + parameter paramname = 7; +endmodule + +module empty ( +); + bar #() barinstance (); +endmodule + +module implicit ( +); + bar #(.paramname()) barinstance (.portname()); +endmodule + +module explicit ( + input a +); + bar #(.paramname(3)) barinstance (.portname(a)); +endmodule +EOF From 5924f2de7b706e589b981db9bbbbc5d47fa0094c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 00:23:55 +0000 Subject: [PATCH 55/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index aa3624253..4616c5a95 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+139 +YOSYS_VER := 0.52+143 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) From 53c22ab7c0ced80861c7536c5dae682c30fb5834 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 6 May 2025 07:45:16 +0200 Subject: [PATCH 56/58] Release version 0.53 --- CHANGELOG | 19 ++++++++++++++++++- Makefile | 4 ++-- docs/source/conf.py | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 413a3236c..1e5af745c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,25 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.52 .. Yosys 0.53-dev +Yosys 0.52 .. Yosys 0.53 -------------------------- + * New commands and options + - Added "constmap" pass for technology mapping of coarse constant value. + - Added "timeest" pass to estimate the critical path in clock domain. + - Added "-blackbox" option to "cutpoint" pass to cut all instances of + blackboxes. + - Added "-noscopeinfo" option to "cutpoint" pass. + - Added "-nocleanup" option to "flatten" pass to prevent removal of + unused submodules. + - Added "-declockgate" option to "formalff" pass that turns clock + gating into clock enables. + + * Various + - Added "$scopeinfo" cells to preserve information during "cutpoint" pass. + - Added dataflow tracking documentation. + - share: Restrict activation patterns to potentially relevant signal. + - liberty: More robust parsing. + - verific: bit blast RAM if using mem2reg attribute. Yosys 0.51 .. Yosys 0.52 -------------------------- diff --git a/Makefile b/Makefile index 4616c5a95..0a9284dc1 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+143 +YOSYS_VER := 0.53 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) @@ -183,7 +183,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline fee39a3.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline fee39a3.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) diff --git a/docs/source/conf.py b/docs/source/conf.py index 74ebe16e0..bfcb28730 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -6,7 +6,7 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' copyright ='2025 YosysHQ GmbH' -yosys_ver = "0.52" +yosys_ver = "0.53" # select HTML theme html_theme = 'furo-ys' From 20921ad9081abc2096eb7867885c285d3082be60 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 6 May 2025 08:26:46 +0200 Subject: [PATCH 57/58] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1e5af745c..bdf30260e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.53 .. Yosys 0.54-dev +-------------------------- + Yosys 0.52 .. Yosys 0.53 -------------------------- * New commands and options diff --git a/Makefile b/Makefile index 0a9284dc1..f4063ad40 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.53 +YOSYS_VER := 0.53+0 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) @@ -183,7 +183,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline fee39a3.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 53c22ab.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From 8da97d00446eba52c78518b1dbc42c0677b8e838 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 00:24:00 +0000 Subject: [PATCH 58/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f4063ad40..5986b1091 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.53+0 +YOSYS_VER := 0.53+3 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)