3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-04 06:26:09 +00:00

Merge branch 'YosysHQ:main' into master

This commit is contained in:
Eder Monteiro 2025-06-09 10:45:30 -03:00 committed by GitHub
commit e793a1952e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
101 changed files with 7356 additions and 5889 deletions

View file

@ -2,9 +2,25 @@
List of major changes and improvements between releases List of major changes and improvements between releases
======================================================= =======================================================
Yosys 0.53 .. Yosys 0.54-dev Yosys 0.54 .. Yosys 0.55-dev
-------------------------- --------------------------
Yosys 0.53 .. Yosys 0.54
--------------------------
* New commands and options
- Added "-genlib" option to "abc_new" and "abc9_exe" passes.
- Added "-verbose" and "-quiet" options to "libcache" pass.
- Added "-no-sort" option to "write_aiger" pass.
* Various
- Added "muldiv_c" peepopt.
- Accept (and ignore) SystemVerilog unique/priority if.
- "read_verilog" copy inout ports in and out of functions/tasks.
- Enable single-bit vector wires in RTLIL.
* Xilinx support
- Single-port URAM mapping to support memories 2048 x 144b
Yosys 0.52 .. Yosys 0.53 Yosys 0.52 .. Yosys 0.53
-------------------------- --------------------------
* New commands and options * New commands and options

View file

@ -20,6 +20,7 @@ passes/opt/opt_lut.cc @whitequark
passes/techmap/abc9*.cc @eddiehung @Ravenslofty passes/techmap/abc9*.cc @eddiehung @Ravenslofty
backends/aiger/xaiger.cc @eddiehung backends/aiger/xaiger.cc @eddiehung
docs/ @KrystalDelusion docs/ @KrystalDelusion
docs/source/using_yosys/synthesis/abc.rst @KrystalDelusion @Ravenslofty
.github/workflows/*.yml @mmicko .github/workflows/*.yml @mmicko
## External Contributors ## External Contributors

View file

@ -160,7 +160,7 @@ ifeq ($(OS), Haiku)
CXXFLAGS += -D_DEFAULT_SOURCE CXXFLAGS += -D_DEFAULT_SOURCE
endif endif
YOSYS_VER := 0.53+3 YOSYS_VER := 0.54+0
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
@ -183,7 +183,7 @@ endif
OBJS = kernel/version_$(GIT_REV).o OBJS = kernel/version_$(GIT_REV).o
bumpversion: bumpversion:
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 53c22ab.. | wc -l`/;" Makefile sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline db72ec3.. | wc -l`/;" Makefile
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
@ -204,7 +204,7 @@ endif
include Makefile.conf include Makefile.conf
endif endif
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) PYTHON_EXECUTABLE ?= $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
ifeq ($(ENABLE_PYOSYS),1) ifeq ($(ENABLE_PYOSYS),1)
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
@ -455,6 +455,7 @@ endif
ifeq ($(ENABLE_DEBUG),1) ifeq ($(ENABLE_DEBUG),1)
CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS)) CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS))
STRIP :=
endif endif
ifeq ($(ENABLE_ABC),1) ifeq ($(ENABLE_ABC),1)
@ -894,6 +895,7 @@ SH_TEST_DIRS += tests/bram
SH_TEST_DIRS += tests/svinterfaces SH_TEST_DIRS += tests/svinterfaces
SH_TEST_DIRS += tests/xprop SH_TEST_DIRS += tests/xprop
SH_TEST_DIRS += tests/select SH_TEST_DIRS += tests/select
SH_TEST_DIRS += tests/peepopt
SH_TEST_DIRS += tests/proc SH_TEST_DIRS += tests/proc
SH_TEST_DIRS += tests/blif SH_TEST_DIRS += tests/blif
SH_TEST_DIRS += tests/arch SH_TEST_DIRS += tests/arch
@ -982,20 +984,20 @@ install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR) $(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR)
ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),) ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),)
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys; fi
endif endif
ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),) ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),)
$(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc; fi
endif endif
ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),) ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),)
$(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib; fi
endif endif
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1) ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/ $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so; fi
ifeq ($(ENABLE_PYOSYS),1) ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so

View file

@ -132,7 +132,7 @@ struct AigerWriter
return a; return a;
} }
AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module) AigerWriter(Module *module, bool no_sort, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
{ {
pool<SigBit> undriven_bits; pool<SigBit> undriven_bits;
pool<SigBit> unused_bits; pool<SigBit> unused_bits;
@ -152,6 +152,37 @@ struct AigerWriter
if (wire->port_input) if (wire->port_input)
sigmap.add(wire); sigmap.add(wire);
// handle ports
// provided the input_bits and output_bits don't get sorted they
// will be returned in reverse order, so add them in reverse to
// match
for (auto riter = module->ports.rbegin(); riter != module->ports.rend(); ++riter) {
auto *wire = module->wire(*riter);
for (int i = 0; i < GetSize(wire); i++)
{
SigBit wirebit(wire, i);
SigBit bit = sigmap(wirebit);
if (bit.wire == nullptr) {
if (wire->port_output) {
aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
output_bits.insert(wirebit);
}
continue;
}
if (wire->port_input)
input_bits.insert(bit);
if (wire->port_output) {
if (bit != wirebit)
alias_map[wirebit] = bit;
output_bits.insert(wirebit);
}
}
}
// handle wires
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if (wire->attributes.count(ID::init)) { if (wire->attributes.count(ID::init)) {
@ -167,25 +198,13 @@ struct AigerWriter
SigBit wirebit(wire, i); SigBit wirebit(wire, i);
SigBit bit = sigmap(wirebit); SigBit bit = sigmap(wirebit);
if (bit.wire == nullptr) { if (bit.wire == nullptr)
if (wire->port_output) { continue;
aig_map[wirebit] = (bit == State::S1) ? 1 : 0; if (wire->port_input || wire->port_output)
output_bits.insert(wirebit);
}
continue; continue;
}
undriven_bits.insert(bit); undriven_bits.insert(bit);
unused_bits.insert(bit); unused_bits.insert(bit);
if (wire->port_input)
input_bits.insert(bit);
if (wire->port_output) {
if (bit != wirebit)
alias_map[wirebit] = bit;
output_bits.insert(wirebit);
}
} }
if (wire->width == 1) { if (wire->width == 1) {
@ -200,12 +219,6 @@ struct AigerWriter
} }
} }
for (auto bit : input_bits)
undriven_bits.erase(bit);
for (auto bit : output_bits)
unused_bits.erase(bit);
for (auto cell : module->cells()) for (auto cell : module->cells())
{ {
if (cell->type == ID($_NOT_)) if (cell->type == ID($_NOT_))
@ -343,8 +356,11 @@ struct AigerWriter
} }
init_map.sort(); init_map.sort();
input_bits.sort(); // we are relying here on unsorted pools iterating last-in-first-out
output_bits.sort(); if (!no_sort) {
input_bits.sort();
output_bits.sort();
}
not_map.sort(); not_map.sort();
ff_map.sort(); ff_map.sort();
and_map.sort(); and_map.sort();
@ -662,8 +678,7 @@ struct AigerWriter
f << std::endl; f << std::endl;
} }
} }
f << stringf("c\nGenerated by %s\n", yosys_maybe_version());
f << stringf("c\nGenerated by %s\n", yosys_version_str);
} }
void write_map(std::ostream &f, bool verbose_map, bool no_startoffset) void write_map(std::ostream &f, bool verbose_map, bool no_startoffset)
@ -698,7 +713,7 @@ struct AigerWriter
} }
if (wire->port_output) { if (wire->port_output) {
int o = ordered_outputs.at(sig[i]); int o = ordered_outputs.at(SigSpec(wire, i));
output_lines[o] += stringf("output %d %d %s\n", o, index, log_id(wire)); output_lines[o] += stringf("output %d %d %s\n", o, index, log_id(wire));
} }
@ -746,7 +761,7 @@ struct AigerWriter
{ {
json.begin_object(); json.begin_object();
json.entry("version", "Yosys Witness Aiger map"); json.entry("version", "Yosys Witness Aiger map");
json.entry("gennerator", yosys_version_str); json.entry("gennerator", yosys_maybe_version());
json.entry("latch_count", aig_l); json.entry("latch_count", aig_l);
json.entry("input_count", aig_i); json.entry("input_count", aig_i);
@ -902,6 +917,9 @@ struct AigerBackend : public Backend {
log(" -symbols\n"); log(" -symbols\n");
log(" include a symbol table in the generated AIGER file\n"); log(" include a symbol table in the generated AIGER file\n");
log("\n"); log("\n");
log(" -no-sort\n");
log(" don't sort input/output ports\n");
log("\n");
log(" -map <filename>\n"); log(" -map <filename>\n");
log(" write an extra file with port and latch symbols\n"); log(" write an extra file with port and latch symbols\n");
log("\n"); log("\n");
@ -926,6 +944,7 @@ struct AigerBackend : public Backend {
bool zinit_mode = false; bool zinit_mode = false;
bool miter_mode = false; bool miter_mode = false;
bool symbols_mode = false; bool symbols_mode = false;
bool no_sort = false;
bool verbose_map = false; bool verbose_map = false;
bool imode = false; bool imode = false;
bool omode = false; bool omode = false;
@ -956,6 +975,10 @@ struct AigerBackend : public Backend {
symbols_mode = true; symbols_mode = true;
continue; continue;
} }
if (args[argidx] == "-no-sort") {
no_sort = true;
continue;
}
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) { if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
map_filename = args[++argidx]; map_filename = args[++argidx];
continue; continue;
@ -1009,7 +1032,7 @@ struct AigerBackend : public Backend {
if (!top_module->memories.empty()) if (!top_module->memories.empty())
log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", log_id(top_module)); log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", log_id(top_module));
AigerWriter writer(top_module, zinit_mode, imode, omode, bmode, lmode); AigerWriter writer(top_module, no_sort, zinit_mode, imode, omode, bmode, lmode);
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
if (!map_filename.empty()) { if (!map_filename.empty()) {

View file

@ -671,7 +671,7 @@ struct XAigerWriter
//f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); //f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
//f.write(buffer_str.data(), buffer_str.size()); //f.write(buffer_str.data(), buffer_str.size());
f << stringf("Generated by %s\n", yosys_version_str); f << stringf("Generated by %s\n", yosys_maybe_version());
design->scratchpad_set_int("write_xaiger.num_ands", and_map.size()); design->scratchpad_set_int("write_xaiger.num_ands", and_map.size());
design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size()); design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size());

View file

@ -649,7 +649,7 @@ struct BlifBackend : public Backend {
if (module->get_bool_attribute(ID::top)) if (module->get_bool_attribute(ID::top))
top_module_name = module->name.str(); top_module_name = module->name.str();
*f << stringf("# Generated by %s\n", yosys_version_str); *f << stringf("# Generated by %s\n", yosys_maybe_version());
std::vector<RTLIL::Module*> mod_list; std::vector<RTLIL::Module*> mod_list;

View file

@ -1499,7 +1499,7 @@ struct BtorWorker
{ {
ywmap_json.begin_object(); ywmap_json.begin_object();
ywmap_json.entry("version", "Yosys Witness BTOR map"); ywmap_json.entry("version", "Yosys Witness BTOR map");
ywmap_json.entry("generator", yosys_version_str); ywmap_json.entry("generator", yosys_maybe_version());
ywmap_json.name("clocks"); ywmap_json.name("clocks");
ywmap_json.begin_array(); ywmap_json.begin_array();
@ -1613,7 +1613,7 @@ struct BtorBackend : public Backend {
log_cmd_error("No top module found.\n"); log_cmd_error("No top module found.\n");
*f << stringf("; BTOR description generated by %s for module %s.\n", *f << stringf("; BTOR description generated by %s for module %s.\n",
yosys_version_str, log_id(topmod)); yosys_maybe_version(), log_id(topmod));
BtorWorker(*f, topmod, verbose, single_bad, cover_mode, print_internal_names, info_filename, ywmap_filename); BtorWorker(*f, topmod, verbose, single_bad, cover_mode, print_internal_names, info_filename, ywmap_filename);

View file

@ -2429,8 +2429,6 @@ struct CxxrtlWorker {
inc_indent(); inc_indent();
for (auto wire : module->wires()) { for (auto wire : module->wires()) {
const auto &debug_wire_type = debug_wire_types[wire]; const auto &debug_wire_type = debug_wire_types[wire];
if (!wire->name.isPublic())
continue;
count_public_wires++; count_public_wires++;
switch (debug_wire_type.type) { switch (debug_wire_type.type) {
case WireType::BUFFERED: case WireType::BUFFERED:
@ -2438,6 +2436,9 @@ struct CxxrtlWorker {
// Member wire // Member wire
std::vector<std::string> flags; std::vector<std::string> flags;
if (!wire->name.isPublic())
flags.push_back("GENERATED");
if (wire->port_input && wire->port_output) if (wire->port_input && wire->port_output)
flags.push_back("INOUT"); flags.push_back("INOUT");
else if (wire->port_output) else if (wire->port_output)

View file

@ -200,6 +200,10 @@ enum cxxrtl_flag {
// node, such as inputs and dangling wires. // node, such as inputs and dangling wires.
CXXRTL_UNDRIVEN = 1 << 4, CXXRTL_UNDRIVEN = 1 << 4,
// Generated correspond to netlist nodes that correspond to state with an internal name, that
// need to be saved, but wouldn't otherwise have a debug item generated.
CXXRTL_GENERATED = 1 << 5,
// More object flags may be added in the future, but the existing ones will never change. // More object flags may be added in the future, but the existing ones will never change.
}; };

View file

@ -1294,6 +1294,7 @@ struct debug_item : ::cxxrtl_object {
DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC, DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC,
DRIVEN_COMB = CXXRTL_DRIVEN_COMB, DRIVEN_COMB = CXXRTL_DRIVEN_COMB,
UNDRIVEN = CXXRTL_UNDRIVEN, UNDRIVEN = CXXRTL_UNDRIVEN,
GENERATED = CXXRTL_GENERATED,
}; };
debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {} debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {}

View file

@ -231,7 +231,8 @@ struct EdifBackend : public Backend {
*f << stringf(" (edifVersion 2 0 0)\n"); *f << stringf(" (edifVersion 2 0 0)\n");
*f << stringf(" (edifLevel 0)\n"); *f << stringf(" (edifLevel 0)\n");
*f << stringf(" (keywordMap (keywordLevel 0))\n"); *f << stringf(" (keywordMap (keywordLevel 0))\n");
*f << stringf(" (comment \"Generated by %s\")\n", yosys_version_str);
*f << stringf(" (comment \"Generated by %s\")\n", yosys_maybe_version());
*f << stringf(" (external LIB\n"); *f << stringf(" (external LIB\n");
*f << stringf(" (edifLevel 0)\n"); *f << stringf(" (edifLevel 0)\n");

View file

@ -125,7 +125,7 @@ struct JnyWriter
f << "{\n"; f << "{\n";
f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/main/misc/jny.schema.json\",\n"; f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/main/misc/jny.schema.json\",\n";
f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_version_str).c_str()); f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_maybe_version()).c_str());
f << " \"version\": \"0.0.1\",\n"; f << " \"version\": \"0.0.1\",\n";
f << " \"invocation\": \"" << escape_string(invk) << "\",\n"; f << " \"invocation\": \"" << escape_string(invk) << "\",\n";
f << " \"features\": ["; f << " \"features\": [";

View file

@ -291,7 +291,7 @@ struct JsonWriter
design->sort(); design->sort();
f << stringf("{\n"); f << stringf("{\n");
f << stringf(" \"creator\": %s,\n", get_string(yosys_version_str).c_str()); f << stringf(" \"creator\": %s,\n", get_string(yosys_maybe_version()).c_str());
f << stringf(" \"modules\": {\n"); f << stringf(" \"modules\": {\n");
vector<Module*> modules = use_selection ? design->selected_modules() : design->modules(); vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
bool first_module = true; bool first_module = true;

View file

@ -459,7 +459,8 @@ struct RTLILBackend : public Backend {
design->sort(); design->sort();
log("Output filename: %s\n", filename.c_str()); log("Output filename: %s\n", filename.c_str());
*f << stringf("# Generated by %s\n", yosys_version_str);
*f << stringf("# Generated by %s\n", yosys_maybe_version());
RTLIL_BACKEND::dump_design(*f, design, selected, true, false); RTLIL_BACKEND::dump_design(*f, design, selected, true, false);
} }
} RTLILBackend; } RTLILBackend;

View file

@ -1831,7 +1831,7 @@ struct Smt2Backend : public Backend {
} }
} }
*f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_version_str); *f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_maybe_version());
if (!bvmode) if (!bvmode)
*f << stringf("; yosys-smt2-nobv\n"); *f << stringf("; yosys-smt2-nobv\n");

View file

@ -797,7 +797,7 @@ struct SmvBackend : public Backend {
if (module == nullptr) if (module == nullptr)
log_error("Module '%s' not found.\n", stmt[1].c_str()); log_error("Module '%s' not found.\n", stmt[1].c_str());
*f << stringf("-- SMV description generated by %s\n", yosys_version_str); *f << stringf("-- SMV description generated by %s\n", yosys_maybe_version());
log("Creating SMV representation of module %s.\n", log_id(module)); log("Creating SMV representation of module %s.\n", log_id(module));
SmvWorker worker(module, verbose, *f); SmvWorker worker(module, verbose, *f);
@ -816,7 +816,7 @@ struct SmvBackend : public Backend {
if (!modules.empty()) if (!modules.empty())
{ {
*f << stringf("-- SMV description generated by %s\n", yosys_version_str); *f << stringf("-- SMV description generated by %s\n", yosys_maybe_version());
for (auto module : modules) { for (auto module : modules) {
log("Creating SMV representation of module %s.\n", log_id(module)); log("Creating SMV representation of module %s.\n", log_id(module));

View file

@ -215,7 +215,7 @@ struct SpiceBackend : public Backend {
if (module->get_bool_attribute(ID::top)) if (module->get_bool_attribute(ID::top))
top_module_name = module->name.str(); top_module_name = module->name.str();
*f << stringf("* SPICE netlist generated by %s\n", yosys_version_str); *f << stringf("* SPICE netlist generated by %s\n", yosys_maybe_version());
*f << stringf("\n"); *f << stringf("\n");
for (auto module : design->modules()) for (auto module : design->modules())

View file

@ -383,6 +383,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString,
if (attr2comment) if (attr2comment)
as_comment = true; as_comment = true;
for (auto it = attributes.begin(); it != attributes.end(); ++it) { for (auto it = attributes.begin(); it != attributes.end(); ++it) {
if (it->first == ID::single_bit_vector) continue;
if (it->first == ID::init && regattr) continue; if (it->first == ID::init && regattr) continue;
f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str()); f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str());
f << stringf(" = "); f << stringf(" = ");
@ -419,6 +420,9 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset); range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
else else
range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset); range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
} else {
if (wire->attributes.count(ID::single_bit_vector))
range = stringf(" [%d:%d]", wire->start_offset, wire->start_offset);
} }
if (wire->port_input && !wire->port_output) if (wire->port_input && !wire->port_output)
f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str()); f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
@ -2596,7 +2600,8 @@ struct VerilogBackend : public Backend {
design->sort(); design->sort();
*f << stringf("/* Generated by %s */\n", yosys_version_str); *f << stringf("/* Generated by %s */\n", yosys_maybe_version());
for (auto module : design->modules()) { for (auto module : design->modules()) {
if (module->get_blackbox_attribute() != blackboxes) if (module->get_blackbox_attribute() != blackboxes)
continue; continue;

View file

@ -72,7 +72,7 @@ circuits.
Tools exist to synthesize high level code (usually in the form of C/C++/SystemC Tools exist to synthesize high level code (usually in the form of C/C++/SystemC
code with additional metadata) to behavioural HDL code (usually in the form of code with additional metadata) to behavioural HDL code (usually in the form of
Verilog or VHDL code). Aside from the many commercial tools for high level Verilog or VHDL code). Aside from the many commercial tools for high level
synthesis there are also a number of FOSS tools for high level synthesis . synthesis there are also a number of FOSS tools for high level synthesis.
Behavioural level Behavioural level
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -185,7 +185,7 @@ advantage that it has a unique normalized form. The latter has much better worst
case performance and is therefore better suited for the synthesis of large logic case performance and is therefore better suited for the synthesis of large logic
functions. functions.
Good FOSS tools exists for multi-level logic synthesis . Good FOSS tools exists for multi-level logic synthesis.
Yosys contains basic logic synthesis functionality but can also use ABC for the Yosys contains basic logic synthesis functionality but can also use ABC for the
logic synthesis step. Using ABC is recommended. logic synthesis step. Using ABC is recommended.
@ -221,7 +221,7 @@ design description as input and generates an RTL, logical gate or physical gate
level description of the design as output. Yosys' main strengths are behavioural level description of the design as output. Yosys' main strengths are behavioural
and RTL synthesis. A wide range of commands (synthesis passes) exist within and RTL synthesis. A wide range of commands (synthesis passes) exist within
Yosys that can be used to perform a wide range of synthesis tasks within the Yosys that can be used to perform a wide range of synthesis tasks within the
domain of behavioural, rtl and logic synthesis. Yosys is designed to be domain of behavioural, RTL and logic synthesis. Yosys is designed to be
extensible and therefore is a good basis for implementing custom synthesis tools extensible and therefore is a good basis for implementing custom synthesis tools
for specialised tasks. for specialised tasks.
@ -572,7 +572,7 @@ of lexical tokens given in :numref:`Tab. %s <tab:Basics_tokens>`.
TOK_SEMICOLON \- TOK_SEMICOLON \-
============== =============== ============== ===============
The lexer is usually generated by a lexer generator (e.g. flex ) from a The lexer is usually generated by a lexer generator (e.g. flex) from a
description file that is using regular expressions to specify the text pattern description file that is using regular expressions to specify the text pattern
that should match the individual tokens. that should match the individual tokens.

View file

@ -6,7 +6,7 @@ import os
project = 'YosysHQ Yosys' project = 'YosysHQ Yosys'
author = 'YosysHQ GmbH' author = 'YosysHQ GmbH'
copyright ='2025 YosysHQ GmbH' copyright ='2025 YosysHQ GmbH'
yosys_ver = "0.53" yosys_ver = "0.54"
# select HTML theme # select HTML theme
html_theme = 'furo-ys' html_theme = 'furo-ys'

View file

@ -73,7 +73,7 @@ contain bits that are not 0 or 1 (i.e. ``x`` or ``z``). Ordinary 32-bit
constants are written using decimal numbers. constants are written using decimal numbers.
Single-bit signals are shown as thin arrows pointing from the driver to the Single-bit signals are shown as thin arrows pointing from the driver to the
load. Signals that are multiple bits wide are shown as think arrows. load. Signals that are multiple bits wide are shown as thick arrows.
Finally *processes* are shown in boxes with round corners. Processes are Yosys' Finally *processes* are shown in boxes with round corners. Processes are Yosys'
internal representation of the decision-trees and synchronization events internal representation of the decision-trees and synchronization events

View file

@ -176,5 +176,6 @@ implemented as whiteboxes too.
Boxes are arguably the biggest advantage that ABC9 has over ABC: by being aware Boxes are arguably the biggest advantage that ABC9 has over ABC: by being aware
of carry chains and DSPs, it avoids optimising for a path that isn't the actual of carry chains and DSPs, it avoids optimising for a path that isn't the actual
critical path, while the generally-longer paths result in ABC9 being able to critical path, while the generally-longer paths result in ABC9 being able to
reduce design area by mapping other logic to larger-but-slower cells. reduce design area by mapping other logic to slower cells with greater logic
density.

View file

@ -626,7 +626,7 @@ pass and the passes it launches:
| This pass replaces the ``RTLIL::SyncRule``\ s to d-type flip-flops (with | This pass replaces the ``RTLIL::SyncRule``\ s to d-type flip-flops (with
asynchronous resets if necessary). asynchronous resets if necessary).
- | `proc_dff` - | `proc_memwr`
| This pass replaces the ``RTLIL::MemWriteAction``\ s with `$memwr` cells. | This pass replaces the ``RTLIL::MemWriteAction``\ s with `$memwr` cells.
- | `proc_clean` - | `proc_clean`

View file

@ -375,3 +375,9 @@ from SystemVerilog:
ports are inputs or outputs are supported. ports are inputs or outputs are supported.
- Assignments within expressions are supported. - Assignments within expressions are supported.
- The ``unique``, ``unique0``, and ``priority`` SystemVerilog keywords are
accepted on ``if`` and ``case`` conditionals. (Those keywords are currently
handled in the same way as their equivalent ``full_case`` and
``parallel_case`` attributes on ``case`` statements, and checked
for syntactic validity but otherwise ignored on ``if`` statements.)

View file

@ -1446,6 +1446,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
wire->port_input = is_input; wire->port_input = is_input;
wire->port_output = is_output; wire->port_output = is_output;
wire->upto = range_swapped; wire->upto = range_swapped;
wire->is_signed = is_signed; wire->is_signed = is_signed;
for (auto &attr : attributes) { for (auto &attr : attributes) {

View file

@ -1433,6 +1433,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
current_ast_mod->children.push_back(wnode); current_ast_mod->children.push_back(wnode);
} }
basic_prep = true; basic_prep = true;
is_custom_type = false;
} }
break; break;
@ -1932,6 +1933,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
// Prepare replacement node. // Prepare replacement node.
newNode = template_node->clone(); newNode = template_node->clone();
newNode->str = str; newNode->str = str;
if (newNode->attributes.count(ID::wiretype))
delete newNode->attributes[ID::wiretype];
newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
newNode->is_input = is_input; newNode->is_input = is_input;
newNode->is_output = is_output; newNode->is_output = is_output;
@ -2084,6 +2087,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
std::swap(range_left, range_right); std::swap(range_left, range_right);
range_swapped = force_upto; range_swapped = force_upto;
} }
if (range_left == range_right && !attributes.count(ID::single_bit_vector))
set_attribute(ID::single_bit_vector, mkconst_int(1, false));
} }
} else { } else {
if (!range_valid) if (!range_valid)
@ -2092,6 +2097,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
range_swapped = false; range_swapped = false;
range_left = 0; range_left = 0;
range_right = 0; range_right = 0;
if (attributes.count(ID::single_bit_vector)) {
delete attributes[ID::single_bit_vector];
attributes.erase(ID::single_bit_vector);
}
} }
} }
@ -4091,16 +4100,24 @@ skip_dynamic_range_lvalue_expansion:;
delete arg; delete arg;
continue; continue;
} }
AstNode *wire_id = new AstNode(AST_IDENTIFIER); AstNode *wire_id = new AstNode(AST_IDENTIFIER);
wire_id->str = wire->str; wire_id->str = wire->str;
AstNode *assign = child->is_input ?
new AstNode(AST_ASSIGN_EQ, wire_id, arg) : if (child->is_input) {
new AstNode(AST_ASSIGN_EQ, arg, wire_id); AstNode *assign = new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg->clone());
assign->children[0]->was_checked = true; assign->children[0]->was_checked = true;
if (child->is_input)
new_stmts.push_back(assign); new_stmts.push_back(assign);
else }
if (child->is_output) {
AstNode *assign = new AstNode(AST_ASSIGN_EQ, arg->clone(), wire_id->clone());
assign->children[0]->was_checked = true;
output_assignments.push_back(assign); output_assignments.push_back(assign);
}
delete arg;
delete wire_id;
} }
} }

View file

@ -1557,6 +1557,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex()); wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
wire->upto = portbus->IsUp(); wire->upto = portbus->IsUp();
import_attributes(wire->attributes, portbus, nl, portbus->Size()); import_attributes(wire->attributes, portbus, nl, portbus->Size());
if (portbus->Size() == 1)
wire->set_bool_attribute(ID::single_bit_vector);
SetIter si ; SetIter si ;
Port *port ; Port *port ;
FOREACH_PORT_OF_PORTBUS(portbus, si, port) { FOREACH_PORT_OF_PORTBUS(portbus, si, port) {
@ -1755,6 +1757,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
break; break;
} }
import_attributes(wire->attributes, netbus, nl, netbus->Size()); import_attributes(wire->attributes, netbus, nl, netbus->Size());
if (netbus->Size() == 1)
wire->set_bool_attribute(ID::single_bit_vector);
RTLIL::Const initval = Const(State::Sx, GetSize(wire)); RTLIL::Const initval = Const(State::Sx, GetSize(wire));
bool initval_valid = false; bool initval_valid = false;
@ -3485,6 +3489,14 @@ struct VerificPass : public Pass {
// WARNING: instantiating unknown module 'XYZ' (VERI-1063) // WARNING: instantiating unknown module 'XYZ' (VERI-1063)
Message::SetMessageType("VERI-1063", VERIFIC_ERROR); Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
// Downgrade warnings about things that are normal
// VERIFIC-WARNING [VERI-1209] foo.sv:98: expression size 7 truncated to fit in target size 6
Message::SetMessageType("VERI-1209", VERIFIC_INFO);
// VERIFIC-WARNING [VERI-1142] foo.sv:55: system task 'display' is ignored for synthesis
Message::SetMessageType("VERI-1142", VERIFIC_INFO);
// VERIFIC-WARNING [VERI-2418] foo.svh:503: parameter 'all_cfgs_gp' declared inside package 'bp_common_pkg' shall be treated as localparam
Message::SetMessageType("VERI-2418", VERIFIC_INFO);
// https://github.com/YosysHQ/yosys/issues/1055 // https://github.com/YosysHQ/yosys/issues/1055
RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ; RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ;
#endif #endif
@ -3543,6 +3555,9 @@ struct VerificPass : public Pass {
} else if (Strings::compare(args[argidx].c_str(), "warnings")) { } else if (Strings::compare(args[argidx].c_str(), "warnings")) {
Message::SetAllMessageType(VERIFIC_WARNING, new_type); Message::SetAllMessageType(VERIFIC_WARNING, new_type);
} else if (Strings::compare(args[argidx].c_str(), "infos")) { } else if (Strings::compare(args[argidx].c_str(), "infos")) {
Message::SetMessageType("VERI-1209", new_type);
Message::SetMessageType("VERI-1142", new_type);
Message::SetMessageType("VERI-2418", new_type);
Message::SetAllMessageType(VERIFIC_INFO, new_type); Message::SetAllMessageType(VERIFIC_INFO, new_type);
} else if (Strings::compare(args[argidx].c_str(), "comments")) { } else if (Strings::compare(args[argidx].c_str(), "comments")) {
Message::SetAllMessageType(VERIFIC_COMMENT, new_type); Message::SetAllMessageType(VERIFIC_COMMENT, new_type);

View file

@ -336,7 +336,8 @@ static AstNode *addIncOrDecExpr(AstNode *lhs, dict<IdString, AstNode*> *attr, AS
log_assert(stmt->type == AST_ASSIGN_EQ); log_assert(stmt->type == AST_ASSIGN_EQ);
AstNode *expr = stmt->children[0]->clone(); AstNode *expr = stmt->children[0]->clone();
if (undo) { if (undo) {
AstNode *minus_one = AstNode::mkconst_int(-1, true, 1); AstNode *one = AstNode::mkconst_int(1, false, 1);
AstNode *minus_one = new AstNode(AST_NEG, one);
expr = new AstNode(op, expr, minus_one); expr = new AstNode(op, expr, minus_one);
} }
SET_AST_NODE_LOC(expr, begin, end); SET_AST_NODE_LOC(expr, begin, end);
@ -426,7 +427,7 @@ static const AstNode *addAsgnBinopStmt(dict<IdString, AstNode*> *attr, AstNode *
%type <boolean> opt_property always_comb_or_latch always_or_always_ff %type <boolean> opt_property always_comb_or_latch always_or_always_ff
%type <boolean> opt_signedness_default_signed opt_signedness_default_unsigned %type <boolean> opt_signedness_default_signed opt_signedness_default_unsigned
%type <integer> integer_atom_type integer_vector_type %type <integer> integer_atom_type integer_vector_type
%type <al> attr case_attr %type <al> attr if_attr case_attr
%type <ast> struct_union %type <ast> struct_union
%type <ast_node_type> asgn_binop inc_or_dec_op %type <ast_node_type> asgn_binop inc_or_dec_op
%type <ast> genvar_identifier %type <ast> genvar_identifier
@ -1855,7 +1856,7 @@ struct_decl:
} }
; ;
struct_type: struct_union { astbuf2 = $1; } struct_body { $$ = astbuf2; } struct_type: struct_union { astbuf2 = $1; astbuf2->is_custom_type = true; } struct_body { $$ = astbuf2; }
; ;
struct_union: struct_union:
@ -2871,7 +2872,7 @@ behavioral_stmt:
ast_stack.pop_back(); ast_stack.pop_back();
ast_stack.pop_back(); ast_stack.pop_back();
} | } |
attr TOK_IF '(' expr ')' { if_attr TOK_IF '(' expr ')' {
AstNode *node = new AstNode(AST_CASE); AstNode *node = new AstNode(AST_CASE);
AstNode *block = new AstNode(AST_BLOCK); AstNode *block = new AstNode(AST_BLOCK);
AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block); AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block);
@ -2901,6 +2902,29 @@ behavioral_stmt:
ast_stack.pop_back(); ast_stack.pop_back();
}; };
if_attr:
attr {
$$ = $1;
} |
attr TOK_UNIQUE0 {
AstNode *context = ast_stack.back();
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) )
frontend_verilog_yyerror("unique0 keyword cannot be used for 'else if' branch.");
$$ = $1; // accept unique0 keyword, but ignore it for now
} |
attr TOK_PRIORITY {
AstNode *context = ast_stack.back();
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) )
frontend_verilog_yyerror("priority keyword cannot be used for 'else if' branch.");
$$ = $1; // accept priority keyword, but ignore it for now
} |
attr TOK_UNIQUE {
AstNode *context = ast_stack.back();
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) )
frontend_verilog_yyerror("unique keyword cannot be used for 'else if' branch.");
$$ = $1; // accept unique keyword, but ignore it for now
};
case_attr: case_attr:
attr { attr {
$$ = $1; $$ = $1;
@ -2948,6 +2972,7 @@ behavioral_stmt_list:
optional_else: optional_else:
TOK_ELSE { TOK_ELSE {
AstNode *block = new AstNode(AST_BLOCK); AstNode *block = new AstNode(AST_BLOCK);
block->attributes[ID::promoted_if] = AstNode::mkconst_int(1, false );
AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block); AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block);
SET_AST_NODE_LOC(cond, @1, @1); SET_AST_NODE_LOC(cond, @1, @1);

View file

@ -153,6 +153,7 @@ X(parameter)
X(PORTID) X(PORTID)
X(PRIORITY) X(PRIORITY)
X(PRIORITY_MASK) X(PRIORITY_MASK)
X(promoted_if)
X(Q) X(Q)
X(R) X(R)
X(ram_block) X(ram_block)
@ -184,6 +185,7 @@ X(romstyle)
X(S) X(S)
X(SET) X(SET)
X(SET_POLARITY) X(SET_POLARITY)
X(single_bit_vector)
X(SIZE) X(SIZE)
X(SRC) X(SRC)
X(src) X(src)

View file

@ -252,6 +252,7 @@ int main(int argc, char **argv)
options.add_options("logging") options.add_options("logging")
("Q", "suppress printing of banner (copyright, disclaimer, version)") ("Q", "suppress printing of banner (copyright, disclaimer, version)")
("T", "suppress printing of footer (log hash, version, timing statistics)") ("T", "suppress printing of footer (log hash, version, timing statistics)")
("no-version", "suppress writing out Yosys version anywhere excluding -V, --version")
("q,quiet", "quiet operation. Only write warnings and error messages to console. " \ ("q,quiet", "quiet operation. Only write warnings and error messages to console. " \
"Use this option twice to also quiet warning messages") "Use this option twice to also quiet warning messages")
("v,verbose", "print log headers up to <level> to the console. " \ ("v,verbose", "print log headers up to <level> to the console. " \
@ -318,6 +319,7 @@ int main(int argc, char **argv)
if (result.count("A")) call_abort = true; if (result.count("A")) call_abort = true;
if (result.count("Q")) print_banner = false; if (result.count("Q")) print_banner = false;
if (result.count("T")) print_stats = false; if (result.count("T")) print_stats = false;
if (result.count("no-version")) yosys_write_versions = false;
if (result.count("V")) { if (result.count("V")) {
std::cout << yosys_version_str << std::endl; std::cout << yosys_version_str << std::endl;
exit(0); exit(0);
@ -691,7 +693,7 @@ int main(int argc, char **argv)
stats_divider.c_str(), ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec, stats_divider.c_str(), ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec, meminfo.c_str()); ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec, meminfo.c_str());
#endif #endif
log("%s\n", yosys_version_str); log("%s\n", yosys_maybe_version());
int64_t total_ns = 0; int64_t total_ns = 0;
std::set<tuple<int64_t, int, std::string>> timedat; std::set<tuple<int64_t, int, std::string>> timedat;
@ -731,7 +733,7 @@ int main(int argc, char **argv)
log_error("Can't open performance log file for writing: %s\n", strerror(errno)); log_error("Can't open performance log file for writing: %s\n", strerror(errno));
fprintf(f, "{\n"); fprintf(f, "{\n");
fprintf(f, " \"generator\": \"%s\",\n", yosys_version_str); fprintf(f, " \"generator\": \"%s\",\n", yosys_maybe_version());
fprintf(f, " \"total_ns\": %" PRIu64 ",\n", total_ns); fprintf(f, " \"total_ns\": %" PRIu64 ",\n", total_ns);
fprintf(f, " \"passes\": {"); fprintf(f, " \"passes\": {");

View file

@ -206,6 +206,7 @@ static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandl
void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */) void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
{ {
if (pnt_time > end_time || !pnt_value) return; if (pnt_time > end_time || !pnt_value) return;
if (curr_cycle > last_cycle) return;
// if we are past the timestamp // if we are past the timestamp
bool is_clock = false; bool is_clock = false;
if (!all_samples) { if (!all_samples) {
@ -225,6 +226,7 @@ void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_faci
if (pnt_time > last_time) { if (pnt_time > last_time) {
if (all_samples) { if (all_samples) {
callback(last_time); callback(last_time);
curr_cycle++;
last_time = pnt_time; last_time = pnt_time;
} else { } else {
if (is_clock) { if (is_clock) {
@ -232,6 +234,7 @@ void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_faci
std::string prev = past_data[pnt_facidx]; std::string prev = past_data[pnt_facidx];
if ((prev!="1" && val=="1") || (prev!="0" && val=="0")) { if ((prev!="1" && val=="1") || (prev!="0" && val=="0")) {
callback(last_time); callback(last_time);
curr_cycle++;
last_time = pnt_time; last_time = pnt_time;
} }
} }
@ -241,12 +244,14 @@ void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_faci
last_data[pnt_facidx] = std::string((const char *)pnt_value); last_data[pnt_facidx] = std::string((const char *)pnt_value);
} }
void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start, uint64_t end, CallbackFunction cb) void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start, uint64_t end, unsigned int end_cycle, CallbackFunction cb)
{ {
clk_signals = signal; clk_signals = signal;
callback = cb; callback = cb;
start_time = start; start_time = start;
end_time = end; end_time = end;
curr_cycle = 0;
last_cycle = end_cycle;
last_data.clear(); last_data.clear();
last_time = start_time; last_time = start_time;
past_data.clear(); past_data.clear();
@ -256,12 +261,16 @@ void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t sta
fstReaderSetUnlimitedTimeRange(ctx); fstReaderSetUnlimitedTimeRange(ctx);
fstReaderSetFacProcessMaskAll(ctx); fstReaderSetFacProcessMaskAll(ctx);
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr); fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
if (last_time!=end_time) { if (last_time!=end_time && curr_cycle <= last_cycle) {
past_data = last_data; past_data = last_data;
callback(last_time); callback(last_time);
curr_cycle++;
}
if (curr_cycle <= last_cycle) {
past_data = last_data;
callback(end_time);
curr_cycle++;
} }
past_data = last_data;
callback(end_time);
} }
std::string FstData::valueOf(fstHandle signal) std::string FstData::valueOf(fstHandle signal)

View file

@ -50,7 +50,7 @@ class FstData
std::vector<FstVar>& getVars() { return vars; }; std::vector<FstVar>& getVars() { return vars; };
void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen); void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
void reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time, CallbackFunction cb); void reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time, unsigned int end_cycle, CallbackFunction cb);
std::string valueOf(fstHandle signal); std::string valueOf(fstHandle signal);
fstHandle getHandle(std::string name); fstHandle getHandle(std::string name);
@ -73,6 +73,8 @@ private:
std::string timescale_str; std::string timescale_str;
uint64_t start_time; uint64_t start_time;
uint64_t end_time; uint64_t end_time;
unsigned int last_cycle;
unsigned int curr_cycle;
CallbackFunction callback; CallbackFunction callback;
std::vector<fstHandle> clk_signals; std::vector<fstHandle> clk_signals;
bool all_samples; bool all_samples;

View file

@ -102,6 +102,8 @@ gzip_istream::ibuf::~ibuf() {
// returns the original ifstream, rewound to the start. // returns the original ifstream, rewound to the start.
// Never returns nullptr or failed state istream* // Never returns nullptr or failed state istream*
std::istream* uncompressed(const std::string filename, std::ios_base::openmode mode) { std::istream* uncompressed(const std::string filename, std::ios_base::openmode mode) {
if (!check_file_exists(filename))
log_cmd_error("File `%s' not found or is a directory\n", filename.c_str());
std::ifstream* f = new std::ifstream(); std::ifstream* f = new std::ifstream();
f->open(filename, mode); f->open(filename, mode);
if (f->fail()) if (f->fail())
@ -125,7 +127,8 @@ std::istream* uncompressed(const std::string filename, std::ios_base::openmode m
filename.c_str(), unsigned(magic[2])); filename.c_str(), unsigned(magic[2]));
gzip_istream* s = new gzip_istream(); gzip_istream* s = new gzip_istream();
delete f; delete f;
log_assert(s->open(filename.c_str())); bool ok = s->open(filename.c_str());
log_assert(ok && "Failed to open gzipped file.\n");
return s; return s;
#else #else
log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str()); log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());

View file

@ -14,6 +14,7 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include <optional>
#include <string> #include <string>
#include <variant> #include <variant>
#include <vector> #include <vector>

View file

@ -247,11 +247,19 @@ std::string make_temp_dir(std::string template_str)
#endif #endif
} }
bool check_directory_exists(const std::string& dirname) bool check_is_directory(const std::string& dirname)
{ {
#if defined(_WIN32) #if defined(_WIN32)
struct _stat info; struct _stat info;
if (_stat(dirname.c_str(), &info) != 0) auto dirname_ = dirname;
/* On old versions of Visual Studio and current versions on MinGW,
_stat will fail if the path ends with a trailing slash. */
if (dirname.back() == '/' || dirname.back() == '\\') {
dirname_ = dirname.substr(0, dirname.length() - 1);
}
if (_stat(dirname_.c_str(), &info) != 0)
{ {
return false; return false;
} }
@ -267,17 +275,26 @@ bool check_directory_exists(const std::string& dirname)
} }
#ifdef _WIN32 #ifdef _WIN32
bool check_file_exists(std::string filename, bool) bool check_accessible(const std::string& filename, bool)
{ {
return _access(filename.c_str(), 0) == 0; return _access(filename.c_str(), 0) == 0;
} }
#else #else
bool check_file_exists(std::string filename, bool is_exec) bool check_accessible(const std::string& filename, bool is_exec)
{ {
return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0; return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
} }
#endif #endif
bool check_file_exists(const std::string& filename, bool is_exec)
{
return check_accessible(filename, is_exec) && !check_is_directory(filename);
}
bool check_directory_exists(const std::string& filename, bool is_exec)
{
return check_accessible(filename, is_exec) && check_is_directory(filename);
}
bool is_absolute_path(std::string filename) bool is_absolute_path(std::string filename)
{ {
#ifdef _WIN32 #ifdef _WIN32

View file

@ -64,6 +64,23 @@ inline std::string stringf(const char *fmt, ...)
return string; return string;
} }
int readsome(std::istream &f, char *s, int n);
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
bool patmatch(const char *pattern, const char *string);
#if !defined(YOSYS_DISABLE_SPAWN)
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
#endif
std::string get_base_tmpdir();
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
bool check_file_exists(const std::string& filename, bool is_exec = false);
bool check_directory_exists(const std::string& dirname, bool is_exec = false);
bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname);
bool create_directory(const std::string& dirname);
std::string escape_filename_spaces(const std::string& filename);
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
#endif // YOSYS_IO_H #endif // YOSYS_IO_H

View file

@ -148,7 +148,7 @@ static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_d
#else #else
static inline bool ys_debug(int = 0) { return false; } static inline bool ys_debug(int = 0) { return false; }
#endif #endif
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); } } # define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
static inline void log_suppressed() { static inline void log_suppressed() {
if (log_debug_suppressed && !log_make_debug) { if (log_debug_suppressed && !log_make_debug) {

View file

@ -860,7 +860,7 @@ struct HelpPass : public Pass {
// init json // init json
json.begin_object(); json.begin_object();
json.entry("version", "Yosys internal cells"); json.entry("version", "Yosys internal cells");
json.entry("generator", yosys_version_str); json.entry("generator", yosys_maybe_version());
dict<string, vector<string>> groups; dict<string, vector<string>> groups;
dict<string, pair<SimHelper, CellType>> cells; dict<string, pair<SimHelper, CellType>> cells;

View file

@ -29,6 +29,7 @@ struct Pass
{ {
std::string pass_name, short_help; std::string pass_name, short_help;
Pass(std::string name, std::string short_help = "** document me **"); Pass(std::string name, std::string short_help = "** document me **");
// Prefer overriding 'Pass::on_shutdown()' if possible
virtual ~Pass(); virtual ~Pass();
virtual void help(); virtual void help();

View file

@ -380,6 +380,49 @@ int RTLIL::Const::as_int(bool is_signed) const
return ret; return ret;
} }
bool RTLIL::Const::convertible_to_int(bool is_signed) const
{
auto size = get_min_size(is_signed);
if (size <= 0)
return false;
// If it fits in 31 bits it is definitely convertible
if (size <= 31)
return true;
// If it fits in 32 bits, it is convertible if signed or if unsigned and the
// leading bit is not 1
if (size == 32) {
if (is_signed)
return true;
return get_bits().at(31) != State::S1;
}
return false;
}
std::optional<int> RTLIL::Const::try_as_int(bool is_signed) const
{
if (!convertible_to_int(is_signed))
return std::nullopt;
return as_int(is_signed);
}
int RTLIL::Const::as_int_saturating(bool is_signed) const
{
if (!convertible_to_int(is_signed)) {
if (!is_signed)
return std::numeric_limits<int>::max();
const auto min_size = get_min_size(is_signed);
log_assert(min_size > 0);
const auto neg = get_bits().at(min_size - 1);
return neg ? std::numeric_limits<int>::min() : std::numeric_limits<int>::max();
}
return as_int(is_signed);
}
int RTLIL::Const::get_min_size(bool is_signed) const int RTLIL::Const::get_min_size(bool is_signed) const
{ {
if (empty()) return 0; if (empty()) return 0;
@ -412,18 +455,7 @@ void RTLIL::Const::compress(bool is_signed)
std::optional<int> RTLIL::Const::as_int_compress(bool is_signed) const std::optional<int> RTLIL::Const::as_int_compress(bool is_signed) const
{ {
auto size = get_min_size(is_signed); return try_as_int(is_signed);
if(size == 0 || size > 32)
return std::nullopt;
int32_t ret = 0;
for (auto i = 0; i < size && i < 32; i++)
if ((*this)[i] == State::S1)
ret |= 1 << i;
if (is_signed && (*this)[size-1] == State::S1)
for (auto i = size; i < 32; i++)
ret |= 1 << i;
return ret;
} }
std::string RTLIL::Const::as_string(const char* any) const std::string RTLIL::Const::as_string(const char* any) const
@ -2377,7 +2409,14 @@ void RTLIL::Module::check()
// assertion check below to make sure that there are no // assertion check below to make sure that there are no
// cases where a cell has a blackbox attribute since // cases where a cell has a blackbox attribute since
// that is deprecated // that is deprecated
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
log_assert(!it.second->get_blackbox_attribute()); log_assert(!it.second->get_blackbox_attribute());
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
} }
} }
@ -5462,6 +5501,38 @@ int RTLIL::SigSpec::as_int(bool is_signed) const
return 0; return 0;
} }
bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const
{
cover("kernel.rtlil.sigspec.convertible_to_int");
pack();
if (!is_fully_const())
return false;
return RTLIL::Const(chunks_[0].data).convertible_to_int(is_signed);
}
std::optional<int> RTLIL::SigSpec::try_as_int(bool is_signed) const
{
cover("kernel.rtlil.sigspec.try_as_int");
pack();
if (!is_fully_const())
return std::nullopt;
return RTLIL::Const(chunks_[0].data).try_as_int(is_signed);
}
int RTLIL::SigSpec::as_int_saturating(bool is_signed) const
{
cover("kernel.rtlil.sigspec.try_as_int");
pack();
log_assert(is_fully_const() && GetSize(chunks_) <= 1);
log_assert(!empty());
return RTLIL::Const(chunks_[0].data).as_int_saturating(is_signed);
}
std::string RTLIL::SigSpec::as_string() const std::string RTLIL::SigSpec::as_string() const
{ {
cover("kernel.rtlil.sigspec.as_string"); cover("kernel.rtlil.sigspec.as_string");

View file

@ -753,7 +753,26 @@ public:
std::vector<RTLIL::State>& bits(); std::vector<RTLIL::State>& bits();
bool as_bool() const; bool as_bool() const;
// Convert the constant value to a C++ int.
// NOTE: If the constant is too wide to fit in int (32 bits) this will
// truncate any higher bits, potentially over/underflowing. Consider using
// try_as_int, as_int_saturating, or guarding behind convertible_to_int
// instead.
int as_int(bool is_signed = false) const; int as_int(bool is_signed = false) const;
// Returns true iff the constant can be converted to an int without
// over/underflow.
bool convertible_to_int(bool is_signed = false) const;
// Returns the constant's value as an int if it can be represented without
// over/underflow, or std::nullopt otherwise.
std::optional<int> try_as_int(bool is_signed = false) const;
// Returns the constant's value as an int if it can be represented without
// over/underflow, otherwise the max/min value for int depending on the sign.
int as_int_saturating(bool is_signed = false) const;
std::string as_string(const char* any = "-") const; std::string as_string(const char* any = "-") const;
static Const from_string(const std::string &str); static Const from_string(const std::string &str);
std::vector<RTLIL::State> to_bits() const; std::vector<RTLIL::State> to_bits() const;
@ -1130,7 +1149,27 @@ public:
bool is_onehot(int *pos = nullptr) const; bool is_onehot(int *pos = nullptr) const;
bool as_bool() const; bool as_bool() const;
// Convert the SigSpec to a C++ int, assuming all bits are constant.
// NOTE: If the value is too wide to fit in int (32 bits) this will
// truncate any higher bits, potentially over/underflowing. Consider using
// try_as_int, as_int_saturating, or guarding behind convertible_to_int
// instead.
int as_int(bool is_signed = false) const; int as_int(bool is_signed = false) const;
// Returns true iff the SigSpec is constant and can be converted to an int
// without over/underflow.
bool convertible_to_int(bool is_signed = false) const;
// Returns the SigSpec's value as an int if it is a constant and can be
// represented without over/underflow, or std::nullopt otherwise.
std::optional<int> try_as_int(bool is_signed = false) const;
// Returns an all constant SigSpec's value as an int if it can be represented
// without over/underflow, otherwise the max/min value for int depending on
// the sign.
int as_int_saturating(bool is_signed = false) const;
std::string as_string() const; std::string as_string() const;
RTLIL::Const as_const() const; RTLIL::Const as_const() const;
RTLIL::Wire *as_wire() const; RTLIL::Wire *as_wire() const;
@ -1182,7 +1221,7 @@ struct RTLIL::Selection
bool boxes = false, bool boxes = false,
// the design to select from // the design to select from
RTLIL::Design *design = nullptr RTLIL::Design *design = nullptr
) : ) :
selects_boxes(boxes), complete_selection(full && boxes), full_selection(full && !boxes), current_design(design) { } selects_boxes(boxes), complete_selection(full && boxes), full_selection(full && !boxes), current_design(design) { }
// checks if the given module exists in the current design and is a // checks if the given module exists in the current design and is a

View file

@ -81,6 +81,14 @@ YOSYS_NAMESPACE_BEGIN
int autoidx = 1; int autoidx = 1;
int yosys_xtrace = 0; int yosys_xtrace = 0;
bool yosys_write_versions = true;
const char* yosys_maybe_version() {
if (yosys_write_versions)
return yosys_version_str;
else
return "Yosys";
}
RTLIL::Design *yosys_design = NULL; RTLIL::Design *yosys_design = NULL;
CellTypes yosys_celltypes; CellTypes yosys_celltypes;
@ -144,7 +152,7 @@ void yosys_banner()
log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@yosyshq.com> |\n"); log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@yosyshq.com> |\n");
log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n"); log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n");
log(" \\----------------------------------------------------------------------------/\n"); log(" \\----------------------------------------------------------------------------/\n");
log(" %s\n", yosys_version_str); log(" %s\n", yosys_maybe_version());
} }
#if !defined(YOSYS_DISABLE_SPAWN) #if !defined(YOSYS_DISABLE_SPAWN)
@ -548,29 +556,29 @@ void init_share_dirname()
std::string proc_self_path = proc_self_dirname(); std::string proc_self_path = proc_self_dirname();
# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR) # if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR)
std::string proc_share_path = proc_self_path + "share\\"; std::string proc_share_path = proc_self_path + "share\\";
if (check_file_exists(proc_share_path, true)) { if (check_directory_exists(proc_share_path, true)) {
yosys_share_dirname = proc_share_path; yosys_share_dirname = proc_share_path;
return; return;
} }
proc_share_path = proc_self_path + "..\\share\\"; proc_share_path = proc_self_path + "..\\share\\";
if (check_file_exists(proc_share_path, true)) { if (check_directory_exists(proc_share_path, true)) {
yosys_share_dirname = proc_share_path; yosys_share_dirname = proc_share_path;
return; return;
} }
# else # else
std::string proc_share_path = proc_self_path + "share/"; std::string proc_share_path = proc_self_path + "share/";
if (check_file_exists(proc_share_path, true)) { if (check_directory_exists(proc_share_path, true)) {
yosys_share_dirname = proc_share_path; yosys_share_dirname = proc_share_path;
return; return;
} }
proc_share_path = proc_self_path + "../share/" + proc_program_prefix()+ "yosys/"; proc_share_path = proc_self_path + "../share/" + proc_program_prefix()+ "yosys/";
if (check_file_exists(proc_share_path, true)) { if (check_directory_exists(proc_share_path, true)) {
yosys_share_dirname = proc_share_path; yosys_share_dirname = proc_share_path;
return; return;
} }
# ifdef YOSYS_DATDIR # ifdef YOSYS_DATDIR
proc_share_path = YOSYS_DATDIR "/"; proc_share_path = YOSYS_DATDIR "/";
if (check_file_exists(proc_share_path, true)) { if (check_directory_exists(proc_share_path, true)) {
yosys_share_dirname = proc_share_path; yosys_share_dirname = proc_share_path;
return; return;
} }

View file

@ -81,6 +81,7 @@ extern std::set<std::string> yosys_input_files, yosys_output_files;
// from kernel/version_*.o (cc source generated from Makefile) // from kernel/version_*.o (cc source generated from Makefile)
extern const char *yosys_version_str; extern const char *yosys_version_str;
const char* yosys_maybe_version();
// from passes/cmds/design.cc // from passes/cmds/design.cc
extern std::map<std::string, RTLIL::Design*> saved_designs; extern std::map<std::string, RTLIL::Design*> saved_designs;

View file

@ -252,28 +252,12 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner(); void yosys_banner();
int ceil_log2(int x) YS_ATTRIBUTE(const); int ceil_log2(int x) YS_ATTRIBUTE(const);
int readsome(std::istream &f, char *s, int n);
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
bool patmatch(const char *pattern, const char *string);
#if !defined(YOSYS_DISABLE_SPAWN)
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
#endif
std::string get_base_tmpdir();
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false);
bool check_directory_exists(const std::string& dirname);
bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname);
bool create_directory(const std::string& dirname);
std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); } template<typename T> int GetSize(const T &obj) { return obj.size(); }
inline int GetSize(RTLIL::Wire *wire); inline int GetSize(RTLIL::Wire *wire);
extern int autoidx; extern int autoidx;
extern int yosys_xtrace; extern int yosys_xtrace;
extern bool yosys_write_versions;
RTLIL::IdString new_id(std::string file, int line, std::string func); RTLIL::IdString new_id(std::string file, int line, std::string func);
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix); RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);

View file

@ -1,14 +1,14 @@
--- fstapi.cc --- fstapi.cc
+++ fstapi.cc +++ fstapi.cc
@@ -4723,7 +4723,10 @@ if(gzread_pass_status) @@ -4723,7 +4723,10 @@ if(gzread_pass_status)
hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0); hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0);
fstFread(&dcheck, 8, 1, xc->f); fstFread(&dcheck, 8, 1, xc->f);
- xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST); - xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
+ /* + /*
+ * Yosys patch: Fix double endian check for i386 targets built in modern gcc + * Yosys patch: Fix double endian check for i386 targets built in modern gcc
+ */ + */
+ xc->double_endian_match = (dcheck == (double)FST_DOUBLE_ENDTEST); + xc->double_endian_match = (dcheck == (double)FST_DOUBLE_ENDTEST);
if(!xc->double_endian_match) if (!xc->double_endian_match) {
{ union
union { {

View file

@ -23,9 +23,9 @@
@@ -137,7 +137,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 @@ -137,7 +137,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
-#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) - defined(__NetBSD__)
+#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(_MSC_VER) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) + defined(__NetBSD__) || defined(_MSC_VER)
#define FST_UNBUFFERED_IO #define FST_UNBUFFERED_IO
#endif #endif

View file

@ -7,10 +7,10 @@
-#include <zlib.h> -#include <zlib.h>
#include <inttypes.h> #include <inttypes.h>
#if defined(_MSC_VER) #if defined(_MSC_VER)
+ #include "libs/zlib/zlib.h" +#include "libs/zlib/zlib.h"
#include "fst_win_unistd.h" #include "fst_win_unistd.h"
#else #else
+ #include <zlib.h> +#include <zlib.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <time.h> #include <time.h>

View file

@ -1,10 +1,10 @@
--- fstapi.cc --- fstapi.cc
+++ fstapi.cc +++ fstapi.cc
@@ -6072,6 +6072,7 @@ for(;;) @@ -6072,6 +6072,7 @@ for(;;)
} }
wx_len = snprintf(wx_buf, 32, "r%.16g", d); wx_len = snprintf(wx_buf, 32, "r%.16g", d);
+ if (wx_len > 32 || wx_len < 0) wx_len = 32; + if (wx_len > 32 || wx_len < 0) wx_len = 32;
fstWritex(xc, wx_buf, wx_len); fstWritex(xc, wx_buf, wx_len);
} }
} }

View file

@ -2,9 +2,10 @@
mv config.h config.h.bak mv config.h config.h.bak
rm -f *.txt *.cc *.h rm -f *.txt *.cc *.h
git clone --depth 1 https://github.com/gtkwave/gtkwave fst_upstream git clone --depth 1 https://github.com/gtkwave/libfst fst_upstream
rm fst_upstream/lib/libfst/CMakeLists.txt rm fst_upstream/src/meson.build
mv fst_upstream/lib/libfst/*.{h,c,txt} . mv fst_upstream/src/*.{h,c} .
mv fst_upstream/doc/block_format.txt .
rm -rf fst_upstream rm -rf fst_upstream
for src in *.c; do for src in *.c; do

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,8 @@
#define FST_API_H #define FST_API_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
#include <stdio.h> #include <stdio.h>
@ -35,430 +36,510 @@ extern "C" {
#include <ctype.h> #include <ctype.h>
#include <inttypes.h> #include <inttypes.h>
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include "libs/zlib/zlib.h" #include "libs/zlib/zlib.h"
#include "fst_win_unistd.h" #include "fst_win_unistd.h"
#else #else
#include <zlib.h> #include <zlib.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <time.h> #include <time.h>
#define FST_RDLOAD "FSTLOAD | "
typedef uint32_t fstHandle; typedef uint32_t fstHandle;
typedef uint32_t fstEnumHandle; typedef uint32_t fstEnumHandle;
enum fstWriterPackType { enum fstWriterPackType
FST_WR_PT_ZLIB = 0, {
FST_WR_PT_FASTLZ = 1, FST_WR_PT_ZLIB = 0,
FST_WR_PT_LZ4 = 2 FST_WR_PT_FASTLZ = 1,
FST_WR_PT_LZ4 = 2
}; };
enum fstFileType { enum fstFileType
FST_FT_MIN = 0, {
FST_FT_MIN = 0,
FST_FT_VERILOG = 0, FST_FT_VERILOG = 0,
FST_FT_VHDL = 1, FST_FT_VHDL = 1,
FST_FT_VERILOG_VHDL = 2, FST_FT_VERILOG_VHDL = 2,
FST_FT_MAX = 2 FST_FT_MAX = 2
}; };
enum fstBlockType { enum fstBlockType
FST_BL_HDR = 0, {
FST_BL_VCDATA = 1, FST_BL_HDR = 0,
FST_BL_BLACKOUT = 2, FST_BL_VCDATA = 1,
FST_BL_GEOM = 3, FST_BL_BLACKOUT = 2,
FST_BL_HIER = 4, FST_BL_GEOM = 3,
FST_BL_VCDATA_DYN_ALIAS = 5, FST_BL_HIER = 4,
FST_BL_HIER_LZ4 = 6, FST_BL_VCDATA_DYN_ALIAS = 5,
FST_BL_HIER_LZ4DUO = 7, FST_BL_HIER_LZ4 = 6,
FST_BL_VCDATA_DYN_ALIAS2 = 8, FST_BL_HIER_LZ4DUO = 7,
FST_BL_VCDATA_DYN_ALIAS2 = 8,
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */ FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
FST_BL_SKIP = 255 /* used while block is being written */ FST_BL_SKIP = 255 /* used while block is being written */
}; };
enum fstScopeType { enum fstScopeType
FST_ST_MIN = 0, {
FST_ST_MIN = 0,
FST_ST_VCD_MODULE = 0, FST_ST_VCD_MODULE = 0,
FST_ST_VCD_TASK = 1, FST_ST_VCD_TASK = 1,
FST_ST_VCD_FUNCTION = 2, FST_ST_VCD_FUNCTION = 2,
FST_ST_VCD_BEGIN = 3, FST_ST_VCD_BEGIN = 3,
FST_ST_VCD_FORK = 4, FST_ST_VCD_FORK = 4,
FST_ST_VCD_GENERATE = 5, FST_ST_VCD_GENERATE = 5,
FST_ST_VCD_STRUCT = 6, FST_ST_VCD_STRUCT = 6,
FST_ST_VCD_UNION = 7, FST_ST_VCD_UNION = 7,
FST_ST_VCD_CLASS = 8, FST_ST_VCD_CLASS = 8,
FST_ST_VCD_INTERFACE = 9, FST_ST_VCD_INTERFACE = 9,
FST_ST_VCD_PACKAGE = 10, FST_ST_VCD_PACKAGE = 10,
FST_ST_VCD_PROGRAM = 11, FST_ST_VCD_PROGRAM = 11,
FST_ST_VHDL_ARCHITECTURE = 12, FST_ST_VHDL_ARCHITECTURE = 12,
FST_ST_VHDL_PROCEDURE = 13, FST_ST_VHDL_PROCEDURE = 13,
FST_ST_VHDL_FUNCTION = 14, FST_ST_VHDL_FUNCTION = 14,
FST_ST_VHDL_RECORD = 15, FST_ST_VHDL_RECORD = 15,
FST_ST_VHDL_PROCESS = 16, FST_ST_VHDL_PROCESS = 16,
FST_ST_VHDL_BLOCK = 17, FST_ST_VHDL_BLOCK = 17,
FST_ST_VHDL_FOR_GENERATE = 18, FST_ST_VHDL_FOR_GENERATE = 18,
FST_ST_VHDL_IF_GENERATE = 19, FST_ST_VHDL_IF_GENERATE = 19,
FST_ST_VHDL_GENERATE = 20, FST_ST_VHDL_GENERATE = 20,
FST_ST_VHDL_PACKAGE = 21, FST_ST_VHDL_PACKAGE = 21,
FST_ST_MAX = 21, FST_ST_MAX = 21,
FST_ST_GEN_ATTRBEGIN = 252, FST_ST_GEN_ATTRBEGIN = 252,
FST_ST_GEN_ATTREND = 253, FST_ST_GEN_ATTREND = 253,
FST_ST_VCD_SCOPE = 254, FST_ST_VCD_SCOPE = 254,
FST_ST_VCD_UPSCOPE = 255 FST_ST_VCD_UPSCOPE = 255
}; };
enum fstVarType { enum fstVarType
FST_VT_MIN = 0, /* start of vartypes */ {
FST_VT_MIN = 0, /* start of vartypes */
FST_VT_VCD_EVENT = 0, FST_VT_VCD_EVENT = 0,
FST_VT_VCD_INTEGER = 1, FST_VT_VCD_INTEGER = 1,
FST_VT_VCD_PARAMETER = 2, FST_VT_VCD_PARAMETER = 2,
FST_VT_VCD_REAL = 3, FST_VT_VCD_REAL = 3,
FST_VT_VCD_REAL_PARAMETER = 4, FST_VT_VCD_REAL_PARAMETER = 4,
FST_VT_VCD_REG = 5, FST_VT_VCD_REG = 5,
FST_VT_VCD_SUPPLY0 = 6, FST_VT_VCD_SUPPLY0 = 6,
FST_VT_VCD_SUPPLY1 = 7, FST_VT_VCD_SUPPLY1 = 7,
FST_VT_VCD_TIME = 8, FST_VT_VCD_TIME = 8,
FST_VT_VCD_TRI = 9, FST_VT_VCD_TRI = 9,
FST_VT_VCD_TRIAND = 10, FST_VT_VCD_TRIAND = 10,
FST_VT_VCD_TRIOR = 11, FST_VT_VCD_TRIOR = 11,
FST_VT_VCD_TRIREG = 12, FST_VT_VCD_TRIREG = 12,
FST_VT_VCD_TRI0 = 13, FST_VT_VCD_TRI0 = 13,
FST_VT_VCD_TRI1 = 14, FST_VT_VCD_TRI1 = 14,
FST_VT_VCD_WAND = 15, FST_VT_VCD_WAND = 15,
FST_VT_VCD_WIRE = 16, FST_VT_VCD_WIRE = 16,
FST_VT_VCD_WOR = 17, FST_VT_VCD_WOR = 17,
FST_VT_VCD_PORT = 18, FST_VT_VCD_PORT = 18,
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */ FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
FST_VT_VCD_REALTIME = 20, FST_VT_VCD_REALTIME = 20,
FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */ FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via
fstWriterEmitVariableLengthValueChange) */
FST_VT_SV_BIT = 22, FST_VT_SV_BIT = 22,
FST_VT_SV_LOGIC = 23, FST_VT_SV_LOGIC = 23,
FST_VT_SV_INT = 24, /* declare as size = 32 */ FST_VT_SV_INT = 24, /* declare as size = 32 */
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */ FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */ FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
FST_VT_SV_BYTE = 27, /* declare as size = 8 */ FST_VT_SV_BYTE = 27, /* declare as size = 8 */
FST_VT_SV_ENUM = 28, /* declare as appropriate type range */ FST_VT_SV_ENUM = 28, /* declare as appropriate type range */
FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */ FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted
as double, not a float) */
FST_VT_MAX = 29 /* end of vartypes */ FST_VT_MAX = 29 /* end of vartypes */
}; };
enum fstVarDir { enum fstVarDir
FST_VD_MIN = 0, {
FST_VD_MIN = 0,
FST_VD_IMPLICIT = 0, FST_VD_IMPLICIT = 0,
FST_VD_INPUT = 1, FST_VD_INPUT = 1,
FST_VD_OUTPUT = 2, FST_VD_OUTPUT = 2,
FST_VD_INOUT = 3, FST_VD_INOUT = 3,
FST_VD_BUFFER = 4, FST_VD_BUFFER = 4,
FST_VD_LINKAGE = 5, FST_VD_LINKAGE = 5,
FST_VD_MAX = 5 FST_VD_MAX = 5
}; };
enum fstHierType { enum fstHierType
FST_HT_MIN = 0, {
FST_HT_MIN = 0,
FST_HT_SCOPE = 0, FST_HT_SCOPE = 0,
FST_HT_UPSCOPE = 1, FST_HT_UPSCOPE = 1,
FST_HT_VAR = 2, FST_HT_VAR = 2,
FST_HT_ATTRBEGIN = 3, FST_HT_ATTRBEGIN = 3,
FST_HT_ATTREND = 4, FST_HT_ATTREND = 4,
/* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when fstHier bridges other formats */ /* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when
FST_HT_TREEBEGIN = 5, fstHier bridges other formats */
FST_HT_TREEEND = 6, FST_HT_TREEBEGIN = 5,
FST_HT_TREEEND = 6,
FST_HT_MAX = 6 FST_HT_MAX = 6
}; };
enum fstAttrType { enum fstAttrType
FST_AT_MIN = 0, {
FST_AT_MIN = 0,
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */ FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
FST_AT_ARRAY = 1, FST_AT_ARRAY = 1,
FST_AT_ENUM = 2, FST_AT_ENUM = 2,
FST_AT_PACK = 3, FST_AT_PACK = 3,
FST_AT_MAX = 3 FST_AT_MAX = 3
}; };
enum fstMiscType { enum fstMiscType
FST_MT_MIN = 0, {
FST_MT_MIN = 0,
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */ FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */ FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */ FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */ FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */ FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */ FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */ FST_MT_VALUELIST =
FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */ 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
FST_MT_UNKNOWN = 8, FST_MT_ENUMTABLE =
7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
FST_MT_UNKNOWN = 8,
FST_MT_MAX = 8 FST_MT_MAX = 8
}; };
enum fstArrayType { enum fstArrayType
FST_AR_MIN = 0, {
FST_AR_MIN = 0,
FST_AR_NONE = 0, FST_AR_NONE = 0,
FST_AR_UNPACKED = 1, FST_AR_UNPACKED = 1,
FST_AR_PACKED = 2, FST_AR_PACKED = 2,
FST_AR_SPARSE = 3, FST_AR_SPARSE = 3,
FST_AR_MAX = 3 FST_AR_MAX = 3
}; };
enum fstEnumValueType { enum fstEnumValueType
FST_EV_SV_INTEGER = 0, {
FST_EV_SV_BIT = 1, FST_EV_SV_INTEGER = 0,
FST_EV_SV_LOGIC = 2, FST_EV_SV_BIT = 1,
FST_EV_SV_INT = 3, FST_EV_SV_LOGIC = 2,
FST_EV_SV_SHORTINT = 4, FST_EV_SV_INT = 3,
FST_EV_SV_LONGINT = 5, FST_EV_SV_SHORTINT = 4,
FST_EV_SV_BYTE = 6, FST_EV_SV_LONGINT = 5,
FST_EV_SV_UNSIGNED_INTEGER = 7, FST_EV_SV_BYTE = 6,
FST_EV_SV_UNSIGNED_BIT = 8, FST_EV_SV_UNSIGNED_INTEGER = 7,
FST_EV_SV_UNSIGNED_LOGIC = 9, FST_EV_SV_UNSIGNED_BIT = 8,
FST_EV_SV_UNSIGNED_INT = 10, FST_EV_SV_UNSIGNED_LOGIC = 9,
FST_EV_SV_UNSIGNED_INT = 10,
FST_EV_SV_UNSIGNED_SHORTINT = 11, FST_EV_SV_UNSIGNED_SHORTINT = 11,
FST_EV_SV_UNSIGNED_LONGINT = 12, FST_EV_SV_UNSIGNED_LONGINT = 12,
FST_EV_SV_UNSIGNED_BYTE = 13, FST_EV_SV_UNSIGNED_BYTE = 13,
FST_EV_REG = 14, FST_EV_REG = 14,
FST_EV_TIME = 15, FST_EV_TIME = 15,
FST_EV_MAX = 15 FST_EV_MAX = 15
}; };
enum fstPackType { enum fstPackType
FST_PT_NONE = 0, {
FST_PT_UNPACKED = 1, FST_PT_NONE = 0,
FST_PT_PACKED = 2, FST_PT_UNPACKED = 1,
FST_PT_PACKED = 2,
FST_PT_TAGGED_PACKED = 3, FST_PT_TAGGED_PACKED = 3,
FST_PT_MAX = 3 FST_PT_MAX = 3
}; };
enum fstSupplementalVarType { enum fstSupplementalVarType
FST_SVT_MIN = 0, {
FST_SVT_MIN = 0,
FST_SVT_NONE = 0, FST_SVT_NONE = 0,
FST_SVT_VHDL_SIGNAL = 1, FST_SVT_VHDL_SIGNAL = 1,
FST_SVT_VHDL_VARIABLE = 2, FST_SVT_VHDL_VARIABLE = 2,
FST_SVT_VHDL_CONSTANT = 3, FST_SVT_VHDL_CONSTANT = 3,
FST_SVT_VHDL_FILE = 4, FST_SVT_VHDL_FILE = 4,
FST_SVT_VHDL_MEMORY = 5, FST_SVT_VHDL_MEMORY = 5,
FST_SVT_MAX = 5 FST_SVT_MAX = 5
}; };
enum fstSupplementalDataType { enum fstSupplementalDataType
FST_SDT_MIN = 0, {
FST_SDT_MIN = 0,
FST_SDT_NONE = 0, FST_SDT_NONE = 0,
FST_SDT_VHDL_BOOLEAN = 1, FST_SDT_VHDL_BOOLEAN = 1,
FST_SDT_VHDL_BIT = 2, FST_SDT_VHDL_BIT = 2,
FST_SDT_VHDL_BIT_VECTOR = 3, FST_SDT_VHDL_BIT_VECTOR = 3,
FST_SDT_VHDL_STD_ULOGIC = 4, FST_SDT_VHDL_STD_ULOGIC = 4,
FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5, FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5,
FST_SDT_VHDL_STD_LOGIC = 6, FST_SDT_VHDL_STD_LOGIC = 6,
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7, FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
FST_SDT_VHDL_UNSIGNED = 8, FST_SDT_VHDL_UNSIGNED = 8,
FST_SDT_VHDL_SIGNED = 9, FST_SDT_VHDL_SIGNED = 9,
FST_SDT_VHDL_INTEGER = 10, FST_SDT_VHDL_INTEGER = 10,
FST_SDT_VHDL_REAL = 11, FST_SDT_VHDL_REAL = 11,
FST_SDT_VHDL_NATURAL = 12, FST_SDT_VHDL_NATURAL = 12,
FST_SDT_VHDL_POSITIVE = 13, FST_SDT_VHDL_POSITIVE = 13,
FST_SDT_VHDL_TIME = 14, FST_SDT_VHDL_TIME = 14,
FST_SDT_VHDL_CHARACTER = 15, FST_SDT_VHDL_CHARACTER = 15,
FST_SDT_VHDL_STRING = 16, FST_SDT_VHDL_STRING = 16,
FST_SDT_MAX = 16, FST_SDT_MAX = 16,
FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */ FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left
FST_SDT_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1) after shifting FST_SDT_SVT_SHIFT_COUNT */
FST_SDT_ABS_MAX = ((1 << (FST_SDT_SVT_SHIFT_COUNT)) - 1)
}; };
struct fstHier struct fstHier
{ {
unsigned char htyp; unsigned char htyp;
union { union
{
/* if htyp == FST_HT_SCOPE */ /* if htyp == FST_HT_SCOPE */
struct fstHierScope { struct fstHierScope
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */ {
const char *name; unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
const char *component; const char *name;
uint32_t name_length; /* strlen(u.scope.name) */ const char *component;
uint32_t component_length; /* strlen(u.scope.component) */ uint32_t name_length; /* strlen(u.scope.name) */
} scope; uint32_t component_length; /* strlen(u.scope.component) */
} scope;
/* if htyp == FST_HT_VAR */ /* if htyp == FST_HT_VAR */
struct fstHierVar { struct fstHierVar
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */ {
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */ unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */ unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */ unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */ unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
const char *name; unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
uint32_t length; const char *name;
fstHandle handle; uint32_t length;
uint32_t name_length; /* strlen(u.var.name) */ fstHandle handle;
unsigned is_alias : 1; uint32_t name_length; /* strlen(u.var.name) */
} var; unsigned is_alias : 1;
} var;
/* if htyp == FST_HT_ATTRBEGIN */ /* if htyp == FST_HT_ATTRBEGIN */
struct fstHierAttr { struct fstHierAttr
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */ {
unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */ unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
const char *name; unsigned char
uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */ subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */ const char *name;
uint32_t name_length; /* strlen(u.attr.name) */ uint64_t arg; /* number of array elements, struct members, or some other payload
} attr; (possibly ignored) */
} u; uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer
(FST_AT_MISC + FST_MT_SOURCESTEM) */
uint32_t name_length; /* strlen(u.attr.name) */
} attr;
} u;
}; };
struct fstETab struct fstETab
{ {
char *name; char *name;
uint32_t elem_count; uint32_t elem_count;
char **literal_arr; char **literal_arr;
char **val_arr; char **val_arr;
}; };
/* /*
* writer functions * writer functions
*/ */
void fstWriterClose(void *ctx);
void * fstWriterCreate(const char *nam, int use_compressed_hier);
fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr);
/* used for Verilog/SV */
fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
uint32_t len, const char *nam, fstHandle aliasHandle);
/* future expansion for VHDL and other languages. The variable type, data type, etc map onto
the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */
fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd,
uint32_t len, const char *nam, fstHandle aliasHandle,
const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt);
void fstWriterEmitDumpActive(void *ctx, int enable);
void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle);
void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val);
void fstWriterEmitValueChange32(void *ctx, fstHandle handle,
uint32_t bits, uint32_t val);
void fstWriterEmitValueChange64(void *ctx, fstHandle handle,
uint32_t bits, uint64_t val);
void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle,
uint32_t bits, const uint32_t *val);
void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle,
uint32_t bits, const uint64_t *val);
void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len);
void fstWriterEmitTimeChange(void *ctx, uint64_t tim);
void fstWriterFlushContext(void *ctx);
int fstWriterGetDumpSizeLimitReached(void *ctx);
int fstWriterGetFseekFailed(void *ctx);
void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype,
const char *attrname, uint64_t arg);
void fstWriterSetAttrEnd(void *ctx);
void fstWriterSetComment(void *ctx, const char *comm);
void fstWriterSetDate(void *ctx, const char *dat);
void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes);
void fstWriterSetEnvVar(void *ctx, const char *envvar);
void fstWriterSetFileType(void *ctx, enum fstFileType filetype);
void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ);
void fstWriterSetParallelMode(void *ctx, int enable);
void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */
void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
const char *scopename, const char *scopecomp);
void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
void fstWriterSetTimescale(void *ctx, int ts);
void fstWriterSetTimescaleFromString(void *ctx, const char *s);
void fstWriterSetTimezero(void *ctx, int64_t tim);
void fstWriterSetUpscope(void *ctx);
void fstWriterSetValueList(void *ctx, const char *vl);
void fstWriterSetVersion(void *ctx, const char *vers);
typedef struct fstWriterContext fstWriterContext;
void fstWriterClose(fstWriterContext *ctx);
fstWriterContext *fstWriterCreate(const char *nam, int use_compressed_hier);
fstEnumHandle fstWriterCreateEnumTable(fstWriterContext *ctx,
const char *name,
uint32_t elem_count,
unsigned int min_valbits,
const char **literal_arr,
const char **val_arr);
/* used for Verilog/SV */
fstHandle fstWriterCreateVar(fstWriterContext *ctx,
enum fstVarType vt,
enum fstVarDir vd,
uint32_t len,
const char *nam,
fstHandle aliasHandle);
/* future expansion for VHDL and other languages. The variable type, data type, etc map onto
the current Verilog/SV one. The "type" string is optional for a more verbose or custom
description */
fstHandle fstWriterCreateVar2(fstWriterContext *ctx,
enum fstVarType vt,
enum fstVarDir vd,
uint32_t len,
const char *nam,
fstHandle aliasHandle,
const char *type,
enum fstSupplementalVarType svt,
enum fstSupplementalDataType sdt);
void fstWriterEmitDumpActive(fstWriterContext *ctx, int enable);
void fstWriterEmitEnumTableRef(fstWriterContext *ctx, fstEnumHandle handle);
void fstWriterEmitValueChange(fstWriterContext *ctx, fstHandle handle, const void *val);
void fstWriterEmitValueChange32(fstWriterContext *ctx,
fstHandle handle,
uint32_t bits,
uint32_t val);
void fstWriterEmitValueChange64(fstWriterContext *ctx,
fstHandle handle,
uint32_t bits,
uint64_t val);
void fstWriterEmitValueChangeVec32(fstWriterContext *ctx,
fstHandle handle,
uint32_t bits,
const uint32_t *val);
void fstWriterEmitValueChangeVec64(fstWriterContext *ctx,
fstHandle handle,
uint32_t bits,
const uint64_t *val);
void fstWriterEmitVariableLengthValueChange(fstWriterContext *ctx,
fstHandle handle,
const void *val,
uint32_t len);
void fstWriterEmitTimeChange(fstWriterContext *ctx, uint64_t tim);
void fstWriterFlushContext(fstWriterContext *ctx);
int fstWriterGetDumpSizeLimitReached(fstWriterContext *ctx);
int fstWriterGetFseekFailed(fstWriterContext *ctx);
int fstWriterGetFlushContextPending(fstWriterContext *ctx);
void fstWriterSetAttrBegin(fstWriterContext *ctx,
enum fstAttrType attrtype,
int subtype,
const char *attrname,
uint64_t arg);
void fstWriterSetAttrEnd(fstWriterContext *ctx);
void fstWriterSetComment(fstWriterContext *ctx, const char *comm);
void fstWriterSetDate(fstWriterContext *ctx, const char *dat);
void fstWriterSetDumpSizeLimit(fstWriterContext *ctx, uint64_t numbytes);
void fstWriterSetEnvVar(fstWriterContext *ctx, const char *envvar);
void fstWriterSetFileType(fstWriterContext *ctx, enum fstFileType filetype);
void fstWriterSetPackType(fstWriterContext *ctx, enum fstWriterPackType typ);
void fstWriterSetParallelMode(fstWriterContext *ctx, int enable);
void fstWriterSetRepackOnClose(fstWriterContext *ctx,
int enable); /* type = 0 (none), 1 (libz) */
void fstWriterSetScope(fstWriterContext *ctx,
enum fstScopeType scopetype,
const char *scopename,
const char *scopecomp);
void fstWriterSetSourceInstantiationStem(fstWriterContext *ctx,
const char *path,
unsigned int line,
unsigned int use_realpath);
void fstWriterSetSourceStem(fstWriterContext *ctx,
const char *path,
unsigned int line,
unsigned int use_realpath);
void fstWriterSetTimescale(fstWriterContext *ctx, int ts);
void fstWriterSetTimescaleFromString(fstWriterContext *ctx, const char *s);
void fstWriterSetTimezero(fstWriterContext *ctx, int64_t tim);
void fstWriterSetUpscope(fstWriterContext *ctx);
void fstWriterSetValueList(fstWriterContext *ctx, const char *vl);
void fstWriterSetVersion(fstWriterContext *ctx, const char *vers);
/* /*
* reader functions * reader functions
*/ */
void fstReaderClose(void *ctx);
void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx);
void fstReaderClrFacProcessMaskAll(void *ctx);
uint64_t fstReaderGetAliasCount(void *ctx);
const char * fstReaderGetCurrentFlatScope(void *ctx);
void * fstReaderGetCurrentScopeUserInfo(void *ctx);
int fstReaderGetCurrentScopeLen(void *ctx);
const char * fstReaderGetDateString(void *ctx);
int fstReaderGetDoubleEndianMatchState(void *ctx);
uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx);
unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx);
uint64_t fstReaderGetEndTime(void *ctx);
int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx);
int fstReaderGetFileType(void *ctx);
int fstReaderGetFseekFailed(void *ctx);
fstHandle fstReaderGetMaxHandle(void *ctx);
uint64_t fstReaderGetMemoryUsedByWriter(void *ctx);
uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx);
uint64_t fstReaderGetScopeCount(void *ctx);
uint64_t fstReaderGetStartTime(void *ctx);
signed char fstReaderGetTimescale(void *ctx);
int64_t fstReaderGetTimezero(void *ctx);
uint64_t fstReaderGetValueChangeSectionCount(void *ctx);
char * fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf);
uint64_t fstReaderGetVarCount(void *ctx);
const char * fstReaderGetVersionString(void *ctx);
struct fstHier *fstReaderIterateHier(void *ctx);
int fstReaderIterateHierRewind(void *ctx);
int fstReaderIterBlocks(void *ctx,
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
void *user_callback_data_pointer, FILE *vcdhandle);
int fstReaderIterBlocks2(void *ctx,
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len),
void *user_callback_data_pointer, FILE *vcdhandle);
void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable);
void * fstReaderOpen(const char *nam);
void * fstReaderOpenForUtilitiesOnly(void);
const char * fstReaderPopScope(void *ctx);
int fstReaderProcessHier(void *ctx, FILE *vcdhandle);
const char * fstReaderPushScope(void *ctx, const char *nam, void *user_info);
void fstReaderResetScope(void *ctx);
void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx);
void fstReaderSetFacProcessMaskAll(void *ctx);
void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time);
void fstReaderSetUnlimitedTimeRange(void *ctx);
void fstReaderSetVcdExtensions(void *ctx, int enable);
typedef struct fstReaderContext fstReaderContext;
void fstReaderClose(fstReaderContext *ctx);
void fstReaderClrFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
void fstReaderClrFacProcessMaskAll(fstReaderContext *ctx);
uint64_t fstReaderGetAliasCount(fstReaderContext *ctx);
const char *fstReaderGetCurrentFlatScope(fstReaderContext *ctx);
void *fstReaderGetCurrentScopeUserInfo(fstReaderContext *ctx);
int fstReaderGetCurrentScopeLen(fstReaderContext *ctx);
const char *fstReaderGetDateString(fstReaderContext *ctx);
int fstReaderGetDoubleEndianMatchState(fstReaderContext *ctx);
uint64_t fstReaderGetDumpActivityChangeTime(fstReaderContext *ctx, uint32_t idx);
unsigned char fstReaderGetDumpActivityChangeValue(fstReaderContext *ctx, uint32_t idx);
uint64_t fstReaderGetEndTime(fstReaderContext *ctx);
int fstReaderGetFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
int fstReaderGetFileType(fstReaderContext *ctx);
int fstReaderGetFseekFailed(fstReaderContext *ctx);
fstHandle fstReaderGetMaxHandle(fstReaderContext *ctx);
uint64_t fstReaderGetMemoryUsedByWriter(fstReaderContext *ctx);
uint32_t fstReaderGetNumberDumpActivityChanges(fstReaderContext *ctx);
uint64_t fstReaderGetScopeCount(fstReaderContext *ctx);
uint64_t fstReaderGetStartTime(fstReaderContext *ctx);
signed char fstReaderGetTimescale(fstReaderContext *ctx);
int64_t fstReaderGetTimezero(fstReaderContext *ctx);
uint64_t fstReaderGetValueChangeSectionCount(fstReaderContext *ctx);
char *fstReaderGetValueFromHandleAtTime(fstReaderContext *ctx,
uint64_t tim,
fstHandle facidx,
char *buf);
uint64_t fstReaderGetVarCount(fstReaderContext *ctx);
const char *fstReaderGetVersionString(fstReaderContext *ctx);
struct fstHier *fstReaderIterateHier(fstReaderContext *ctx);
int fstReaderIterateHierRewind(fstReaderContext *ctx);
int fstReaderIterBlocks(fstReaderContext *ctx,
void (*value_change_callback)(void *user_callback_data_pointer,
uint64_t time,
fstHandle facidx,
const unsigned char *value),
void *user_callback_data_pointer,
FILE *vcdhandle);
int fstReaderIterBlocks2(fstReaderContext *ctx,
void (*value_change_callback)(void *user_callback_data_pointer,
uint64_t time,
fstHandle facidx,
const unsigned char *value),
void (*value_change_callback_varlen)(void *user_callback_data_pointer,
uint64_t time,
fstHandle facidx,
const unsigned char *value,
uint32_t len),
void *user_callback_data_pointer,
FILE *vcdhandle);
void fstReaderIterBlocksSetNativeDoublesOnCallback(fstReaderContext *ctx, int enable);
fstReaderContext *fstReaderOpen(const char *nam);
fstReaderContext *fstReaderOpenForUtilitiesOnly(void);
const char *fstReaderPopScope(fstReaderContext *ctx);
int fstReaderProcessHier(fstReaderContext *ctx, FILE *vcdhandle);
const char *fstReaderPushScope(fstReaderContext *ctx, const char *nam, void *user_info);
void fstReaderResetScope(fstReaderContext *ctx);
void fstReaderSetFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
void fstReaderSetFacProcessMaskAll(fstReaderContext *ctx);
void fstReaderSetLimitTimeRange(fstReaderContext *ctx, uint64_t start_time, uint64_t end_time);
void fstReaderSetUnlimitedTimeRange(fstReaderContext *ctx);
void fstReaderSetVcdExtensions(fstReaderContext *ctx, int enable);
/* /*
* utility functions * utility functions
*/ */
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */ int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */
int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len); int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len); int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
struct fstETab *fstUtilityExtractEnumTableFromString(const char *s); struct fstETab *fstUtilityExtractEnumTableFromString(const char *s);
void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */ void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -28,7 +28,7 @@ std::vector<RTLIL::Design*> pushed_designs;
struct DesignPass : public Pass { struct DesignPass : public Pass {
DesignPass() : Pass("design", "save, restore and reset current design") { } DesignPass() : Pass("design", "save, restore and reset current design") { }
~DesignPass() override { void on_shutdown() override {
for (auto &it : saved_designs) for (auto &it : saved_designs)
delete it.second; delete it.second;
saved_designs.clear(); saved_designs.clear();

View file

@ -99,7 +99,7 @@ struct InternalStatsPass : public Pass {
if (json_mode) { if (json_mode) {
log("{\n"); log("{\n");
log(" \"creator\": %s,\n", json11::Json(yosys_version_str).dump().c_str()); log(" \"creator\": %s,\n", json11::Json(yosys_maybe_version()).dump().c_str());
std::stringstream invocation; std::stringstream invocation;
std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " ")); std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str()); log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());

View file

@ -67,7 +67,7 @@ struct LoggerPass : public Pass {
log(" -check-expected\n"); log(" -check-expected\n");
log(" verifies that the patterns previously set up by -expect have actually\n"); log(" verifies that the patterns previously set up by -expect have actually\n");
log(" been met, then clears the expected log list. If this is not called\n"); log(" been met, then clears the expected log list. If this is not called\n");
log(" manually, the check will happen at yosys exist time instead.\n"); log(" manually, the check will happen at yosys exit time instead.\n");
log("\n"); log("\n");
} }

View file

@ -444,7 +444,7 @@ struct StatPass : public Pass {
if (json_mode) { if (json_mode) {
log("{\n"); log("{\n");
log(" \"creator\": %s,\n", json11::Json(yosys_version_str).dump().c_str()); log(" \"creator\": %s,\n", json11::Json(yosys_maybe_version()).dump().c_str());
std::stringstream invocation; std::stringstream invocation;
std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " ")); std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str()); log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());

View file

@ -1452,7 +1452,7 @@ struct HierarchyPass : public Pass {
bool resize_widths = !keep_portwidths && GetSize(w) != GetSize(conn.second); bool resize_widths = !keep_portwidths && GetSize(w) != GetSize(conn.second);
if (resize_widths && verific_mod && boxed_params) if (resize_widths && verific_mod && boxed_params)
log_warning("Ignoring width mismatch on %s.%s.%s from verific, is port width parametrizable?\n", log_debug("Ignoring width mismatch on %s.%s.%s from verific, is port width parametrizable?\n",
log_id(module), log_id(cell), log_id(conn.first) log_id(module), log_id(cell), log_id(conn.first)
); );
else if (resize_widths) { else if (resize_widths) {

View file

@ -32,6 +32,7 @@ PEEPOPT_PATTERN = passes/opt/peepopt_shiftmul_right.pmg
PEEPOPT_PATTERN += passes/opt/peepopt_shiftmul_left.pmg PEEPOPT_PATTERN += passes/opt/peepopt_shiftmul_left.pmg
PEEPOPT_PATTERN += passes/opt/peepopt_shiftadd.pmg PEEPOPT_PATTERN += passes/opt/peepopt_shiftadd.pmg
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv.pmg PEEPOPT_PATTERN += passes/opt/peepopt_muldiv.pmg
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv_c.pmg
PEEPOPT_PATTERN += passes/opt/peepopt_formal_clockgateff.pmg PEEPOPT_PATTERN += passes/opt/peepopt_formal_clockgateff.pmg
passes/opt/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) passes/opt/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)

View file

@ -487,7 +487,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", ID::E, assign_map, invert_map); handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", ID::E, assign_map, invert_map);
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", ID::S, assign_map, invert_map); handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", ID::S, assign_map, invert_map);
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", ID::R, assign_map, invert_map); handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", ID::R, assign_map, invert_map);
} }
TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells; TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
@ -1307,7 +1307,12 @@ skip_fine_alu:
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)) && (keepdc ? assign_map(cell->getPort(ID::B)).is_fully_def() : assign_map(cell->getPort(ID::B)).is_fully_const())) if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)) && (keepdc ? assign_map(cell->getPort(ID::B)).is_fully_def() : assign_map(cell->getPort(ID::B)).is_fully_const()))
{ {
bool sign_ext = cell->type == ID($sshr) && cell->getParam(ID::A_SIGNED).as_bool(); bool sign_ext = cell->type == ID($sshr) && cell->getParam(ID::A_SIGNED).as_bool();
int shift_bits = assign_map(cell->getPort(ID::B)).as_int(cell->type.in(ID($shift), ID($shiftx)) && cell->getParam(ID::B_SIGNED).as_bool()); RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
const bool b_sign_ext = cell->type.in(ID($shift), ID($shiftx)) && cell->getParam(ID::B_SIGNED).as_bool();
// We saturate the value to prevent overflow, but note that this could
// cause incorrect opimization in the impractical case that A is 2^32 bits
// wide
int shift_bits = sig_b.as_int_saturating(b_sign_ext);
if (cell->type.in(ID($shl), ID($sshl))) if (cell->type.in(ID($shl), ID($sshl)))
shift_bits *= -1; shift_bits *= -1;
@ -1715,22 +1720,22 @@ skip_identity:
if (onehot) { if (onehot) {
if (bit_idx == 1) { if (bit_idx == 1) {
log_debug("Replacing pow cell `%s' in module `%s' with left-shift\n", log_debug("Replacing pow cell `%s' in module `%s' with left-shift\n",
cell->name.c_str(), module->name.c_str()); cell->name.c_str(), module->name.c_str());
cell->type = ID($shl); cell->type = ID($shl);
cell->parameters[ID::A_WIDTH] = 1; cell->parameters[ID::A_WIDTH] = 1;
cell->setPort(ID::A, Const(State::S1, 1)); cell->setPort(ID::A, Const(State::S1, 1));
} }
else { else {
log_debug("Replacing pow cell `%s' in module `%s' with multiply and left-shift\n", log_debug("Replacing pow cell `%s' in module `%s' with multiply and left-shift\n",
cell->name.c_str(), module->name.c_str()); cell->name.c_str(), module->name.c_str());
cell->type = ID($mul); cell->type = ID($mul);
cell->parameters[ID::A_SIGNED] = 0; cell->parameters[ID::A_SIGNED] = 0;
cell->setPort(ID::A, Const(bit_idx, cell->parameters[ID::A_WIDTH].as_int())); cell->setPort(ID::A, Const(bit_idx, cell->parameters[ID::A_WIDTH].as_int()));
SigSpec y_wire = module->addWire(NEW_ID, y_size); SigSpec y_wire = module->addWire(NEW_ID, y_size);
cell->setPort(ID::Y, y_wire); cell->setPort(ID::Y, y_wire);
module->addShl(NEW_ID, Const(State::S1, 1), y_wire, sig_y); module->addShl(NEW_ID, Const(State::S1, 1), y_wire, sig_y);
} }
did_something = true; did_something = true;

View file

@ -29,6 +29,14 @@ bool did_something;
// scratchpad configurations for pmgen // scratchpad configurations for pmgen
int shiftadd_max_ratio; int shiftadd_max_ratio;
// Helper function, removes LSB 0s
SigSpec remove_bottom_padding(SigSpec sig)
{
int i = 0;
for (; i < sig.size() - 1 && sig[i] == State::S0; i++);
return sig.extract(i, sig.size() - i);
}
#include "passes/opt/peepopt_pm.h" #include "passes/opt/peepopt_pm.h"
struct PeepoptPass : public Pass { struct PeepoptPass : public Pass {
@ -45,6 +53,8 @@ struct PeepoptPass : public Pass {
log("\n"); log("\n");
log(" * muldiv - Replace (A*B)/B with A\n"); log(" * muldiv - Replace (A*B)/B with A\n");
log("\n"); log("\n");
log(" * muldiv_c - Replace (A*B)/C with A*(B/C) when C is a const divisible by B.\n");
log("\n");
log(" * shiftmul - Replace A>>(B*C) with A'>>(B<<K) where C and K are constants\n"); log(" * shiftmul - Replace A>>(B*C) with A'>>(B<<K) where C and K are constants\n");
log(" and A' is derived from A by appropriately inserting padding\n"); log(" and A' is derived from A by appropriately inserting padding\n");
log(" into the signal. (right variant)\n"); log(" into the signal. (right variant)\n");
@ -106,6 +116,7 @@ struct PeepoptPass : public Pass {
pm.run_shiftmul_right(); pm.run_shiftmul_right();
pm.run_shiftmul_left(); pm.run_shiftmul_left();
pm.run_muldiv(); pm.run_muldiv();
pm.run_muldiv_c();
} }
} }
} }

View file

@ -0,0 +1,125 @@
pattern muldiv_c
//
// Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license.
// Transforms mul->div into const->mul when b and c are divisible constants:
// y = (a * b_const) / c_const ===> a * eval(b_const / c_const)
//
state <SigSpec> a b_const mul_y
match mul
// Select multiplier
select mul->type == $mul
endmatch
code a b_const mul_y
// Get multiplier signals
a = port(mul, \A);
b_const = port(mul, \B);
mul_y = port(mul, \Y);
// Fanout of each multiplier Y bit should be 1 (no bit-split)
if (nusers(mul_y) != 2)
reject;
// A and B can be interchanged
branch;
std::swap(a, b_const);
endcode
match div
// Select div of form (a * b_const) / c_const
select div->type == $div
// Check that b_const and c_const is constant
filter b_const.is_fully_const()
filter port(div, \B).is_fully_const()
index <SigSpec> remove_bottom_padding(port(div, \A)) === mul_y
endmatch
code
// Get div signals
SigSpec div_a = port(div, \A);
SigSpec c_const = port(div, \B);
SigSpec div_y = port(div, \Y);
// Get offset of multiplier result chunk in divider
int offset = GetSize(div_a) - GetSize(mul_y);
// Get properties and values of b_const and c_const
// b_const may be coming from the A port
// But it is an RTLIL invariant that A_SIGNED equals B_SIGNED
bool b_const_signed = mul->getParam(ID::B_SIGNED).as_bool();
bool c_const_signed = div->getParam(ID::B_SIGNED).as_bool();
int b_const_int = b_const.as_int(b_const_signed);
int c_const_int = c_const.as_int(c_const_signed);
int b_const_int_shifted = b_const_int << offset;
// Helper lambdas for two's complement math
auto sign2sComplement = [](auto value, int numBits) {
if (value & (1 << (numBits - 1))) {
return -1;
} else {
return 1;
}
};
auto twosComplement = [](auto value, int numBits) {
if (value & (1 << (numBits - 1))) {
return (~value) + 1; // invert bits before adding 1
} else {
return value;
}
};
// Two's complement conversion
if (b_const_signed)
b_const_int = sign2sComplement(b_const_int, GetSize(b_const)) * twosComplement(b_const_int, GetSize(b_const));
if (c_const_signed)
c_const_int = sign2sComplement(c_const_int, GetSize(c_const)) * twosComplement(c_const_int, GetSize(c_const));
// Calculate the constant and compress the width to fit the value
Const const_ratio;
Const b_const_actual;
// Avoid division by zero
if (c_const_int == 0)
reject;
b_const_actual = b_const_int_shifted;
b_const_actual.compress(b_const_signed);
const_ratio = b_const_int_shifted / c_const_int;
const_ratio.compress(b_const_signed | c_const_signed);
// Integer values should be lesser than 32 bits
// This is because we are using C++ types, and int is 32 bits
// FIXME: use long long or BigInteger to make pass work with >32 bits
if (GetSize(mul->getParam(ID::B_WIDTH)) > 32)
reject;
if (GetSize(b_const) > 32)
reject;
if (GetSize(c_const) + offset > 32)
reject;
// Check for potential multiplier overflow
if (GetSize(b_const_actual) + GetSize(a) > GetSize(mul_y))
reject;
// Check that there are only zeros before offset
if (offset < 0 || !div_a.extract(0, offset).is_fully_zero())
reject;
// Check that b is divisible by c
if (b_const_int_shifted % c_const_int != 0)
reject;
// Rewire to only keep multiplier
mul->setPort(\A, a);
mul->setPort(\B, const_ratio);
mul->setPort(\Y, div_y);
// Remove divider
autoremove(div);
// Log, fixup, accept
log("muldiv_const pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
mul->fixup_parameters();
accept;
endcode

View file

@ -288,43 +288,40 @@ struct ProcArstPass : public Pass {
extra_args(args, argidx, design); extra_args(args, argidx, design);
pool<Wire*> delete_initattr_wires; pool<Wire*> delete_initattr_wires;
for (auto mod : design->modules()) for (auto mod : design->all_selected_modules()) {
if (design->selected(mod)) { SigMap assign_map(mod);
SigMap assign_map(mod); for (auto proc : mod->selected_processes()) {
for (auto &proc_it : mod->processes) { proc_arst(mod, proc, assign_map);
if (!design->selected(mod, proc_it.second)) if (global_arst.empty() || mod->wire(global_arst) == nullptr)
continue; continue;
proc_arst(mod, proc_it.second, assign_map); std::vector<RTLIL::SigSig> arst_actions;
if (global_arst.empty() || mod->wire(global_arst) == nullptr) for (auto sync : proc->syncs)
continue; if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
std::vector<RTLIL::SigSig> arst_actions; for (auto &act : sync->actions) {
for (auto sync : proc_it.second->syncs) RTLIL::SigSpec arst_sig, arst_val;
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) for (auto &chunk : act.first.chunks())
for (auto &act : sync->actions) { if (chunk.wire && chunk.wire->attributes.count(ID::init)) {
RTLIL::SigSpec arst_sig, arst_val; RTLIL::SigSpec value = chunk.wire->attributes.at(ID::init);
for (auto &chunk : act.first.chunks()) value.extend_u0(chunk.wire->width, false);
if (chunk.wire && chunk.wire->attributes.count(ID::init)) { arst_sig.append(chunk);
RTLIL::SigSpec value = chunk.wire->attributes.at(ID::init); arst_val.append(value.extract(chunk.offset, chunk.width));
value.extend_u0(chunk.wire->width, false); delete_initattr_wires.insert(chunk.wire);
arst_sig.append(chunk);
arst_val.append(value.extract(chunk.offset, chunk.width));
delete_initattr_wires.insert(chunk.wire);
}
if (arst_sig.size()) {
log("Added global reset to process %s: %s <- %s\n",
proc_it.first.c_str(), log_signal(arst_sig), log_signal(arst_val));
arst_actions.push_back(RTLIL::SigSig(arst_sig, arst_val));
} }
if (arst_sig.size()) {
log("Added global reset to process %s: %s <- %s\n",
proc->name.c_str(), log_signal(arst_sig), log_signal(arst_val));
arst_actions.push_back(RTLIL::SigSig(arst_sig, arst_val));
} }
if (!arst_actions.empty()) { }
RTLIL::SyncRule *sync = new RTLIL::SyncRule; if (!arst_actions.empty()) {
sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1; RTLIL::SyncRule *sync = new RTLIL::SyncRule;
sync->signal = mod->wire(global_arst); sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1;
sync->actions = arst_actions; sync->signal = mod->wire(global_arst);
proc_it.second->syncs.push_back(sync); sync->actions = arst_actions;
} proc->syncs.push_back(sync);
} }
} }
}
for (auto wire : delete_initattr_wires) for (auto wire : delete_initattr_wires)
wire->attributes.erase(ID::init); wire->attributes.erase(ID::init);

View file

@ -208,19 +208,15 @@ struct ProcCleanPass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto mod : design->modules()) { for (auto mod : design->all_selected_modules()) {
std::vector<RTLIL::Process *> delme; std::vector<RTLIL::Process *> delme;
if (!design->selected(mod)) for (auto proc : mod->selected_processes()) {
continue; proc_clean(mod, proc, total_count, quiet);
for (auto &proc_it : mod->processes) { if (proc->syncs.size() == 0 && proc->root_case.switches.size() == 0 &&
if (!design->selected(mod, proc_it.second)) proc->root_case.actions.size() == 0) {
continue;
proc_clean(mod, proc_it.second, total_count, quiet);
if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 &&
proc_it.second->root_case.actions.size() == 0) {
if (!quiet) if (!quiet)
log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str()); log("Removing empty process `%s.%s'.\n", log_id(mod), proc->name.c_str());
delme.push_back(proc_it.second); delme.push_back(proc);
} }
} }
for (auto proc : delme) { for (auto proc : delme) {

View file

@ -306,13 +306,11 @@ struct ProcDffPass : public Pass {
extra_args(args, 1, design); extra_args(args, 1, design);
for (auto mod : design->modules()) for (auto mod : design->all_selected_modules()) {
if (design->selected(mod)) { ConstEval ce(mod);
ConstEval ce(mod); for (auto proc : mod->selected_processes())
for (auto &proc_it : mod->processes) proc_dff(mod, proc, ce);
if (design->selected(mod, proc_it.second)) }
proc_dff(mod, proc_it.second, ce);
}
} }
} ProcDffPass; } ProcDffPass;

View file

@ -463,11 +463,10 @@ struct ProcDlatchPass : public Pass {
extra_args(args, 1, design); extra_args(args, 1, design);
for (auto module : design->selected_modules()) { for (auto mod : design->all_selected_modules()) {
proc_dlatch_db_t db(module); proc_dlatch_db_t db(mod);
for (auto &proc_it : module->processes) for (auto proc : mod->selected_processes())
if (design->selected(module, proc_it.second)) proc_dlatch(db, proc);
proc_dlatch(db, proc_it.second);
db.fixup_muxes(); db.fixup_muxes();
} }
} }

View file

@ -91,13 +91,11 @@ struct ProcInitPass : public Pass {
extra_args(args, 1, design); extra_args(args, 1, design);
for (auto mod : design->modules()) for (auto mod : design->all_selected_modules()) {
if (design->selected(mod)) { SigMap sigmap(mod);
SigMap sigmap(mod); for (auto proc : mod->selected_processes())
for (auto &proc_it : mod->processes) proc_init(mod, sigmap, proc);
if (design->selected(mod, proc_it.second)) }
proc_init(mod, sigmap, proc_it.second);
}
} }
} ProcInitPass; } ProcInitPass;

View file

@ -99,9 +99,9 @@ struct ProcMemWrPass : public Pass {
extra_args(args, 1, design); extra_args(args, 1, design);
for (auto module : design->selected_modules()) { for (auto mod : design->all_selected_modules()) {
dict<IdString, int> next_port_id; dict<IdString, int> next_port_id;
for (auto cell : module->cells()) { for (auto cell : mod->cells()) {
if (cell->type.in(ID($memwr), ID($memwr_v2))) { if (cell->type.in(ID($memwr), ID($memwr_v2))) {
bool is_compat = cell->type == ID($memwr); bool is_compat = cell->type == ID($memwr);
IdString memid = cell->parameters.at(ID::MEMID).decode_string(); IdString memid = cell->parameters.at(ID::MEMID).decode_string();
@ -110,9 +110,8 @@ struct ProcMemWrPass : public Pass {
next_port_id[memid] = port_id + 1; next_port_id[memid] = port_id + 1;
} }
} }
for (auto &proc_it : module->processes) for (auto proc : mod->selected_processes())
if (design->selected(module, proc_it.second)) proc_memwr(mod, proc, next_port_id);
proc_memwr(module, proc_it.second, next_port_id);
} }
} }
} ProcMemWrPass; } ProcMemWrPass;

View file

@ -468,11 +468,9 @@ struct ProcMuxPass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto mod : design->modules()) for (auto mod : design->all_selected_modules())
if (design->selected(mod)) for (auto proc : mod->selected_processes())
for (auto &proc_it : mod->processes) proc_mux(mod, proc, ifxmode);
if (design->selected(mod, proc_it.second))
proc_mux(mod, proc_it.second, ifxmode);
} }
} ProcMuxPass; } ProcMuxPass;

View file

@ -127,15 +127,10 @@ struct ProcPrunePass : public Pass {
extra_args(args, 1, design); extra_args(args, 1, design);
for (auto mod : design->modules()) { for (auto mod : design->all_selected_modules()) {
if (!design->selected(mod))
continue;
PruneWorker worker(mod); PruneWorker worker(mod);
for (auto &proc_it : mod->processes) { for (auto proc : mod->selected_processes())
if (!design->selected(mod, proc_it.second)) worker.do_process(proc);
continue;
worker.do_process(proc_it.second);
}
total_removed_count += worker.removed_count; total_removed_count += worker.removed_count;
total_promoted_count += worker.promoted_count; total_promoted_count += worker.promoted_count;
} }

View file

@ -147,21 +147,17 @@ struct ProcRmdeadPass : public Pass {
extra_args(args, 1, design); extra_args(args, 1, design);
int total_counter = 0; int total_counter = 0;
for (auto mod : design->modules()) { for (auto mod : design->all_selected_modules()) {
if (!design->selected(mod)) for (auto proc : mod->selected_processes()) {
continue;
for (auto &proc_it : mod->processes) {
if (!design->selected(mod, proc_it.second))
continue;
int counter = 0, full_case_counter = 0; int counter = 0, full_case_counter = 0;
for (auto switch_it : proc_it.second->root_case.switches) for (auto switch_it : proc->root_case.switches)
proc_rmdead(switch_it, counter, full_case_counter); proc_rmdead(switch_it, counter, full_case_counter);
if (counter > 0) if (counter > 0)
log("Removed %d dead cases from process %s in module %s.\n", counter, log("Removed %d dead cases from process %s in module %s.\n", counter,
log_id(proc_it.first), log_id(mod)); log_id(proc), log_id(mod));
if (full_case_counter > 0) if (full_case_counter > 0)
log("Marked %d switch rules as full_case in process %s in module %s.\n", log("Marked %d switch rules as full_case in process %s in module %s.\n",
full_case_counter, log_id(proc_it.first), log_id(mod)); full_case_counter, log_id(proc), log_id(mod));
total_counter += counter; total_counter += counter;
} }
} }

View file

@ -243,15 +243,10 @@ struct ProcRomPass : public Pass {
extra_args(args, 1, design); extra_args(args, 1, design);
for (auto mod : design->modules()) { for (auto mod : design->all_selected_modules()) {
if (!design->selected(mod))
continue;
RomWorker worker(mod); RomWorker worker(mod);
for (auto &proc_it : mod->processes) { for (auto proc : mod->selected_processes())
if (!design->selected(mod, proc_it.second)) worker.do_process(proc);
continue;
worker.do_process(proc_it.second);
}
total_count += worker.count; total_count += worker.count;
} }

View file

@ -86,6 +86,20 @@ struct CutpointPass : public Pass {
for (auto module : design->all_selected_modules()) for (auto module : design->all_selected_modules())
{ {
if (module->is_selected_whole()) {
log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module));
module->new_connections(std::vector<RTLIL::SigSig>());
for (auto cell : vector<Cell*>(module->cells()))
module->remove(cell);
vector<Wire*> output_wires;
for (auto wire : module->wires())
if (wire->port_output)
output_wires.push_back(wire);
for (auto wire : output_wires)
module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire)));
continue;
}
SigMap sigmap(module); SigMap sigmap(module);
pool<SigBit> cutpoint_bits; pool<SigBit> cutpoint_bits;

View file

@ -691,7 +691,7 @@ struct SatHelper
fprintf(f, " %s\n", stime); fprintf(f, " %s\n", stime);
fprintf(f, "$end\n"); fprintf(f, "$end\n");
fprintf(f, "$version\n"); fprintf(f, "$version\n");
fprintf(f, " Generated by %s\n", yosys_version_str); fprintf(f, " Generated by %s\n", yosys_maybe_version());
fprintf(f, "$end\n"); fprintf(f, "$end\n");
fprintf(f, "$comment\n"); fprintf(f, "$comment\n");
fprintf(f, " Generated from SAT problem in module %s (declared at %s)\n", fprintf(f, " Generated from SAT problem in module %s (declared at %s)\n",

View file

@ -1546,36 +1546,27 @@ struct SimWorker : SimShared
log(" for %d clock cycle(s)",numcycles); log(" for %d clock cycle(s)",numcycles);
log("\n"); log("\n");
bool all_samples = fst_clock.empty(); bool all_samples = fst_clock.empty();
unsigned int end_cycle = cycles_set ? numcycles*2 : INT_MAX;
try { fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, end_cycle, [&](uint64_t time) {
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) { if (verbose)
if (verbose) log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString()); bool did_something = top->setInputs();
bool did_something = top->setInputs();
if (initial) { if (initial) {
if (!fst_noinit) did_something |= top->setInitState(); if (!fst_noinit) did_something |= top->setInitState();
initialize_stable_past(); initialize_stable_past();
initial = false; initial = false;
} }
if (did_something) if (did_something)
update(true); update(true);
register_output_step(time); register_output_step(time);
bool status = top->checkSignals(); bool status = top->checkSignals();
if (status) if (status)
log_error("Signal difference\n"); log_error("Signal difference\n");
cycle++; cycle++;
});
// Limit to number of cycles if provided
if (cycles_set && cycle > numcycles *2)
throw fst_end_of_data_exception();
if (time==stopCount)
throw fst_end_of_data_exception();
});
} catch(fst_end_of_data_exception) {
// end of data detected
}
write_output_files(); write_output_files();
delete fst; delete fst;
@ -2065,7 +2056,7 @@ struct SimWorker : SimShared
json.begin_object(); json.begin_object();
json.entry("version", "Yosys sim summary"); json.entry("version", "Yosys sim summary");
json.entry("generator", yosys_version_str); json.entry("generator", yosys_maybe_version());
json.entry("steps", step); json.entry("steps", step);
json.entry("top", log_id(top->module->name)); json.entry("top", log_id(top->module->name));
json.name("assertions"); json.name("assertions");
@ -2248,40 +2239,31 @@ struct SimWorker : SimShared
log("Writing data to `%s`\n", (tb_filename+".txt").c_str()); log("Writing data to `%s`\n", (tb_filename+".txt").c_str());
std::ofstream data_file(tb_filename+".txt"); std::ofstream data_file(tb_filename+".txt");
std::stringstream initstate; std::stringstream initstate;
try { unsigned int end_cycle = cycles_set ? numcycles*2 : INT_MAX;
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) { fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, end_cycle, [&](uint64_t time) {
for(auto &item : clocks) for(auto &item : clocks)
data_file << stringf("%s",fst->valueOf(item.second).c_str()); data_file << stringf("%s",fst->valueOf(item.second).c_str());
for(auto &item : inputs) for(auto &item : inputs)
data_file << stringf("%s",fst->valueOf(item.second).c_str()); data_file << stringf("%s",fst->valueOf(item.second).c_str());
for(auto &item : outputs) for(auto &item : outputs)
data_file << stringf("%s",fst->valueOf(item.second).c_str()); data_file << stringf("%s",fst->valueOf(item.second).c_str());
data_file << stringf("%s\n",Const(time-prev_time).as_string().c_str()); data_file << stringf("%s\n",Const(time-prev_time).as_string().c_str());
if (time==startCount) { if (time==startCount) {
// initial state // initial state
for(auto var : fst->getVars()) { for(auto var : fst->getVars()) {
if (var.is_reg && !Const::from_string(fst->valueOf(var.id).c_str()).is_fully_undef()) { if (var.is_reg && !Const::from_string(fst->valueOf(var.id).c_str()).is_fully_undef()) {
if (var.scope == scope) { if (var.scope == scope) {
initstate << stringf("\t\tuut.%s = %d'b%s;\n", var.name.c_str(), var.width, fst->valueOf(var.id).c_str()); initstate << stringf("\t\tuut.%s = %d'b%s;\n", var.name.c_str(), var.width, fst->valueOf(var.id).c_str());
} else if (var.scope.find(scope+".")==0) { } else if (var.scope.find(scope+".")==0) {
initstate << stringf("\t\tuut.%s.%s = %d'b%s;\n",var.scope.substr(scope.size()+1).c_str(), var.name.c_str(), var.width, fst->valueOf(var.id).c_str()); initstate << stringf("\t\tuut.%s.%s = %d'b%s;\n",var.scope.substr(scope.size()+1).c_str(), var.name.c_str(), var.width, fst->valueOf(var.id).c_str());
}
} }
} }
} }
cycle++; }
prev_time = time; cycle++;
prev_time = time;
// Limit to number of cycles if provided });
if (cycles_set && cycle > numcycles *2)
throw fst_end_of_data_exception();
if (time==stopCount)
throw fst_end_of_data_exception();
});
} catch(fst_end_of_data_exception) {
// end of data detected
}
f << stringf("\treg [0:%d] data [0:%d];\n", data_len-1, cycle-1); f << stringf("\treg [0:%d] data [0:%d];\n", data_len-1, cycle-1);
f << "\tinitial begin;\n"; f << "\tinitial begin;\n";
@ -2344,7 +2326,7 @@ struct VCDWriter : public OutputWriter
void write(std::map<int, bool> &use_signal) override void write(std::map<int, bool> &use_signal) override
{ {
if (!vcdfile.is_open()) return; if (!vcdfile.is_open()) return;
vcdfile << stringf("$version %s $end\n", worker->date ? yosys_version_str : "Yosys"); vcdfile << stringf("$version %s $end\n", worker->date ? yosys_maybe_version() : "Yosys");
if (worker->date) { if (worker->date) {
std::time_t t = std::time(nullptr); std::time_t t = std::time(nullptr);
@ -2400,7 +2382,7 @@ struct VCDWriter : public OutputWriter
struct FSTWriter : public OutputWriter struct FSTWriter : public OutputWriter
{ {
FSTWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) { FSTWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) {
fstfile = (struct fstContext *)fstWriterCreate(filename.c_str(),1); fstfile = fstWriterCreate(filename.c_str(),1);
} }
virtual ~FSTWriter() virtual ~FSTWriter()
@ -2412,7 +2394,7 @@ struct FSTWriter : public OutputWriter
{ {
if (!fstfile) return; if (!fstfile) return;
std::time_t t = std::time(nullptr); std::time_t t = std::time(nullptr);
fstWriterSetVersion(fstfile, worker->date ? yosys_version_str : "Yosys"); fstWriterSetVersion(fstfile, worker->date ? yosys_maybe_version() : "Yosys");
if (worker->date) if (worker->date)
fstWriterSetDate(fstfile, asctime(std::localtime(&t))); fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
else else
@ -2456,7 +2438,7 @@ struct FSTWriter : public OutputWriter
} }
} }
struct fstContext *fstfile = nullptr; struct fstWriterContext *fstfile = nullptr;
std::map<int,fstHandle> mapping; std::map<int,fstHandle> mapping;
}; };

View file

@ -168,7 +168,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
vector<int> lut_costs, bool dff_mode, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, vector<int> lut_costs, bool dff_mode, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
bool show_tempdir, std::string box_file, std::string lut_file, bool show_tempdir, std::string box_file, std::string lut_file,
std::vector<std::string> liberty_files, std::string wire_delay, std::string tempdir_name, std::vector<std::string> liberty_files, std::string wire_delay, std::string tempdir_name,
std::string constr_file, std::vector<std::string> dont_use_cells) std::string constr_file, std::vector<std::string> dont_use_cells, std::vector<std::string> genlib_files)
{ {
std::string abc9_script; std::string abc9_script;
@ -186,6 +186,10 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
} }
if (!constr_file.empty()) if (!constr_file.empty())
abc9_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str()); abc9_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str());
} else if (!genlib_files.empty()) {
for (std::string genlib_file : genlib_files) {
abc9_script += stringf("read_genlib \"%s\"; ", genlib_file.c_str());
}
} }
log_assert(!box_file.empty()); log_assert(!box_file.empty());
@ -384,9 +388,14 @@ struct Abc9ExePass : public Pass {
log(" read the given Liberty file as a description of the target cell library.\n"); log(" read the given Liberty file as a description of the target cell library.\n");
log(" this option can be used multiple times.\n"); log(" this option can be used multiple times.\n");
log("\n"); log("\n");
log(" -genlib <file>\n");
log(" read the given genlib file as a description of the target cell library.\n");
log(" this option can be used multiple times.\n");
log("\n");
log(" -dont_use <cell_name>\n"); log(" -dont_use <cell_name>\n");
log(" avoid usage of the technology cell <cell_name> when mapping the design.\n"); log(" avoid usage of the technology cell <cell_name> when mapping the design.\n");
log(" this option can be used multiple times.\n"); log(" this option can be used multiple times. only supported with Liberty\n");
log(" cell libraries.\n");
log("\n"); log("\n");
log(" -D <picoseconds>\n"); log(" -D <picoseconds>\n");
log(" set delay target. the string {D} in the default scripts above is\n"); log(" set delay target. the string {D} in the default scripts above is\n");
@ -441,7 +450,7 @@ struct Abc9ExePass : public Pass {
std::string exe_file = yosys_abc_executable; std::string exe_file = yosys_abc_executable;
std::string script_file, clk_str, box_file, lut_file, constr_file; std::string script_file, clk_str, box_file, lut_file, constr_file;
std::vector<std::string> liberty_files, dont_use_cells; std::vector<std::string> liberty_files, genlib_files, dont_use_cells;
std::string delay_target, lutin_shared = "-S 1", wire_delay; std::string delay_target, lutin_shared = "-S 1", wire_delay;
std::string tempdir_name; std::string tempdir_name;
bool fast_mode = false, dff_mode = false; bool fast_mode = false, dff_mode = false;
@ -530,9 +539,15 @@ struct Abc9ExePass : public Pass {
continue; continue;
} }
if (arg == "-liberty" && argidx+1 < args.size()) { if (arg == "-liberty" && argidx+1 < args.size()) {
rewrite_filename(args[argidx+1]);
liberty_files.push_back(args[++argidx]); liberty_files.push_back(args[++argidx]);
continue; continue;
} }
if (arg == "-genlib" && argidx+1 < args.size()) {
rewrite_filename(args[argidx+1]);
genlib_files.push_back(args[++argidx]);
continue;
}
if (arg == "-dont_use" && argidx+1 < args.size()) { if (arg == "-dont_use" && argidx+1 < args.size()) {
dont_use_cells.push_back(args[++argidx]); dont_use_cells.push_back(args[++argidx]);
continue; continue;
@ -601,11 +616,13 @@ struct Abc9ExePass : public Pass {
if (tempdir_name.empty()) if (tempdir_name.empty())
log_cmd_error("abc9_exe '-cwd' option is mandatory.\n"); log_cmd_error("abc9_exe '-cwd' option is mandatory.\n");
if (!genlib_files.empty() && !dont_use_cells.empty())
log_cmd_error("abc9_exe '-genlib' is incompatible with '-dont_use'.\n");
abc9_module(design, script_file, exe_file, lut_costs, dff_mode, abc9_module(design, script_file, exe_file, lut_costs, dff_mode,
delay_target, lutin_shared, fast_mode, show_tempdir, delay_target, lutin_shared, fast_mode, show_tempdir,
box_file, lut_file, liberty_files, wire_delay, tempdir_name, box_file, lut_file, liberty_files, wire_delay, tempdir_name,
constr_file, dont_use_cells); constr_file, dont_use_cells, genlib_files);
} }
} Abc9ExePass; } Abc9ExePass;

View file

@ -123,7 +123,7 @@ void check(RTLIL::Design *design, bool dff_mode)
log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type)); log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type));
if (derived_module->has_processes()) if (derived_module->has_processes())
Pass::call_on_module(design, derived_module, "proc"); Pass::call_on_module(design, derived_module, "proc -noopt");
bool found = false; bool found = false;
for (auto derived_cell : derived_module->cells()) { for (auto derived_cell : derived_module->cells()) {
@ -204,7 +204,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
if (!unmap_design->module(derived_type)) { if (!unmap_design->module(derived_type)) {
if (derived_module->has_processes()) if (derived_module->has_processes())
Pass::call_on_module(design, derived_module, "proc"); Pass::call_on_module(design, derived_module, "proc -noopt");
if (derived_module->get_bool_attribute(ID::abc9_flop)) { if (derived_module->get_bool_attribute(ID::abc9_flop)) {
for (auto derived_cell : derived_module->cells()) for (auto derived_cell : derived_module->cells())
@ -834,7 +834,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
holes_cell = holes_module->addCell(NEW_ID, cell->type); holes_cell = holes_module->addCell(NEW_ID, cell->type);
if (box_module->has_processes()) if (box_module->has_processes())
Pass::call_on_module(design, box_module, "proc"); Pass::call_on_module(design, box_module, "proc -noopt");
int box_inputs = 0; int box_inputs = 0;
for (auto port_name : box_ports.at(cell->type)) { for (auto port_name : box_ports.at(cell->type)) {

View file

@ -68,6 +68,7 @@ struct AbcNewPass : public ScriptPass {
log(" -constr <file>\n"); log(" -constr <file>\n");
log(" -dont_use <cell_name>\n"); log(" -dont_use <cell_name>\n");
log(" -liberty <file>\n"); log(" -liberty <file>\n");
log(" -genlib <file>\n");
log(" these options are passed on to the 'abc9_exe' command which invokes\n"); log(" these options are passed on to the 'abc9_exe' command which invokes\n");
log(" the ABC tool on individual modules of the design. please see\n"); log(" the ABC tool on individual modules of the design. please see\n");
log(" 'help abc9_exe' for more details\n"); log(" 'help abc9_exe' for more details\n");
@ -90,7 +91,7 @@ struct AbcNewPass : public ScriptPass {
if (args[argidx] == "-exe" || args[argidx] == "-script" || if (args[argidx] == "-exe" || args[argidx] == "-script" ||
args[argidx] == "-D" || args[argidx] == "-D" ||
args[argidx] == "-constr" || args[argidx] == "-dont_use" || args[argidx] == "-constr" || args[argidx] == "-dont_use" ||
args[argidx] == "-liberty") { args[argidx] == "-liberty" || args[argidx] == "-genlib") {
abc_exe_options += " " + args[argidx] + " " + args[argidx + 1]; abc_exe_options += " " + args[argidx] + " " + args[argidx + 1];
argidx++; argidx++;
} else if (args[argidx] == "-run" && argidx + 1 < args.size()) { } else if (args[argidx] == "-run" && argidx + 1 < args.size()) {

View file

@ -47,6 +47,13 @@
log("\n"); log("\n");
log("Displays the current cache settings and cached paths.\n"); log("Displays the current cache settings and cached paths.\n");
log("\n"); log("\n");
log(" libcache {-verbose|-quiet}\n");
log("\n");
log("Controls cache use logging.\n");
log("\n");
log(" -verbose Enable printing info when cache is used\n");
log(" -quiet Disable printing info when cache is used (default)\n");
log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design *) override void execute(std::vector<std::string> args, RTLIL::Design *) override
{ {
@ -55,6 +62,8 @@
bool purge = false; bool purge = false;
bool all = false; bool all = false;
bool list = false; bool list = false;
bool verbose = false;
bool quiet = false;
std::vector<std::string> paths; std::vector<std::string> paths;
size_t argidx; size_t argidx;
@ -79,16 +88,24 @@
list = true; list = true;
continue; continue;
} }
if (args[argidx] == "-verbose") {
verbose = true;
continue;
}
if (args[argidx] == "-quiet") {
quiet = true;
continue;
}
std::string fname = args[argidx]; std::string fname = args[argidx];
rewrite_filename(fname); rewrite_filename(fname);
paths.push_back(fname); paths.push_back(fname);
break; break;
} }
int modes = enable + disable + purge + list; int modes = enable + disable + purge + list + verbose + quiet;
if (modes == 0) if (modes == 0)
log_cmd_error("At least one of -enable, -disable, -purge or -list is required.\n"); log_cmd_error("At least one of -enable, -disable, -purge, -list,\n-verbose, or -quiet is required.\n");
if (modes > 1) if (modes > 1)
log_cmd_error("Only one of -enable, -disable, -purge or -list may be present.\n"); log_cmd_error("Only one of -enable, -disable, -purge, -list,\n-verbose, or -quiet may be present.\n");
if (all && !paths.empty()) if (all && !paths.empty())
log_cmd_error("The -all option cannot be combined with a list of paths.\n"); log_cmd_error("The -all option cannot be combined with a list of paths.\n");
@ -121,6 +138,10 @@
LibertyAstCache::instance.cache_path.erase(path); LibertyAstCache::instance.cache_path.erase(path);
} }
} }
} else if (verbose) {
LibertyAstCache::instance.verbose = true;
} else if (quiet) {
LibertyAstCache::instance.verbose = false;
} else { } else {
log_assert(false); log_assert(false);
} }

View file

@ -41,7 +41,8 @@ std::shared_ptr<const LibertyAst> LibertyAstCache::cached_ast(const std::string
auto it = cached.find(fname); auto it = cached.find(fname);
if (it == cached.end()) if (it == cached.end())
return nullptr; return nullptr;
log("Using cached data for liberty file `%s'\n", fname.c_str()); if (verbose)
log("Using cached data for liberty file `%s'\n", fname.c_str());
return it->second; return it->second;
} }
@ -51,7 +52,8 @@ void LibertyAstCache::parsed_ast(const std::string &fname, const std::shared_ptr
bool should_cache = it == cache_path.end() ? cache_by_default : it->second; bool should_cache = it == cache_path.end() ? cache_by_default : it->second;
if (!should_cache) if (!should_cache)
return; return;
log("Caching data for liberty file `%s'\n", fname.c_str()); if (verbose)
log("Caching data for liberty file `%s'\n", fname.c_str());
cached.emplace(fname, ast); cached.emplace(fname, ast);
} }

View file

@ -140,6 +140,7 @@ namespace Yosys
dict<std::string, std::shared_ptr<const LibertyAst>> cached; dict<std::string, std::shared_ptr<const LibertyAst>> cached;
bool cache_by_default = false; bool cache_by_default = false;
bool verbose = false;
dict<std::string, bool> cache_path; dict<std::string, bool> cache_path;
std::shared_ptr<const LibertyAst> cached_ast(const std::string &fname); std::shared_ptr<const LibertyAst> cached_ast(const std::string &fname);

View file

@ -35,3 +35,25 @@ ram huge $__XILINX_URAM_ {
wrbe_separate; wrbe_separate;
} }
} }
ram huge $__XILINX_URAM_SP_ {
abits 11;
width 144;
cost 1024;
option "BYTEWIDTH" 8 byte 8;
option "BYTEWIDTH" 9 byte 9;
init zero;
port srsw "A" {
clock anyedge "C";
clken;
rdwr no_change;
rdinit zero;
portoption "RST_MODE" "SYNC" {
rdsrst zero ungated;
}
portoption "RST_MODE" "ASYNC" {
rdarst zero;
}
wrbe_separate;
}
}

View file

@ -150,3 +150,141 @@ module $__XILINX_URAM_ (...);
.SLEEP(1'b0) .SLEEP(1'b0)
); );
endmodule endmodule
module $__XILINX_URAM_SP_ (...);
parameter OPTION_BYTEWIDTH = 8;
localparam WR_BE_WIDTH = 144 / OPTION_BYTEWIDTH;
parameter CLK_C_POL = 1;
parameter PORT_A_CLK_POL = 1;
parameter PORT_A_OPTION_RST_MODE = "SYNC";
input CLK_C;
input PORT_A_CLK;
input PORT_A_CLK_EN;
input PORT_A_RD_SRST;
input PORT_A_RD_ARST;
input PORT_A_WR_EN;
input [WR_BE_WIDTH-1:0] PORT_A_WR_BE;
input [10:0] PORT_A_ADDR;
input [143:0] PORT_A_WR_DATA;
output [143:0] PORT_A_RD_DATA;
wire [71:0] DIN_A, DIN_B, DOUT_A, DOUT_B;
generate
if (OPTION_BYTEWIDTH == 8) begin
assign DIN_A = PORT_A_WR_DATA[71:0];
assign DIN_B = PORT_A_WR_DATA[143:72];
assign PORT_A_RD_DATA = {DOUT_B, DOUT_A};
end else begin
assign DIN_A = {
PORT_A_WR_DATA[71],
PORT_A_WR_DATA[62],
PORT_A_WR_DATA[53],
PORT_A_WR_DATA[44],
PORT_A_WR_DATA[35],
PORT_A_WR_DATA[26],
PORT_A_WR_DATA[17],
PORT_A_WR_DATA[8],
PORT_A_WR_DATA[70:63],
PORT_A_WR_DATA[61:54],
PORT_A_WR_DATA[52:45],
PORT_A_WR_DATA[43:36],
PORT_A_WR_DATA[34:27],
PORT_A_WR_DATA[25:18],
PORT_A_WR_DATA[16:9],
PORT_A_WR_DATA[7:0]
};
assign DIN_B = {
PORT_A_WR_DATA[72+71],
PORT_A_WR_DATA[72+62],
PORT_A_WR_DATA[72+53],
PORT_A_WR_DATA[72+44],
PORT_A_WR_DATA[72+35],
PORT_A_WR_DATA[72+26],
PORT_A_WR_DATA[72+17],
PORT_A_WR_DATA[72+8],
PORT_A_WR_DATA[72+70:72+63],
PORT_A_WR_DATA[72+61:72+54],
PORT_A_WR_DATA[72+52:72+45],
PORT_A_WR_DATA[72+43:72+36],
PORT_A_WR_DATA[72+34:72+27],
PORT_A_WR_DATA[72+25:72+18],
PORT_A_WR_DATA[72+16:72+ 9],
PORT_A_WR_DATA[72+ 7:72+ 0]
};
assign PORT_A_RD_DATA = {
DOUT_B[71],
DOUT_B[63:56],
DOUT_B[70],
DOUT_B[55:48],
DOUT_B[69],
DOUT_B[47:40],
DOUT_B[68],
DOUT_B[39:32],
DOUT_B[67],
DOUT_B[31:24],
DOUT_B[66],
DOUT_B[23:16],
DOUT_B[65],
DOUT_B[15:8],
DOUT_B[64],
DOUT_B[7:0],
DOUT_A[71],
DOUT_A[63:56],
DOUT_A[70],
DOUT_A[55:48],
DOUT_A[69],
DOUT_A[47:40],
DOUT_A[68],
DOUT_A[39:32],
DOUT_A[67],
DOUT_A[31:24],
DOUT_A[66],
DOUT_A[23:16],
DOUT_A[65],
DOUT_A[15:8],
DOUT_A[64],
DOUT_A[7:0]
};
end
endgenerate
URAM288 #(
.BWE_MODE_A(OPTION_BYTEWIDTH == 8 ? "PARITY_INDEPENDENT" : "PARITY_INTERLEAVED"),
.BWE_MODE_B(OPTION_BYTEWIDTH == 8 ? "PARITY_INDEPENDENT" : "PARITY_INTERLEAVED"),
.EN_AUTO_SLEEP_MODE("FALSE"),
.IREG_PRE_A("FALSE"),
.IREG_PRE_B("FALSE"),
.IS_CLK_INVERTED(!CLK_C_POL),
.OREG_A("FALSE"),
.OREG_B("FALSE"),
.RST_MODE_A(PORT_A_OPTION_RST_MODE),
.RST_MODE_B(PORT_A_OPTION_RST_MODE),
) _TECHMAP_REPLACE_ (
.ADDR_A({11'b0, PORT_A_ADDR, 1'b0}),
.BWE_A(PORT_A_WR_BE[WR_BE_WIDTH/2-1:0]),
.EN_A(PORT_A_CLK_EN),
.RDB_WR_A(PORT_A_WR_EN),
.INJECT_DBITERR_A(1'b0),
.INJECT_SBITERR_A(1'b0),
.RST_A(PORT_A_OPTION_RST_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
.DIN_A(DIN_A),
.DOUT_A(DOUT_A),
.ADDR_B({11'b0, PORT_A_ADDR, 1'b1}),
.BWE_B(PORT_A_WR_BE[WR_BE_WIDTH-1:WR_BE_WIDTH/2]),
.EN_B(PORT_A_CLK_EN),
.RDB_WR_B(PORT_A_WR_EN),
.INJECT_DBITERR_B(1'b0),
.INJECT_SBITERR_B(1'b0),
.RST_B(PORT_A_OPTION_RST_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
.DIN_B(DIN_B),
.DOUT_B(DOUT_B),
.CLK(CLK_C),
.SLEEP(1'b0)
);
endmodule

10
tests/aiger/io.ys Normal file
View file

@ -0,0 +1,10 @@
read_verilog <<EOF
module bad(
input in,
output reg [1:0] out
);
assign out = {in, 1'b0};
endmodule
EOF
proc
write_aiger -vmap /dev/null /dev/null

View file

@ -2,7 +2,7 @@ module priority_memory (
clk, wren_a, rden_a, addr_a, wdata_a, rdata_a, clk, wren_a, rden_a, addr_a, wdata_a, rdata_a,
wren_b, rden_b, addr_b, wdata_b, rdata_b wren_b, rden_b, addr_b, wdata_b, rdata_b
); );
parameter ABITS = 12; parameter ABITS = 12;
parameter WIDTH = 72; parameter WIDTH = 72;
@ -30,7 +30,7 @@ module priority_memory (
mem[addr_a] <= wdata_a; mem[addr_a] <= wdata_a;
else if (rden_a) else if (rden_a)
rdata_a <= mem[addr_a]; rdata_a <= mem[addr_a];
// B port // B port
if (wren_b) if (wren_b)
mem[addr_b] <= wdata_b; mem[addr_b] <= wdata_b;
@ -47,7 +47,7 @@ module priority_memory (
mem[addr_b] <= wdata_b; mem[addr_b] <= wdata_b;
else if (rden_b) else if (rden_b)
rdata_b <= mem[addr_b]; rdata_b <= mem[addr_b];
// B port // B port
if (wren_a) if (wren_a)
mem[addr_a] <= wdata_a; mem[addr_a] <= wdata_a;
@ -79,12 +79,11 @@ module sp_write_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
rdata_a <= 'h0; rdata_a <= 'h0;
end end
always @(posedge clk) begin always @(posedge clk) begin
// A port // A port
if (wren_a) if (wren_a)
mem[addr_a] <= wdata_a; mem[addr_a] <= wdata_a;
if (rden_a) if (rden_a)
if (wren_a) if (wren_a)
rdata_a <= wdata_a; rdata_a <= wdata_a;
else else
@ -111,12 +110,39 @@ module sp_read_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
rdata_a <= 'h0; rdata_a <= 'h0;
end end
always @(posedge clk) begin always @(posedge clk) begin
// A port // A port
if (wren_a) if (wren_a)
mem[addr_a] <= wdata_a; mem[addr_a] <= wdata_a;
if (rden_a) if (rden_a)
rdata_a <= mem[addr_a]; rdata_a <= mem[addr_a];
end end
endmodule endmodule
module sp_read_or_write (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
parameter ABITS = 11;
parameter WIDTH = 144;
input clk;
input wren_a, rden_a;
input [ABITS-1:0] addr_a;
input [WIDTH-1:0] wdata_a;
output reg [WIDTH-1:0] rdata_a;
(* ram_style = "huge" *)
reg [WIDTH-1:0] mem [0:2**ABITS-1];
integer i;
initial begin
rdata_a <= 'h0;
end
always @(posedge clk) begin
if (wren_a)
mem[addr_a] <= wdata_a;
else if (rden_a)
rdata_a <= mem[addr_a];
end
endmodule

View file

@ -58,3 +58,13 @@ select -assert-count 1 t:URAM288
# see above for details # see above for details
select -assert-count 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i select -assert-count 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i
select -assert-none 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i select -assert-none 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i
# sp read or write for size 2048 x 144b
# the two URAM ports A and B are concatenated, with port A serving LSBs and port B serving MSBs
design -reset
read_verilog priority_memory.v
synth_xilinx -family xcup -top sp_read_or_write -noiopad
select -assert-count 1 t:URAM288
# we expect no more than 1 LUT2 to control the hardware enable ports
# see above for details about this command
select -assert-max 1 t:LUT* n:*blif* %d

View file

@ -1,3 +1,4 @@
libcache -verbose
libcache -enable busdef.lib libcache -enable busdef.lib
logger -expect log "Caching is disabled by default." 1 logger -expect log "Caching is disabled by default." 1
@ -14,8 +15,8 @@ logger -expect log "Caching data" 1
read_liberty -lib busdef.lib; design -reset read_liberty -lib busdef.lib; design -reset
logger -check-expected logger -check-expected
logger -expect log "Using caching data" 1 logger -expect log "Using cached data" 1
log Using caching data log Using cached data
read_liberty normal.lib; design -reset read_liberty normal.lib; design -reset
logger -check-expected logger -check-expected
@ -23,6 +24,13 @@ logger -expect log "Using cached data" 1
read_liberty -lib busdef.lib; design -reset read_liberty -lib busdef.lib; design -reset
logger -check-expected logger -check-expected
libcache -quiet
logger -expect log "Using cached data" 1
log Using cached data
read_liberty -lib busdef.lib; design -reset
logger -check-expected
libcache -verbose
libcache -purge busdef.lib libcache -purge busdef.lib
logger -expect log "Caching is disabled by default." 1 logger -expect log "Caching is disabled by default." 1

View file

@ -20,7 +20,11 @@ module top (
output wire [7:0] sshr_uu, output wire [7:0] sshr_uu,
output wire signed [7:0] sshr_us, output wire signed [7:0] sshr_us,
output wire [7:0] sshr_su, output wire [7:0] sshr_su,
output wire signed [7:0] sshr_ss output wire signed [7:0] sshr_ss,
output wire [7:0] shiftx_uu,
output wire signed [7:0] shiftx_us,
output wire [7:0] shiftx_su,
output wire signed [7:0] shiftx_ss
); );
assign shl_uu = in_u << 20; assign shl_uu = in_u << 20;
assign shl_us = in_u << 20; assign shl_us = in_u << 20;
@ -38,9 +42,20 @@ module top (
assign sshr_us = in_u >>> 20; assign sshr_us = in_u >>> 20;
assign sshr_su = in_s >>> 20; assign sshr_su = in_s >>> 20;
assign sshr_ss = in_s >>> 20; assign sshr_ss = in_s >>> 20;
wire [7:0] shamt = 20;
assign shiftx_uu = in_u[shamt +: 8];
assign shiftx_us = in_u[shamt +: 8];
assign shiftx_su = in_s[shamt +: 8];
assign shiftx_ss = in_s[shamt +: 8];
endmodule endmodule
EOT EOT
select -assert-count 4 t:$shl
select -assert-count 4 t:$shr
select -assert-count 4 t:$sshl
select -assert-count 4 t:$sshr
select -assert-count 4 t:$shiftx
equiv_opt opt_expr equiv_opt opt_expr
design -load postopt design -load postopt
@ -48,3 +63,98 @@ select -assert-none t:$shl
select -assert-none t:$shr select -assert-none t:$shr
select -assert-none t:$sshl select -assert-none t:$sshl
select -assert-none t:$sshr select -assert-none t:$sshr
select -assert-none t:$shiftx
design -reset
read_verilog <<EOT
module top (
input wire [3:0] in,
output wire [7:0] shl,
output wire [7:0] shr,
output wire [7:0] sshl,
output wire [7:0] sshr,
output wire [7:0] shiftx,
output wire [7:0] shl_s,
output wire [7:0] shr_s,
output wire [7:0] sshl_s,
output wire [7:0] sshr_s,
output wire [7:0] shiftx_s,
);
assign shl = in << 36'hfffffffff;
assign shr = in >> 36'hfffffffff;
assign sshl = in <<< 36'hfffffffff;
assign sshr = in >>> 36'hfffffffff;
assign shiftx = in[36'hfffffffff +: 8];
wire signed [35:0] shamt = 36'hfffffffff;
assign shl_s = in << shamt;
assign shr_s = in >> shamt;
assign sshl_s = in <<< shamt;
assign sshr_s = in >>> shamt;
assign shiftx_s = in[shamt +: 8];
endmodule
EOT
select -assert-count 2 t:$shl
select -assert-count 2 t:$shr
select -assert-count 2 t:$sshl
select -assert-count 2 t:$sshr
select -assert-count 1 t:$shiftx
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
select -assert-none t:$shiftx
design -reset
read_verilog <<EOT
module top (
input wire [3:0] in,
output wire [7:0] shl,
output wire [7:0] shr,
output wire [7:0] sshl,
output wire [7:0] sshr,
output wire [7:0] shiftx,
output wire [7:0] shl_s,
output wire [7:0] shr_s,
output wire [7:0] sshl_s,
output wire [7:0] sshr_s,
output wire [7:0] shiftx_s,
);
assign shl = in << 32'hffffffff;
assign shr = in >> 32'hffffffff;
assign sshl = in <<< 32'hffffffff;
assign sshr = in >>> 32'hffffffff;
assign shiftx = in[32'hffffffff +: 8];
wire signed [31:0] shamt = 32'hffffffff;
assign shl_s = in << shamt;
assign shr_s = in >> shamt;
assign sshl_s = in <<< shamt;
assign sshr_s = in >>> shamt;
assign shiftx_s = in[shamt +: 8];
endmodule
EOT
select -assert-count 2 t:$shl
select -assert-count 2 t:$shr
select -assert-count 2 t:$sshl
select -assert-count 2 t:$sshr
select -assert-count 1 t:$shiftx
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
select -assert-none t:$shiftx

1
tests/peepopt/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/*.log

343
tests/peepopt/muldiv_c.ys Normal file
View file

@ -0,0 +1,343 @@
log -header "Test simple positive case"
log -push
design -reset
read_verilog <<EOF
module top (
input wire [11:0] a,
output wire [11:0] y
);
assign y = (a * 16'd5140) / (257 * 2);
endmodule
EOF
check -assert
equiv_opt -assert peepopt
design -load postopt
select -assert-none t:$div
design -reset
log -pop
log -header "Test negative case where div is kept"
log -push
design -reset
read_verilog <<EOF
module top (
input wire signed [11:0] a,
output wire signed [31:0] y,
output wire probe
);
wire [28:0] tmp = (a * 16'd5140);
assign probe = tmp[28];
assign y = tmp[27:0] / (257 * 2);
endmodule
EOF
check -assert
equiv_opt -assert peepopt
design -load postopt
select -assert-any t:$div
design -reset
log -pop
log -header "Basic pattern transformed: (a * b) / c"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [7:0] mul;
assign mul = a * 4'sd6;
assign y = mul / 8'sd3;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 0 t:$div
design -reset
log -pop
log -header "Transformed on symmetry in multiplication"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [7:0] mul;
assign mul = 4'sd6 * a;
assign y = mul / 8'sd3;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 0 t:$div
design -reset
log -pop
log -header "Transformed on b == c"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [7:0] mul;
assign mul = a * 4'sd6;
assign y = mul / 8'sd6;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 0 t:$div
design -reset
log -pop
log -header "b negative, c positive"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [7:0] mul;
assign mul = a * -4'sd6;
assign y = mul / 8'sd3;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 0 t:$div
design -reset
log -pop
log -header "b positive, c negative"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [7:0] mul;
assign mul = a * 4'sd6;
assign y = mul / -8'sd3;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 0 t:$div
design -reset
log -pop
log -header "No transform when b not divisible by c"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [7:0] mul;
assign mul = a * 4'sd3;
assign y = mul / 8'sd2;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "No transform when product has a second fanout"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
output signed [7:0] z,
);
wire signed [7:0] mul;
assign mul = a * 4'sd6;
assign y = mul / 8'sd3;
assign z = mul;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "No transform when divisor is 0"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [7:0] mul;
assign mul = a * 4'sd4;
assign y = mul / 8'sd0;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "No transform when (a*b) output can overflow (dividers A input signed)"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [5:0] mul;
assign mul = a * 4'sd6;
assign y = mul / 8'sd3;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "No transform when (a*b) output can overflow (dividers A input signed)"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [6:0] mul;
assign mul = a * 4'sd6;
assign y = mul / 8'sd3;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "No transform when (a*b) output can overflow (dividers A input unsigned)"
log -push
read_verilog <<EOT
module top(
input [3:0] a,
output [7:0] y,
);
wire [4:0] mul;
assign mul = a * 4'd4;
assign y = mul / 8'd2;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "No transform when (a*b) output can overflow (dividers A input unsigned)"
log -push
read_verilog <<EOT
module top(
input [3:0] a,
output [7:0] y,
);
wire [6:0] mul;
assign mul = a * 4'd8;
assign y = mul / 8'd2;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "No transform when (a*b) and x/c fitting criteria but not connected (x != a*b)"
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
input signed [7:0] b,
output signed [7:0] y,
output signed [7:0] z,
);
assign y = a * 4'sd6;
assign z = b / 8'sd3;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "No transform when b only divisible by c if b misinterpreted as unsigned"
# b 1001 is -7 but 9 misinterpreted
# c 11 is 3
log -push
read_verilog <<EOT
module top(
input signed [3:0] a,
output signed [7:0] y,
);
wire signed [7:0] mul;
assign mul = a * 4'sb1001;
assign y = mul / 8'sb11;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 1 t:$div
design -reset
log -pop
log -header "Transform even if (a*b) result would overflow if dividers A input signedness is confused & (A input is unsigned)"
log -push
# Transform even if:
# (a*b) result would overflow if dividers A input signedness is confused
# (A input is unsigned)
read_verilog <<EOT
module top(
input [3:0] a,
output [7:0] y,
);
wire [7:0] mul;
assign mul = a * 4'd6;
assign y = mul / 8'd3;
endmodule
EOT
equiv_opt -assert peepopt
design -load postopt
select -assert-count 1 t:$mul
select -assert-count 0 t:$div
design -reset

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
for x in *.ys; do
echo "Running $x.."
../../yosys -ql ${x%.ys}.log $x
done

51
tests/sim/sim_cycles.ys Normal file
View file

@ -0,0 +1,51 @@
read_verilog dff.v
prep
# create fst with 20 clock cycles (41 samples, 202ns)
sim -clock clk -fst sim_cycles.fst -n 20
logger -expect-no-warnings
# final step is 41
logger -expect log "Co-simulating cycle 41" 2
logger -warn "Co-simulating cycle 42"
sim -clock clk -r sim_cycles.fst -scope dff -n 21 -sim-cmp
sim -clock clk -r sim_cycles.fst -scope dff -stop 202 -sim-cmp
logger -check-expected
# over limit stops at final step
logger -expect log "Co-simulating cycle 41" 2
sim -clock clk -r sim_cycles.fst -scope dff -n 30 -sim-cmp
# -stop warns for over limit
logger -nowarn "Stop time is after simulation file end time"
sim -clock clk -r sim_cycles.fst -scope dff -stop 300 -sim-cmp
logger -check-expected
# don't auto step last
logger -expect log "Co-simulating cycle 40" 2
logger -warn "Co-simulating cycle 41"
sim -clock clk -r sim_cycles.fst -scope dff -n 20 -sim-cmp
sim -clock clk -r sim_cycles.fst -scope dff -stop 200 -sim-cmp
logger -check-expected
# -n 10 == -stop 100
# should simulate up to 20 and not more
logger -expect log "Co-simulating cycle 20" 2
logger -warn "Co-simulating cycle 21"
sim -clock clk -r sim_cycles.fst -scope dff -n 10 -sim-cmp
sim -clock clk -r sim_cycles.fst -scope dff -stop 100 -sim-cmp
logger -check-expected
# -n 1 == -stop 10
logger -expect log "Co-simulating cycle 2" 2
logger -warn "Co-simulating cycle 3"
sim -clock clk -r sim_cycles.fst -scope dff -n 1 -sim-cmp
sim -clock clk -r sim_cycles.fst -scope dff -stop 10 -sim-cmp
logger -check-expected
# -n 0 == -stop 0
logger -expect log "Co-simulating cycle 0" 2
logger -warn "Co-simulating cycle 1"
sim -clock clk -r sim_cycles.fst -scope dff -n 0 -sim-cmp
sim -clock clk -r sim_cycles.fst -scope dff -stop 0 -sim-cmp
logger -check-expected

View file

@ -0,0 +1,13 @@
read_verilog -sv << EOF
typedef struct packed {
logic y;
logic x;
} Vec_2_B;
module top;
Vec_2_B two_dee;
wire foo = two_dee.x;
endmodule
EOF

View file

@ -0,0 +1,50 @@
read_verilog << EOT
module top(input a, b, output o);
wire c, d, e;
bb bb1 (.a (a), .b (b), .o (c));
sub_mod sub_inst (.a (a), .b (b), .o (e));
some_mod some_inst (.a (c), .b (d), .c (e), .o (o));
endmodule
(* blackbox *)
module bb #( parameter SOME_PARAM=0 ) (input a, b, output o);
endmodule
module sub_mod(input a, b, output o);
bb bb2 (.a (a), .b (b), .o (o));
endmodule
module some_mod(input a, b, c, output o);
assign o = a & (b | c);
endmodule
EOT
hierarchy -top top
design -stash hier
# removing cell
design -load hier
logger -expect log "Removing cell .*, making all cell outputs cutpoints" 1
cutpoint sub_mod/bb2
logger -check-expected
logger -werror "Removing cell .*, making all cell outputs cutpoints"
# removing wires
design -load hier
logger -expect log "Making wire .* a cutpoint" 1
cutpoint top/c
logger -check-expected
logger -werror "Making wire .* a cutpoint"
# removing output wires
design -load hier
logger -expect log "Making output wire .* a cutpoint" 1
cutpoint sub_mod/o
logger -check-expected
logger -werror "Making output wire .* a cutpoint"
# whole module optimization, doesn't do any of the previous
design -load hier
logger -expect log "Making all outputs of module .* cut points, removing module contents" 1
cutpoint sub_mod
logger -check-expected

View file

@ -0,0 +1,132 @@
# https://github.com/YosysHQ/yosys/issues/5157
read_verilog -sv <<EOT
module stmt_if_task (
output logic [7:0] out_val_m6,
input logic [7:0] in_val_m6,
input bit condition_m6
);
logic [7:0] var_m6;
task automatic update_conditional_m6(input bit cond, inout logic [7:0] val);
if (cond) begin
val++;
end else begin
--val;
end
endtask
always_comb begin
var_m6 = in_val_m6;
update_conditional_m6(condition_m6, var_m6);
out_val_m6 = var_m6;
end
wire [7:0] m6_inc = in_val_m6 + 1;
wire [7:0] m6_dec = in_val_m6 - 1;
always_comb assert(out_val_m6 == (condition_m6 ? m6_inc : m6_dec));
endmodule
EOT
prep
chformal -lower
sat -prove-asserts -verify
design -reset
read_verilog -sv <<EOT
module top (
output logic [7:0] out
);
task automatic set_to_5(inout logic [7:0] val);
val = 5;
endtask
always_comb begin
out = 0;
set_to_5(out);
end
always_comb assert(out == 5);
endmodule
EOT
prep
chformal -lower
sat -prove-asserts -verify
design -reset
read_verilog -sv <<EOT
module top (
output logic [7:0] a,
output logic [7:0] b,
output logic [7:0] c
);
task automatic modify(
input logic [7:0] t_in,
output logic [7:0] t_out,
inout logic [7:0] t_inout
);
assert(t_in == 5);
t_in = 6;
t_out = 7;
assert(t_inout == 8);
t_inout = 9;
endtask
always_comb begin
a = 5;
b = 4;
c = 8;
modify(a, b, c);
assert(a == 5);
assert(b == 7);
assert(c == 9);
end
endmodule
EOT
prep
chformal -lower
sat -prove-asserts -verify
design -reset
read_verilog -sv <<EOT
module top (
output logic [7:0] a,
output logic [7:0] b,
output logic [7:0] c
);
function logic [7:0] modify(
input logic [7:0] t_in,
output logic [7:0] t_out,
inout logic [7:0] t_inout
);
assert(t_in == 5);
t_in = 6;
t_out = 7;
assert(t_inout == 8);
t_inout = 9;
modify = 10;
endfunction
logic [7:0] result;
always_comb begin
a = 5;
b = 4;
c = 8;
result = modify(a, b, c);
assert(a == 5);
assert(b == 7);
assert(c == 9);
assert(result == 10);
end
endmodule
EOT
prep
chformal -lower
sat -prove-asserts -verify

68
tests/verilog/incdec.ys Normal file
View file

@ -0,0 +1,68 @@
# From https://github.com/YosysHQ/yosys/issues/5151
read_verilog -sv <<EOT
module expr_postsub_comb (
input logic [7:0] in_val_m2,
input logic [7:0] sub_val_m2,
output logic [7:0] out_diff_m2,
output logic [7:0] var_out_m2
);
logic [7:0] var_m2;
always_comb begin
var_m2 = in_val_m2;
out_diff_m2 = (var_m2--) - sub_val_m2;
var_out_m2 = var_m2;
end
always_comb assert(out_diff_m2 == in_val_m2 - sub_val_m2);
endmodule
EOT
prep
chformal -lower
sat -prove-asserts -verify
design -reset
read_verilog -sv <<EOT
module top(
input logic [7:0] a,
output logic [7:0] pre_inc,
output logic [7:0] pre_dec,
output logic [7:0] post_inc,
output logic [7:0] post_dec
);
logic [7:0] a_pre_inc, a_pre_dec, a_post_inc, a_post_dec;
always_comb begin
a_pre_inc = a;
a_pre_dec = a;
a_post_inc = a;
a_post_dec = a;
pre_inc = ++a_pre_inc;
pre_dec = --a_pre_dec;
post_inc = a_post_inc++;
post_dec = a_post_dec--;
end
wire [7:0] a_inc = a + 1;
wire [7:0] a_dec = a - 1;
always_comb begin
assert(a_pre_inc == a_inc);
assert(a_pre_dec == a_dec);
assert(a_post_inc == a_inc);
assert(a_post_dec == a_dec);
assert(pre_inc == a_inc);
assert(pre_dec == a_dec);
assert(post_inc == a);
assert(post_dec == a);
end
endmodule
EOT
prep
chformal -lower
sat -prove-asserts -verify

View file

@ -0,0 +1,41 @@
logger -expect log "SAT proof finished - no model found: SUCCESS" 1
read_verilog -sv <<EOF
// A somewhat contrived model of an encoder, relying on SystemVerilog's
// strong "if" semantics to guarantee priority encoder behaviour.
module encoder( input [ 2:0 ] x, output reg [ 1:0 ] y );
always_comb begin
y = 2'b00;
if( x[ 2 ] ) y = 2'b11;
else if( x[ 1 ] ) y = 2'b10;
else if( x[ 0 ] ) y = 2'b01;
end
endmodule
// Almost the same thing, but by using "priority if" we introduce
// "don't care" states, essentially conveying permission to synthesise
// a simple encoder instead.
module dut( input [ 2:0 ] x, output reg [ 1:0 ] y );
always_comb begin
y = 2'b00;
priority if( x[ 2 ] ) y = 2'b11;
else if( x[ 1 ] ) y = 2'b10;
else if( x[ 0 ] ) y = 2'b01;
end
endmodule
// A simple test bench to detect mismatches between the two encoders.
module compare_encoders( input [ 2:0 ] x, output ok );
wire [ 1:0 ] encout;
wire [ 1:0 ] dutout;
encoder e( x, encout );
dut d( x, dutout );
// The "priority if" above assumes $countones( x ) > 0.
assign ok = encout == dutout || !$countones( x );
endmodule
EOF
synth -flatten -top compare_encoders
sat -prove ok 1

30
tests/verilog/sbvector.ys Normal file
View file

@ -0,0 +1,30 @@
read_verilog <<EOT
module foo(
output o,
input [0:0] i1,
input i2
);
wire [0:0] w1 = i1 ^ i2;
wire w2 = ~i1;
assign o = w1 ^ w2;
endmodule
EOT
hierarchy
proc
select -assert-count 1 w:i1
select -assert-count 1 w:i1 a:single_bit_vector %i
select -assert-count 1 w:i2
select -assert-count 0 w:i2 a:single_bit_vector %i
select -assert-count 1 w:w1
select -assert-count 1 w:w1 a:single_bit_vector %i
select -assert-count 1 w:w2
select -assert-count 0 w:w2 a:single_bit_vector %i
write_verilog verilog_sbvector.out
!grep -qF 'wire [0:0] i1;' verilog_sbvector.out
!grep -qF 'input [0:0] i1;' verilog_sbvector.out
!grep -qF 'wire i2;' verilog_sbvector.out
!grep -qF 'input i2;' verilog_sbvector.out
!grep -qF 'wire [0:0] w1;' verilog_sbvector.out
!grep -qF 'wire w2;' verilog_sbvector.out

View file

@ -0,0 +1,41 @@
logger -expect log "SAT proof finished - no model found: SUCCESS" 1
read_verilog -sv <<EOF
// A somewhat contrived model of an encoder, relying on SystemVerilog's
// strong "if" semantics to guarantee priority encoder behaviour.
module encoder( input [ 2:0 ] x, output reg [ 1:0 ] y );
always_comb begin
y = 2'b00;
if( x[ 2 ] ) y = 2'b11;
else if( x[ 1 ] ) y = 2'b10;
else if( x[ 0 ] ) y = 2'b01;
end
endmodule
// Almost the same thing, but by using "unique0 if" we introduce
// "don't care" states, essentially conveying permission to synthesise
// a simple encoder instead.
module dut( input [ 2:0 ] x, output reg [ 1:0 ] y );
always_comb begin
y = 2'b00;
unique0 if( x[ 2 ] ) y = 2'b11;
else if( x[ 1 ] ) y = 2'b10;
else if( x[ 0 ] ) y = 2'b01;
end
endmodule
// A simple test bench to detect mismatches between the two encoders.
module compare_encoders( input [ 2:0 ] x, output ok );
wire [ 1:0 ] encout;
wire [ 1:0 ] dutout;
encoder e( x, encout );
dut d( x, dutout );
// The "unique0 if" above assumes $onehot0( x ).
assign ok = encout == dutout || !$onehot0( x );
endmodule
EOF
synth -flatten -top compare_encoders
sat -prove ok 1

View file

@ -0,0 +1,10 @@
read_verilog -sv <<EOF
module top( input[2:0] a );
always_comb begin
// example from 1800-2012 12.4.2
unique if ((a==0) || (a==1)) $display("0 or 1");
else if (a == 2) $display("2");
else if (a == 4) $display("4");
end
endmodule
EOF

View file

@ -0,0 +1,11 @@
logger -expect error "unique keyword cannot be used for 'else if' branch" 1
read_verilog -sv <<EOF
module top( input[2:0] a );
always_comb begin
// invalid example from 1800-2012 12.4.2
unique if ((a==0) || (a==1)) $display("0 or 1");
else unique if (a == 2) $display("2");
else if (a == 4) $display("4");
end
endmodule
EOF

View file

@ -0,0 +1,12 @@
read_verilog -sv <<EOF
module top( input[2:0] a );
always_comb begin
// example from 1800-2012 12.4.2
unique if ((a==0) || (a==1)) $display("0 or 1");
else begin
unique if (a == 2) $display("2");
else if (a == 4) $display("4");
end
end
endmodule
EOF

Some files were not shown because too many files have changed in this diff Show more