mirror of
https://github.com/YosysHQ/yosys
synced 2026-06-25 02:00:33 +00:00
Merge branch 'YosysHQ:main' into master
This commit is contained in:
commit
e793a1952e
101 changed files with 7356 additions and 5889 deletions
18
CHANGELOG
18
CHANGELOG
|
|
@ -2,9 +2,25 @@
|
|||
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
|
||||
--------------------------
|
||||
* New commands and options
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ passes/opt/opt_lut.cc @whitequark
|
|||
passes/techmap/abc9*.cc @eddiehung @Ravenslofty
|
||||
backends/aiger/xaiger.cc @eddiehung
|
||||
docs/ @KrystalDelusion
|
||||
docs/source/using_yosys/synthesis/abc.rst @KrystalDelusion @Ravenslofty
|
||||
.github/workflows/*.yml @mmicko
|
||||
|
||||
## External Contributors
|
||||
|
|
|
|||
16
Makefile
16
Makefile
|
|
@ -160,7 +160,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.53+3
|
||||
YOSYS_VER := 0.54+0
|
||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
|
||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
|
||||
|
|
@ -183,7 +183,7 @@ endif
|
|||
OBJS = kernel/version_$(GIT_REV).o
|
||||
|
||||
bumpversion:
|
||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 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)
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ endif
|
|||
include Makefile.conf
|
||||
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)
|
||||
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)"")
|
||||
|
|
@ -455,6 +455,7 @@ endif
|
|||
|
||||
ifeq ($(ENABLE_DEBUG),1)
|
||||
CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS))
|
||||
STRIP :=
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_ABC),1)
|
||||
|
|
@ -894,6 +895,7 @@ SH_TEST_DIRS += tests/bram
|
|||
SH_TEST_DIRS += tests/svinterfaces
|
||||
SH_TEST_DIRS += tests/xprop
|
||||
SH_TEST_DIRS += tests/select
|
||||
SH_TEST_DIRS += tests/peepopt
|
||||
SH_TEST_DIRS += tests/proc
|
||||
SH_TEST_DIRS += tests/blif
|
||||
SH_TEST_DIRS += tests/arch
|
||||
|
|
@ -982,20 +984,20 @@ install: $(TARGETS) $(EXTRA_TARGETS)
|
|||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR)
|
||||
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
|
||||
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
|
||||
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
|
||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
|
||||
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
|
||||
ifeq ($(ENABLE_LIBYOSYS),1)
|
||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
|
||||
$(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)
|
||||
$(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
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ struct AigerWriter
|
|||
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> unused_bits;
|
||||
|
|
@ -152,6 +152,37 @@ struct AigerWriter
|
|||
if (wire->port_input)
|
||||
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())
|
||||
{
|
||||
if (wire->attributes.count(ID::init)) {
|
||||
|
|
@ -167,25 +198,13 @@ struct AigerWriter
|
|||
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);
|
||||
}
|
||||
if (bit.wire == nullptr)
|
||||
continue;
|
||||
if (wire->port_input || wire->port_output)
|
||||
continue;
|
||||
}
|
||||
|
||||
undriven_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) {
|
||||
|
|
@ -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())
|
||||
{
|
||||
if (cell->type == ID($_NOT_))
|
||||
|
|
@ -343,8 +356,11 @@ struct AigerWriter
|
|||
}
|
||||
|
||||
init_map.sort();
|
||||
input_bits.sort();
|
||||
output_bits.sort();
|
||||
// we are relying here on unsorted pools iterating last-in-first-out
|
||||
if (!no_sort) {
|
||||
input_bits.sort();
|
||||
output_bits.sort();
|
||||
}
|
||||
not_map.sort();
|
||||
ff_map.sort();
|
||||
and_map.sort();
|
||||
|
|
@ -662,8 +678,7 @@ struct AigerWriter
|
|||
f << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
f << stringf("c\nGenerated by %s\n", yosys_version_str);
|
||||
f << stringf("c\nGenerated by %s\n", yosys_maybe_version());
|
||||
}
|
||||
|
||||
void write_map(std::ostream &f, bool verbose_map, bool no_startoffset)
|
||||
|
|
@ -698,7 +713,7 @@ struct AigerWriter
|
|||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
@ -746,7 +761,7 @@ struct AigerWriter
|
|||
{
|
||||
json.begin_object();
|
||||
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("input_count", aig_i);
|
||||
|
|
@ -902,6 +917,9 @@ struct AigerBackend : public Backend {
|
|||
log(" -symbols\n");
|
||||
log(" include a symbol table in the generated AIGER file\n");
|
||||
log("\n");
|
||||
log(" -no-sort\n");
|
||||
log(" don't sort input/output ports\n");
|
||||
log("\n");
|
||||
log(" -map <filename>\n");
|
||||
log(" write an extra file with port and latch symbols\n");
|
||||
log("\n");
|
||||
|
|
@ -926,6 +944,7 @@ struct AigerBackend : public Backend {
|
|||
bool zinit_mode = false;
|
||||
bool miter_mode = false;
|
||||
bool symbols_mode = false;
|
||||
bool no_sort = false;
|
||||
bool verbose_map = false;
|
||||
bool imode = false;
|
||||
bool omode = false;
|
||||
|
|
@ -956,6 +975,10 @@ struct AigerBackend : public Backend {
|
|||
symbols_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-no-sort") {
|
||||
no_sort = true;
|
||||
continue;
|
||||
}
|
||||
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
|
||||
map_filename = args[++argidx];
|
||||
continue;
|
||||
|
|
@ -1009,7 +1032,7 @@ struct AigerBackend : public Backend {
|
|||
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));
|
||||
|
||||
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);
|
||||
|
||||
if (!map_filename.empty()) {
|
||||
|
|
|
|||
|
|
@ -671,7 +671,7 @@ struct XAigerWriter
|
|||
//f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
|
||||
//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_wires", aig_map.size());
|
||||
|
|
|
|||
|
|
@ -649,7 +649,7 @@ struct BlifBackend : public Backend {
|
|||
if (module->get_bool_attribute(ID::top))
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -1499,7 +1499,7 @@ struct BtorWorker
|
|||
{
|
||||
ywmap_json.begin_object();
|
||||
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.begin_array();
|
||||
|
|
@ -1613,7 +1613,7 @@ struct BtorBackend : public Backend {
|
|||
log_cmd_error("No top module found.\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);
|
||||
|
||||
|
|
|
|||
|
|
@ -2429,8 +2429,6 @@ struct CxxrtlWorker {
|
|||
inc_indent();
|
||||
for (auto wire : module->wires()) {
|
||||
const auto &debug_wire_type = debug_wire_types[wire];
|
||||
if (!wire->name.isPublic())
|
||||
continue;
|
||||
count_public_wires++;
|
||||
switch (debug_wire_type.type) {
|
||||
case WireType::BUFFERED:
|
||||
|
|
@ -2438,6 +2436,9 @@ struct CxxrtlWorker {
|
|||
// Member wire
|
||||
std::vector<std::string> flags;
|
||||
|
||||
if (!wire->name.isPublic())
|
||||
flags.push_back("GENERATED");
|
||||
|
||||
if (wire->port_input && wire->port_output)
|
||||
flags.push_back("INOUT");
|
||||
else if (wire->port_output)
|
||||
|
|
|
|||
|
|
@ -200,6 +200,10 @@ enum cxxrtl_flag {
|
|||
// node, such as inputs and dangling wires.
|
||||
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.
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1294,6 +1294,7 @@ struct debug_item : ::cxxrtl_object {
|
|||
DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC,
|
||||
DRIVEN_COMB = CXXRTL_DRIVEN_COMB,
|
||||
UNDRIVEN = CXXRTL_UNDRIVEN,
|
||||
GENERATED = CXXRTL_GENERATED,
|
||||
};
|
||||
|
||||
debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {}
|
||||
|
|
|
|||
|
|
@ -231,7 +231,8 @@ struct EdifBackend : public Backend {
|
|||
*f << stringf(" (edifVersion 2 0 0)\n");
|
||||
*f << stringf(" (edifLevel 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(" (edifLevel 0)\n");
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ struct JnyWriter
|
|||
|
||||
f << "{\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 << " \"invocation\": \"" << escape_string(invk) << "\",\n";
|
||||
f << " \"features\": [";
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ struct JsonWriter
|
|||
design->sort();
|
||||
|
||||
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");
|
||||
vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
|
||||
bool first_module = true;
|
||||
|
|
|
|||
|
|
@ -459,7 +459,8 @@ struct RTLILBackend : public Backend {
|
|||
design->sort();
|
||||
|
||||
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);
|
||||
}
|
||||
} RTLILBackend;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
*f << stringf("; yosys-smt2-nobv\n");
|
||||
|
|
|
|||
|
|
@ -797,7 +797,7 @@ struct SmvBackend : public Backend {
|
|||
if (module == nullptr)
|
||||
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));
|
||||
SmvWorker worker(module, verbose, *f);
|
||||
|
|
@ -816,7 +816,7 @@ struct SmvBackend : public Backend {
|
|||
|
||||
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) {
|
||||
log("Creating SMV representation of module %s.\n", log_id(module));
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ struct SpiceBackend : public Backend {
|
|||
if (module->get_bool_attribute(ID::top))
|
||||
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");
|
||||
|
||||
for (auto module : design->modules())
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString,
|
|||
if (attr2comment)
|
||||
as_comment = true;
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
if (it->first == ID::single_bit_vector) 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(" = ");
|
||||
|
|
@ -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);
|
||||
else
|
||||
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)
|
||||
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();
|
||||
|
||||
*f << stringf("/* Generated by %s */\n", yosys_version_str);
|
||||
*f << stringf("/* Generated by %s */\n", yosys_maybe_version());
|
||||
|
||||
for (auto module : design->modules()) {
|
||||
if (module->get_blackbox_attribute() != blackboxes)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ circuits.
|
|||
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
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
for specialised tasks.
|
||||
|
||||
|
|
@ -572,7 +572,7 @@ of lexical tokens given in :numref:`Tab. %s <tab:Basics_tokens>`.
|
|||
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
|
||||
that should match the individual tokens.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import os
|
|||
project = 'YosysHQ Yosys'
|
||||
author = 'YosysHQ GmbH'
|
||||
copyright ='2025 YosysHQ GmbH'
|
||||
yosys_ver = "0.53"
|
||||
yosys_ver = "0.54"
|
||||
|
||||
# select HTML theme
|
||||
html_theme = 'furo-ys'
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
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'
|
||||
internal representation of the decision-trees and synchronization events
|
||||
|
|
|
|||
|
|
@ -176,5 +176,6 @@ implemented as whiteboxes too.
|
|||
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
|
||||
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.
|
||||
|
||||
|
|
|
|||
|
|
@ -626,7 +626,7 @@ pass and the passes it launches:
|
|||
| This pass replaces the ``RTLIL::SyncRule``\ s to d-type flip-flops (with
|
||||
asynchronous resets if necessary).
|
||||
|
||||
- | `proc_dff`
|
||||
- | `proc_memwr`
|
||||
| This pass replaces the ``RTLIL::MemWriteAction``\ s with `$memwr` cells.
|
||||
|
||||
- | `proc_clean`
|
||||
|
|
|
|||
|
|
@ -375,3 +375,9 @@ from SystemVerilog:
|
|||
ports are inputs or outputs 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.)
|
||||
|
|
|
|||
|
|
@ -1446,6 +1446,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
wire->port_input = is_input;
|
||||
wire->port_output = is_output;
|
||||
wire->upto = range_swapped;
|
||||
|
||||
wire->is_signed = is_signed;
|
||||
|
||||
for (auto &attr : attributes) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
basic_prep = true;
|
||||
is_custom_type = false;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -1932,6 +1933,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
|||
// Prepare replacement node.
|
||||
newNode = template_node->clone();
|
||||
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->is_input = is_input;
|
||||
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);
|
||||
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 {
|
||||
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_left = 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;
|
||||
continue;
|
||||
}
|
||||
|
||||
AstNode *wire_id = new AstNode(AST_IDENTIFIER);
|
||||
wire_id->str = wire->str;
|
||||
AstNode *assign = child->is_input ?
|
||||
new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
|
||||
new AstNode(AST_ASSIGN_EQ, arg, wire_id);
|
||||
assign->children[0]->was_checked = true;
|
||||
if (child->is_input)
|
||||
|
||||
if (child->is_input) {
|
||||
AstNode *assign = new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg->clone());
|
||||
assign->children[0]->was_checked = true;
|
||||
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);
|
||||
}
|
||||
|
||||
delete arg;
|
||||
delete wire_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1557,6 +1557,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
|
||||
wire->upto = portbus->IsUp();
|
||||
import_attributes(wire->attributes, portbus, nl, portbus->Size());
|
||||
if (portbus->Size() == 1)
|
||||
wire->set_bool_attribute(ID::single_bit_vector);
|
||||
SetIter si ;
|
||||
Port *port ;
|
||||
FOREACH_PORT_OF_PORTBUS(portbus, si, port) {
|
||||
|
|
@ -1755,6 +1757,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
|||
break;
|
||||
}
|
||||
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));
|
||||
bool initval_valid = false;
|
||||
|
|
@ -3485,6 +3489,14 @@ struct VerificPass : public Pass {
|
|||
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
|
||||
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
|
||||
RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ;
|
||||
#endif
|
||||
|
|
@ -3543,6 +3555,9 @@ struct VerificPass : public Pass {
|
|||
} else if (Strings::compare(args[argidx].c_str(), "warnings")) {
|
||||
Message::SetAllMessageType(VERIFIC_WARNING, new_type);
|
||||
} 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);
|
||||
} else if (Strings::compare(args[argidx].c_str(), "comments")) {
|
||||
Message::SetAllMessageType(VERIFIC_COMMENT, new_type);
|
||||
|
|
|
|||
|
|
@ -336,7 +336,8 @@ static AstNode *addIncOrDecExpr(AstNode *lhs, dict<IdString, AstNode*> *attr, AS
|
|||
log_assert(stmt->type == AST_ASSIGN_EQ);
|
||||
AstNode *expr = stmt->children[0]->clone();
|
||||
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);
|
||||
}
|
||||
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_signedness_default_signed opt_signedness_default_unsigned
|
||||
%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_node_type> asgn_binop inc_or_dec_op
|
||||
%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:
|
||||
|
|
@ -2871,7 +2872,7 @@ behavioral_stmt:
|
|||
ast_stack.pop_back();
|
||||
ast_stack.pop_back();
|
||||
} |
|
||||
attr TOK_IF '(' expr ')' {
|
||||
if_attr TOK_IF '(' expr ')' {
|
||||
AstNode *node = new AstNode(AST_CASE);
|
||||
AstNode *block = new AstNode(AST_BLOCK);
|
||||
AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block);
|
||||
|
|
@ -2901,6 +2902,29 @@ behavioral_stmt:
|
|||
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:
|
||||
attr {
|
||||
$$ = $1;
|
||||
|
|
@ -2948,6 +2972,7 @@ behavioral_stmt_list:
|
|||
optional_else:
|
||||
TOK_ELSE {
|
||||
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);
|
||||
SET_AST_NODE_LOC(cond, @1, @1);
|
||||
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ X(parameter)
|
|||
X(PORTID)
|
||||
X(PRIORITY)
|
||||
X(PRIORITY_MASK)
|
||||
X(promoted_if)
|
||||
X(Q)
|
||||
X(R)
|
||||
X(ram_block)
|
||||
|
|
@ -184,6 +185,7 @@ X(romstyle)
|
|||
X(S)
|
||||
X(SET)
|
||||
X(SET_POLARITY)
|
||||
X(single_bit_vector)
|
||||
X(SIZE)
|
||||
X(SRC)
|
||||
X(src)
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ int main(int argc, char **argv)
|
|||
options.add_options("logging")
|
||||
("Q", "suppress printing of banner (copyright, disclaimer, version)")
|
||||
("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. " \
|
||||
"Use this option twice to also quiet warning messages")
|
||||
("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("Q")) print_banner = false;
|
||||
if (result.count("T")) print_stats = false;
|
||||
if (result.count("no-version")) yosys_write_versions = false;
|
||||
if (result.count("V")) {
|
||||
std::cout << yosys_version_str << std::endl;
|
||||
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,
|
||||
ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec, meminfo.c_str());
|
||||
#endif
|
||||
log("%s\n", yosys_version_str);
|
||||
log("%s\n", yosys_maybe_version());
|
||||
|
||||
int64_t total_ns = 0;
|
||||
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));
|
||||
|
||||
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, " \"passes\": {");
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */)
|
||||
{
|
||||
if (pnt_time > end_time || !pnt_value) return;
|
||||
if (curr_cycle > last_cycle) return;
|
||||
// if we are past the timestamp
|
||||
bool is_clock = false;
|
||||
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 (all_samples) {
|
||||
callback(last_time);
|
||||
curr_cycle++;
|
||||
last_time = pnt_time;
|
||||
} else {
|
||||
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];
|
||||
if ((prev!="1" && val=="1") || (prev!="0" && val=="0")) {
|
||||
callback(last_time);
|
||||
curr_cycle++;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
callback = cb;
|
||||
start_time = start;
|
||||
end_time = end;
|
||||
curr_cycle = 0;
|
||||
last_cycle = end_cycle;
|
||||
last_data.clear();
|
||||
last_time = start_time;
|
||||
past_data.clear();
|
||||
|
|
@ -256,12 +261,16 @@ void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t sta
|
|||
fstReaderSetUnlimitedTimeRange(ctx);
|
||||
fstReaderSetFacProcessMaskAll(ctx);
|
||||
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;
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class FstData
|
|||
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 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);
|
||||
fstHandle getHandle(std::string name);
|
||||
|
|
@ -73,6 +73,8 @@ private:
|
|||
std::string timescale_str;
|
||||
uint64_t start_time;
|
||||
uint64_t end_time;
|
||||
unsigned int last_cycle;
|
||||
unsigned int curr_cycle;
|
||||
CallbackFunction callback;
|
||||
std::vector<fstHandle> clk_signals;
|
||||
bool all_samples;
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ gzip_istream::ibuf::~ibuf() {
|
|||
// returns the original ifstream, rewound to the start.
|
||||
// Never returns nullptr or failed state istream*
|
||||
std::istream* uncompressed(const std::string filename, std::ios_base::openmode mode) {
|
||||
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();
|
||||
f->open(filename, mode);
|
||||
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]));
|
||||
gzip_istream* s = new gzip_istream();
|
||||
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;
|
||||
#else
|
||||
log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
|
|
|||
25
kernel/io.cc
25
kernel/io.cc
|
|
@ -247,11 +247,19 @@ std::string make_temp_dir(std::string template_str)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool check_directory_exists(const std::string& dirname)
|
||||
bool check_is_directory(const std::string& dirname)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
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;
|
||||
}
|
||||
|
|
@ -267,17 +275,26 @@ bool check_directory_exists(const std::string& dirname)
|
|||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
|
|
|||
17
kernel/io.h
17
kernel/io.h
|
|
@ -64,6 +64,23 @@ inline std::string stringf(const char *fmt, ...)
|
|||
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
|
||||
|
||||
#endif // YOSYS_IO_H
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_d
|
|||
#else
|
||||
static inline bool ys_debug(int = 0) { return false; }
|
||||
#endif
|
||||
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() {
|
||||
if (log_debug_suppressed && !log_make_debug) {
|
||||
|
|
|
|||
|
|
@ -860,7 +860,7 @@ struct HelpPass : public Pass {
|
|||
// init json
|
||||
json.begin_object();
|
||||
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, pair<SimHelper, CellType>> cells;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ struct Pass
|
|||
{
|
||||
std::string pass_name, short_help;
|
||||
Pass(std::string name, std::string short_help = "** document me **");
|
||||
// Prefer overriding 'Pass::on_shutdown()' if possible
|
||||
virtual ~Pass();
|
||||
|
||||
virtual void help();
|
||||
|
|
|
|||
|
|
@ -380,6 +380,49 @@ int RTLIL::Const::as_int(bool is_signed) const
|
|||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
auto size = get_min_size(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;
|
||||
return try_as_int(is_signed);
|
||||
}
|
||||
|
||||
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
|
||||
// cases where a cell has a blackbox attribute since
|
||||
// that is deprecated
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
cover("kernel.rtlil.sigspec.as_string");
|
||||
|
|
|
|||
|
|
@ -753,7 +753,26 @@ public:
|
|||
|
||||
std::vector<RTLIL::State>& bits();
|
||||
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;
|
||||
|
||||
// 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;
|
||||
static Const from_string(const std::string &str);
|
||||
std::vector<RTLIL::State> to_bits() const;
|
||||
|
|
@ -1130,7 +1149,27 @@ public:
|
|||
bool is_onehot(int *pos = nullptr) 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;
|
||||
|
||||
// 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;
|
||||
RTLIL::Const as_const() const;
|
||||
RTLIL::Wire *as_wire() const;
|
||||
|
|
@ -1182,7 +1221,7 @@ struct RTLIL::Selection
|
|||
bool boxes = false,
|
||||
// the design to select from
|
||||
RTLIL::Design *design = nullptr
|
||||
) :
|
||||
) :
|
||||
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
|
||||
|
|
|
|||
|
|
@ -81,6 +81,14 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
int autoidx = 1;
|
||||
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;
|
||||
CellTypes yosys_celltypes;
|
||||
|
||||
|
|
@ -144,7 +152,7 @@ void yosys_banner()
|
|||
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(" \\----------------------------------------------------------------------------/\n");
|
||||
log(" %s\n", yosys_version_str);
|
||||
log(" %s\n", yosys_maybe_version());
|
||||
}
|
||||
|
||||
#if !defined(YOSYS_DISABLE_SPAWN)
|
||||
|
|
@ -548,29 +556,29 @@ void init_share_dirname()
|
|||
std::string proc_self_path = proc_self_dirname();
|
||||
# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR)
|
||||
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;
|
||||
return;
|
||||
}
|
||||
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;
|
||||
return;
|
||||
}
|
||||
# else
|
||||
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;
|
||||
return;
|
||||
}
|
||||
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;
|
||||
return;
|
||||
}
|
||||
# ifdef 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;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ extern std::set<std::string> yosys_input_files, yosys_output_files;
|
|||
|
||||
// from kernel/version_*.o (cc source generated from Makefile)
|
||||
extern const char *yosys_version_str;
|
||||
const char* yosys_maybe_version();
|
||||
|
||||
// from passes/cmds/design.cc
|
||||
extern std::map<std::string, RTLIL::Design*> saved_designs;
|
||||
|
|
|
|||
|
|
@ -252,28 +252,12 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); }
|
|||
void yosys_banner();
|
||||
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(); }
|
||||
inline int GetSize(RTLIL::Wire *wire);
|
||||
|
||||
extern int autoidx;
|
||||
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_suffix(std::string file, int line, std::string func, std::string suffix);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
--- fstapi.cc
|
||||
+++ fstapi.cc
|
||||
@@ -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);
|
||||
- xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
|
||||
+ /*
|
||||
+ * Yosys patch: Fix double endian check for i386 targets built in modern gcc
|
||||
+ */
|
||||
+ xc->double_endian_match = (dcheck == (double)FST_DOUBLE_ENDTEST);
|
||||
if(!xc->double_endian_match)
|
||||
{
|
||||
union {
|
||||
fstFread(&dcheck, 8, 1, xc->f);
|
||||
- xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
|
||||
+ /*
|
||||
+ * Yosys patch: Fix double endian check for i386 targets built in modern gcc
|
||||
+ */
|
||||
+ xc->double_endian_match = (dcheck == (double)FST_DOUBLE_ENDTEST);
|
||||
if (!xc->double_endian_match) {
|
||||
union
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@
|
|||
@@ -137,7 +137,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
-#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
+#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(_MSC_VER) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
|
||||
- defined(__NetBSD__)
|
||||
+ defined(__NetBSD__) || defined(_MSC_VER)
|
||||
#define FST_UNBUFFERED_IO
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
-#include <zlib.h>
|
||||
#include <inttypes.h>
|
||||
#if defined(_MSC_VER)
|
||||
+ #include "libs/zlib/zlib.h"
|
||||
#include "fst_win_unistd.h"
|
||||
+#include "libs/zlib/zlib.h"
|
||||
#include "fst_win_unistd.h"
|
||||
#else
|
||||
+ #include <zlib.h>
|
||||
#include <unistd.h>
|
||||
+#include <zlib.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
--- fstapi.cc
|
||||
+++ fstapi.cc
|
||||
@@ -6072,6 +6072,7 @@ for(;;)
|
||||
}
|
||||
}
|
||||
|
||||
wx_len = snprintf(wx_buf, 32, "r%.16g", d);
|
||||
+ if (wx_len > 32 || wx_len < 0) wx_len = 32;
|
||||
fstWritex(xc, wx_buf, wx_len);
|
||||
}
|
||||
}
|
||||
wx_len = snprintf(wx_buf, 32, "r%.16g", d);
|
||||
+ if (wx_len > 32 || wx_len < 0) wx_len = 32;
|
||||
fstWritex(xc, wx_buf, wx_len);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
mv config.h config.h.bak
|
||||
rm -f *.txt *.cc *.h
|
||||
git clone --depth 1 https://github.com/gtkwave/gtkwave fst_upstream
|
||||
rm fst_upstream/lib/libfst/CMakeLists.txt
|
||||
mv fst_upstream/lib/libfst/*.{h,c,txt} .
|
||||
git clone --depth 1 https://github.com/gtkwave/libfst fst_upstream
|
||||
rm fst_upstream/src/meson.build
|
||||
mv fst_upstream/src/*.{h,c} .
|
||||
mv fst_upstream/doc/block_format.txt .
|
||||
rm -rf fst_upstream
|
||||
|
||||
for src in *.c; do
|
||||
|
|
|
|||
10227
libs/fst/fstapi.cc
10227
libs/fst/fstapi.cc
File diff suppressed because it is too large
Load diff
|
|
@ -26,7 +26,8 @@
|
|||
#define FST_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
|
@ -35,430 +36,510 @@ extern "C" {
|
|||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#if defined(_MSC_VER)
|
||||
#include "libs/zlib/zlib.h"
|
||||
#include "fst_win_unistd.h"
|
||||
#include "libs/zlib/zlib.h"
|
||||
#include "fst_win_unistd.h"
|
||||
#else
|
||||
#include <zlib.h>
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#define FST_RDLOAD "FSTLOAD | "
|
||||
|
||||
typedef uint32_t fstHandle;
|
||||
typedef uint32_t fstEnumHandle;
|
||||
|
||||
enum fstWriterPackType {
|
||||
FST_WR_PT_ZLIB = 0,
|
||||
FST_WR_PT_FASTLZ = 1,
|
||||
FST_WR_PT_LZ4 = 2
|
||||
enum fstWriterPackType
|
||||
{
|
||||
FST_WR_PT_ZLIB = 0,
|
||||
FST_WR_PT_FASTLZ = 1,
|
||||
FST_WR_PT_LZ4 = 2
|
||||
};
|
||||
|
||||
enum fstFileType {
|
||||
FST_FT_MIN = 0,
|
||||
enum fstFileType
|
||||
{
|
||||
FST_FT_MIN = 0,
|
||||
|
||||
FST_FT_VERILOG = 0,
|
||||
FST_FT_VHDL = 1,
|
||||
FST_FT_VERILOG_VHDL = 2,
|
||||
FST_FT_VERILOG = 0,
|
||||
FST_FT_VHDL = 1,
|
||||
FST_FT_VERILOG_VHDL = 2,
|
||||
|
||||
FST_FT_MAX = 2
|
||||
FST_FT_MAX = 2
|
||||
};
|
||||
|
||||
enum fstBlockType {
|
||||
FST_BL_HDR = 0,
|
||||
FST_BL_VCDATA = 1,
|
||||
FST_BL_BLACKOUT = 2,
|
||||
FST_BL_GEOM = 3,
|
||||
FST_BL_HIER = 4,
|
||||
FST_BL_VCDATA_DYN_ALIAS = 5,
|
||||
FST_BL_HIER_LZ4 = 6,
|
||||
FST_BL_HIER_LZ4DUO = 7,
|
||||
FST_BL_VCDATA_DYN_ALIAS2 = 8,
|
||||
enum fstBlockType
|
||||
{
|
||||
FST_BL_HDR = 0,
|
||||
FST_BL_VCDATA = 1,
|
||||
FST_BL_BLACKOUT = 2,
|
||||
FST_BL_GEOM = 3,
|
||||
FST_BL_HIER = 4,
|
||||
FST_BL_VCDATA_DYN_ALIAS = 5,
|
||||
FST_BL_HIER_LZ4 = 6,
|
||||
FST_BL_HIER_LZ4DUO = 7,
|
||||
FST_BL_VCDATA_DYN_ALIAS2 = 8,
|
||||
|
||||
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
|
||||
FST_BL_SKIP = 255 /* used while block is being written */
|
||||
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
|
||||
FST_BL_SKIP = 255 /* used while block is being written */
|
||||
};
|
||||
|
||||
enum fstScopeType {
|
||||
FST_ST_MIN = 0,
|
||||
enum fstScopeType
|
||||
{
|
||||
FST_ST_MIN = 0,
|
||||
|
||||
FST_ST_VCD_MODULE = 0,
|
||||
FST_ST_VCD_TASK = 1,
|
||||
FST_ST_VCD_FUNCTION = 2,
|
||||
FST_ST_VCD_BEGIN = 3,
|
||||
FST_ST_VCD_FORK = 4,
|
||||
FST_ST_VCD_GENERATE = 5,
|
||||
FST_ST_VCD_STRUCT = 6,
|
||||
FST_ST_VCD_UNION = 7,
|
||||
FST_ST_VCD_CLASS = 8,
|
||||
FST_ST_VCD_INTERFACE = 9,
|
||||
FST_ST_VCD_PACKAGE = 10,
|
||||
FST_ST_VCD_PROGRAM = 11,
|
||||
FST_ST_VCD_MODULE = 0,
|
||||
FST_ST_VCD_TASK = 1,
|
||||
FST_ST_VCD_FUNCTION = 2,
|
||||
FST_ST_VCD_BEGIN = 3,
|
||||
FST_ST_VCD_FORK = 4,
|
||||
FST_ST_VCD_GENERATE = 5,
|
||||
FST_ST_VCD_STRUCT = 6,
|
||||
FST_ST_VCD_UNION = 7,
|
||||
FST_ST_VCD_CLASS = 8,
|
||||
FST_ST_VCD_INTERFACE = 9,
|
||||
FST_ST_VCD_PACKAGE = 10,
|
||||
FST_ST_VCD_PROGRAM = 11,
|
||||
|
||||
FST_ST_VHDL_ARCHITECTURE = 12,
|
||||
FST_ST_VHDL_PROCEDURE = 13,
|
||||
FST_ST_VHDL_FUNCTION = 14,
|
||||
FST_ST_VHDL_RECORD = 15,
|
||||
FST_ST_VHDL_PROCESS = 16,
|
||||
FST_ST_VHDL_BLOCK = 17,
|
||||
FST_ST_VHDL_FOR_GENERATE = 18,
|
||||
FST_ST_VHDL_IF_GENERATE = 19,
|
||||
FST_ST_VHDL_GENERATE = 20,
|
||||
FST_ST_VHDL_PACKAGE = 21,
|
||||
FST_ST_VHDL_ARCHITECTURE = 12,
|
||||
FST_ST_VHDL_PROCEDURE = 13,
|
||||
FST_ST_VHDL_FUNCTION = 14,
|
||||
FST_ST_VHDL_RECORD = 15,
|
||||
FST_ST_VHDL_PROCESS = 16,
|
||||
FST_ST_VHDL_BLOCK = 17,
|
||||
FST_ST_VHDL_FOR_GENERATE = 18,
|
||||
FST_ST_VHDL_IF_GENERATE = 19,
|
||||
FST_ST_VHDL_GENERATE = 20,
|
||||
FST_ST_VHDL_PACKAGE = 21,
|
||||
|
||||
FST_ST_MAX = 21,
|
||||
FST_ST_MAX = 21,
|
||||
|
||||
FST_ST_GEN_ATTRBEGIN = 252,
|
||||
FST_ST_GEN_ATTREND = 253,
|
||||
FST_ST_GEN_ATTRBEGIN = 252,
|
||||
FST_ST_GEN_ATTREND = 253,
|
||||
|
||||
FST_ST_VCD_SCOPE = 254,
|
||||
FST_ST_VCD_UPSCOPE = 255
|
||||
FST_ST_VCD_SCOPE = 254,
|
||||
FST_ST_VCD_UPSCOPE = 255
|
||||
};
|
||||
|
||||
enum fstVarType {
|
||||
FST_VT_MIN = 0, /* start of vartypes */
|
||||
enum fstVarType
|
||||
{
|
||||
FST_VT_MIN = 0, /* start of vartypes */
|
||||
|
||||
FST_VT_VCD_EVENT = 0,
|
||||
FST_VT_VCD_INTEGER = 1,
|
||||
FST_VT_VCD_PARAMETER = 2,
|
||||
FST_VT_VCD_REAL = 3,
|
||||
FST_VT_VCD_REAL_PARAMETER = 4,
|
||||
FST_VT_VCD_REG = 5,
|
||||
FST_VT_VCD_SUPPLY0 = 6,
|
||||
FST_VT_VCD_SUPPLY1 = 7,
|
||||
FST_VT_VCD_TIME = 8,
|
||||
FST_VT_VCD_TRI = 9,
|
||||
FST_VT_VCD_TRIAND = 10,
|
||||
FST_VT_VCD_TRIOR = 11,
|
||||
FST_VT_VCD_TRIREG = 12,
|
||||
FST_VT_VCD_TRI0 = 13,
|
||||
FST_VT_VCD_TRI1 = 14,
|
||||
FST_VT_VCD_WAND = 15,
|
||||
FST_VT_VCD_WIRE = 16,
|
||||
FST_VT_VCD_WOR = 17,
|
||||
FST_VT_VCD_PORT = 18,
|
||||
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
|
||||
FST_VT_VCD_REALTIME = 20,
|
||||
FST_VT_VCD_EVENT = 0,
|
||||
FST_VT_VCD_INTEGER = 1,
|
||||
FST_VT_VCD_PARAMETER = 2,
|
||||
FST_VT_VCD_REAL = 3,
|
||||
FST_VT_VCD_REAL_PARAMETER = 4,
|
||||
FST_VT_VCD_REG = 5,
|
||||
FST_VT_VCD_SUPPLY0 = 6,
|
||||
FST_VT_VCD_SUPPLY1 = 7,
|
||||
FST_VT_VCD_TIME = 8,
|
||||
FST_VT_VCD_TRI = 9,
|
||||
FST_VT_VCD_TRIAND = 10,
|
||||
FST_VT_VCD_TRIOR = 11,
|
||||
FST_VT_VCD_TRIREG = 12,
|
||||
FST_VT_VCD_TRI0 = 13,
|
||||
FST_VT_VCD_TRI1 = 14,
|
||||
FST_VT_VCD_WAND = 15,
|
||||
FST_VT_VCD_WIRE = 16,
|
||||
FST_VT_VCD_WOR = 17,
|
||||
FST_VT_VCD_PORT = 18,
|
||||
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
|
||||
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_LOGIC = 23,
|
||||
FST_VT_SV_INT = 24, /* declare as size = 32 */
|
||||
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
|
||||
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
|
||||
FST_VT_SV_BYTE = 27, /* declare as size = 8 */
|
||||
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_BIT = 22,
|
||||
FST_VT_SV_LOGIC = 23,
|
||||
FST_VT_SV_INT = 24, /* declare as size = 32 */
|
||||
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
|
||||
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
|
||||
FST_VT_SV_BYTE = 27, /* declare as size = 8 */
|
||||
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_MAX = 29 /* end of vartypes */
|
||||
FST_VT_MAX = 29 /* end of vartypes */
|
||||
};
|
||||
|
||||
enum fstVarDir {
|
||||
FST_VD_MIN = 0,
|
||||
enum fstVarDir
|
||||
{
|
||||
FST_VD_MIN = 0,
|
||||
|
||||
FST_VD_IMPLICIT = 0,
|
||||
FST_VD_INPUT = 1,
|
||||
FST_VD_OUTPUT = 2,
|
||||
FST_VD_INOUT = 3,
|
||||
FST_VD_BUFFER = 4,
|
||||
FST_VD_LINKAGE = 5,
|
||||
FST_VD_IMPLICIT = 0,
|
||||
FST_VD_INPUT = 1,
|
||||
FST_VD_OUTPUT = 2,
|
||||
FST_VD_INOUT = 3,
|
||||
FST_VD_BUFFER = 4,
|
||||
FST_VD_LINKAGE = 5,
|
||||
|
||||
FST_VD_MAX = 5
|
||||
FST_VD_MAX = 5
|
||||
};
|
||||
|
||||
enum fstHierType {
|
||||
FST_HT_MIN = 0,
|
||||
enum fstHierType
|
||||
{
|
||||
FST_HT_MIN = 0,
|
||||
|
||||
FST_HT_SCOPE = 0,
|
||||
FST_HT_UPSCOPE = 1,
|
||||
FST_HT_VAR = 2,
|
||||
FST_HT_ATTRBEGIN = 3,
|
||||
FST_HT_ATTREND = 4,
|
||||
FST_HT_SCOPE = 0,
|
||||
FST_HT_UPSCOPE = 1,
|
||||
FST_HT_VAR = 2,
|
||||
FST_HT_ATTRBEGIN = 3,
|
||||
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 = 5,
|
||||
FST_HT_TREEEND = 6,
|
||||
/* 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 = 5,
|
||||
FST_HT_TREEEND = 6,
|
||||
|
||||
FST_HT_MAX = 6
|
||||
FST_HT_MAX = 6
|
||||
};
|
||||
|
||||
enum fstAttrType {
|
||||
FST_AT_MIN = 0,
|
||||
enum fstAttrType
|
||||
{
|
||||
FST_AT_MIN = 0,
|
||||
|
||||
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
|
||||
FST_AT_ARRAY = 1,
|
||||
FST_AT_ENUM = 2,
|
||||
FST_AT_PACK = 3,
|
||||
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
|
||||
FST_AT_ARRAY = 1,
|
||||
FST_AT_ENUM = 2,
|
||||
FST_AT_PACK = 3,
|
||||
|
||||
FST_AT_MAX = 3
|
||||
FST_AT_MAX = 3
|
||||
};
|
||||
|
||||
enum fstMiscType {
|
||||
FST_MT_MIN = 0,
|
||||
enum fstMiscType
|
||||
{
|
||||
FST_MT_MIN = 0,
|
||||
|
||||
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
|
||||
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
|
||||
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
|
||||
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
|
||||
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
|
||||
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
|
||||
FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
|
||||
FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
|
||||
FST_MT_UNKNOWN = 8,
|
||||
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
|
||||
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
|
||||
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
|
||||
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
|
||||
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
|
||||
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
|
||||
FST_MT_VALUELIST =
|
||||
6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
|
||||
FST_MT_ENUMTABLE =
|
||||
7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
|
||||
FST_MT_UNKNOWN = 8,
|
||||
|
||||
FST_MT_MAX = 8
|
||||
FST_MT_MAX = 8
|
||||
};
|
||||
|
||||
enum fstArrayType {
|
||||
FST_AR_MIN = 0,
|
||||
enum fstArrayType
|
||||
{
|
||||
FST_AR_MIN = 0,
|
||||
|
||||
FST_AR_NONE = 0,
|
||||
FST_AR_UNPACKED = 1,
|
||||
FST_AR_PACKED = 2,
|
||||
FST_AR_SPARSE = 3,
|
||||
FST_AR_NONE = 0,
|
||||
FST_AR_UNPACKED = 1,
|
||||
FST_AR_PACKED = 2,
|
||||
FST_AR_SPARSE = 3,
|
||||
|
||||
FST_AR_MAX = 3
|
||||
FST_AR_MAX = 3
|
||||
};
|
||||
|
||||
enum fstEnumValueType {
|
||||
FST_EV_SV_INTEGER = 0,
|
||||
FST_EV_SV_BIT = 1,
|
||||
FST_EV_SV_LOGIC = 2,
|
||||
FST_EV_SV_INT = 3,
|
||||
FST_EV_SV_SHORTINT = 4,
|
||||
FST_EV_SV_LONGINT = 5,
|
||||
FST_EV_SV_BYTE = 6,
|
||||
FST_EV_SV_UNSIGNED_INTEGER = 7,
|
||||
FST_EV_SV_UNSIGNED_BIT = 8,
|
||||
FST_EV_SV_UNSIGNED_LOGIC = 9,
|
||||
FST_EV_SV_UNSIGNED_INT = 10,
|
||||
enum fstEnumValueType
|
||||
{
|
||||
FST_EV_SV_INTEGER = 0,
|
||||
FST_EV_SV_BIT = 1,
|
||||
FST_EV_SV_LOGIC = 2,
|
||||
FST_EV_SV_INT = 3,
|
||||
FST_EV_SV_SHORTINT = 4,
|
||||
FST_EV_SV_LONGINT = 5,
|
||||
FST_EV_SV_BYTE = 6,
|
||||
FST_EV_SV_UNSIGNED_INTEGER = 7,
|
||||
FST_EV_SV_UNSIGNED_BIT = 8,
|
||||
FST_EV_SV_UNSIGNED_LOGIC = 9,
|
||||
FST_EV_SV_UNSIGNED_INT = 10,
|
||||
FST_EV_SV_UNSIGNED_SHORTINT = 11,
|
||||
FST_EV_SV_UNSIGNED_LONGINT = 12,
|
||||
FST_EV_SV_UNSIGNED_BYTE = 13,
|
||||
FST_EV_SV_UNSIGNED_LONGINT = 12,
|
||||
FST_EV_SV_UNSIGNED_BYTE = 13,
|
||||
|
||||
FST_EV_REG = 14,
|
||||
FST_EV_TIME = 15,
|
||||
FST_EV_REG = 14,
|
||||
FST_EV_TIME = 15,
|
||||
|
||||
FST_EV_MAX = 15
|
||||
FST_EV_MAX = 15
|
||||
};
|
||||
|
||||
enum fstPackType {
|
||||
FST_PT_NONE = 0,
|
||||
FST_PT_UNPACKED = 1,
|
||||
FST_PT_PACKED = 2,
|
||||
enum fstPackType
|
||||
{
|
||||
FST_PT_NONE = 0,
|
||||
FST_PT_UNPACKED = 1,
|
||||
FST_PT_PACKED = 2,
|
||||
FST_PT_TAGGED_PACKED = 3,
|
||||
|
||||
FST_PT_MAX = 3
|
||||
FST_PT_MAX = 3
|
||||
};
|
||||
|
||||
enum fstSupplementalVarType {
|
||||
FST_SVT_MIN = 0,
|
||||
enum fstSupplementalVarType
|
||||
{
|
||||
FST_SVT_MIN = 0,
|
||||
|
||||
FST_SVT_NONE = 0,
|
||||
FST_SVT_NONE = 0,
|
||||
|
||||
FST_SVT_VHDL_SIGNAL = 1,
|
||||
FST_SVT_VHDL_VARIABLE = 2,
|
||||
FST_SVT_VHDL_CONSTANT = 3,
|
||||
FST_SVT_VHDL_FILE = 4,
|
||||
FST_SVT_VHDL_MEMORY = 5,
|
||||
FST_SVT_VHDL_SIGNAL = 1,
|
||||
FST_SVT_VHDL_VARIABLE = 2,
|
||||
FST_SVT_VHDL_CONSTANT = 3,
|
||||
FST_SVT_VHDL_FILE = 4,
|
||||
FST_SVT_VHDL_MEMORY = 5,
|
||||
|
||||
FST_SVT_MAX = 5
|
||||
FST_SVT_MAX = 5
|
||||
};
|
||||
|
||||
enum fstSupplementalDataType {
|
||||
FST_SDT_MIN = 0,
|
||||
enum fstSupplementalDataType
|
||||
{
|
||||
FST_SDT_MIN = 0,
|
||||
|
||||
FST_SDT_NONE = 0,
|
||||
FST_SDT_NONE = 0,
|
||||
|
||||
FST_SDT_VHDL_BOOLEAN = 1,
|
||||
FST_SDT_VHDL_BIT = 2,
|
||||
FST_SDT_VHDL_BIT_VECTOR = 3,
|
||||
FST_SDT_VHDL_STD_ULOGIC = 4,
|
||||
FST_SDT_VHDL_BOOLEAN = 1,
|
||||
FST_SDT_VHDL_BIT = 2,
|
||||
FST_SDT_VHDL_BIT_VECTOR = 3,
|
||||
FST_SDT_VHDL_STD_ULOGIC = 4,
|
||||
FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5,
|
||||
FST_SDT_VHDL_STD_LOGIC = 6,
|
||||
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
|
||||
FST_SDT_VHDL_UNSIGNED = 8,
|
||||
FST_SDT_VHDL_SIGNED = 9,
|
||||
FST_SDT_VHDL_INTEGER = 10,
|
||||
FST_SDT_VHDL_REAL = 11,
|
||||
FST_SDT_VHDL_NATURAL = 12,
|
||||
FST_SDT_VHDL_POSITIVE = 13,
|
||||
FST_SDT_VHDL_TIME = 14,
|
||||
FST_SDT_VHDL_CHARACTER = 15,
|
||||
FST_SDT_VHDL_STRING = 16,
|
||||
FST_SDT_VHDL_STD_LOGIC = 6,
|
||||
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
|
||||
FST_SDT_VHDL_UNSIGNED = 8,
|
||||
FST_SDT_VHDL_SIGNED = 9,
|
||||
FST_SDT_VHDL_INTEGER = 10,
|
||||
FST_SDT_VHDL_REAL = 11,
|
||||
FST_SDT_VHDL_NATURAL = 12,
|
||||
FST_SDT_VHDL_POSITIVE = 13,
|
||||
FST_SDT_VHDL_TIME = 14,
|
||||
FST_SDT_VHDL_CHARACTER = 15,
|
||||
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_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1)
|
||||
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_ABS_MAX = ((1 << (FST_SDT_SVT_SHIFT_COUNT)) - 1)
|
||||
};
|
||||
|
||||
|
||||
struct fstHier
|
||||
{
|
||||
unsigned char htyp;
|
||||
unsigned char htyp;
|
||||
|
||||
union {
|
||||
union
|
||||
{
|
||||
/* if htyp == FST_HT_SCOPE */
|
||||
struct fstHierScope {
|
||||
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
|
||||
const char *name;
|
||||
const char *component;
|
||||
uint32_t name_length; /* strlen(u.scope.name) */
|
||||
uint32_t component_length; /* strlen(u.scope.component) */
|
||||
} scope;
|
||||
struct fstHierScope
|
||||
{
|
||||
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
|
||||
const char *name;
|
||||
const char *component;
|
||||
uint32_t name_length; /* strlen(u.scope.name) */
|
||||
uint32_t component_length; /* strlen(u.scope.component) */
|
||||
} scope;
|
||||
|
||||
/* if htyp == FST_HT_VAR */
|
||||
struct fstHierVar {
|
||||
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
|
||||
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
|
||||
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
|
||||
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
|
||||
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
|
||||
const char *name;
|
||||
uint32_t length;
|
||||
fstHandle handle;
|
||||
uint32_t name_length; /* strlen(u.var.name) */
|
||||
unsigned is_alias : 1;
|
||||
} var;
|
||||
struct fstHierVar
|
||||
{
|
||||
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
|
||||
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
|
||||
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
|
||||
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
|
||||
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
|
||||
const char *name;
|
||||
uint32_t length;
|
||||
fstHandle handle;
|
||||
uint32_t name_length; /* strlen(u.var.name) */
|
||||
unsigned is_alias : 1;
|
||||
} var;
|
||||
|
||||
/* if htyp == FST_HT_ATTRBEGIN */
|
||||
struct fstHierAttr {
|
||||
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
|
||||
unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
|
||||
const char *name;
|
||||
uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */
|
||||
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 fstHierAttr
|
||||
{
|
||||
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
|
||||
unsigned char
|
||||
subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
|
||||
const char *name;
|
||||
uint64_t arg; /* number of array elements, struct members, or some other payload
|
||||
(possibly ignored) */
|
||||
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
|
||||
{
|
||||
char *name;
|
||||
uint32_t elem_count;
|
||||
char **literal_arr;
|
||||
char **val_arr;
|
||||
char *name;
|
||||
uint32_t elem_count;
|
||||
char **literal_arr;
|
||||
char **val_arr;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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 fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
|
||||
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 fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ std::vector<RTLIL::Design*> pushed_designs;
|
|||
|
||||
struct DesignPass : public Pass {
|
||||
DesignPass() : Pass("design", "save, restore and reset current design") { }
|
||||
~DesignPass() override {
|
||||
void on_shutdown() override {
|
||||
for (auto &it : saved_designs)
|
||||
delete it.second;
|
||||
saved_designs.clear();
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ struct InternalStatsPass : public Pass {
|
|||
|
||||
if (json_mode) {
|
||||
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::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
|
||||
log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ struct LoggerPass : public Pass {
|
|||
log(" -check-expected\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(" 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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ struct StatPass : public Pass {
|
|||
|
||||
if (json_mode) {
|
||||
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::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
|
||||
log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());
|
||||
|
|
|
|||
|
|
@ -1452,7 +1452,7 @@ struct HierarchyPass : public Pass {
|
|||
|
||||
bool resize_widths = !keep_portwidths && GetSize(w) != GetSize(conn.second);
|
||||
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)
|
||||
);
|
||||
else if (resize_widths) {
|
||||
|
|
|
|||
|
|
@ -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_shiftadd.pmg
|
||||
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv.pmg
|
||||
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv_c.pmg
|
||||
PEEPOPT_PATTERN += passes/opt/peepopt_formal_clockgateff.pmg
|
||||
|
||||
passes/opt/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
||||
|
|
|
|||
|
|
@ -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::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;
|
||||
|
|
@ -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()))
|
||||
{
|
||||
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)))
|
||||
shift_bits *= -1;
|
||||
|
|
@ -1715,22 +1720,22 @@ skip_identity:
|
|||
|
||||
if (onehot) {
|
||||
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->type = ID($shl);
|
||||
cell->parameters[ID::A_WIDTH] = 1;
|
||||
cell->setPort(ID::A, Const(State::S1, 1));
|
||||
}
|
||||
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->type = ID($mul);
|
||||
cell->parameters[ID::A_SIGNED] = 0;
|
||||
cell->setPort(ID::A, Const(bit_idx, cell->parameters[ID::A_WIDTH].as_int()));
|
||||
|
||||
|
||||
SigSpec y_wire = module->addWire(NEW_ID, y_size);
|
||||
cell->setPort(ID::Y, y_wire);
|
||||
|
||||
|
||||
module->addShl(NEW_ID, Const(State::S1, 1), y_wire, sig_y);
|
||||
}
|
||||
did_something = true;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,14 @@ bool did_something;
|
|||
// scratchpad configurations for pmgen
|
||||
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"
|
||||
|
||||
struct PeepoptPass : public Pass {
|
||||
|
|
@ -45,6 +53,8 @@ struct PeepoptPass : public Pass {
|
|||
log("\n");
|
||||
log(" * muldiv - Replace (A*B)/B with A\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(" and A' is derived from A by appropriately inserting padding\n");
|
||||
log(" into the signal. (right variant)\n");
|
||||
|
|
@ -106,6 +116,7 @@ struct PeepoptPass : public Pass {
|
|||
pm.run_shiftmul_right();
|
||||
pm.run_shiftmul_left();
|
||||
pm.run_muldiv();
|
||||
pm.run_muldiv_c();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
125
passes/opt/peepopt_muldiv_c.pmg
Normal file
125
passes/opt/peepopt_muldiv_c.pmg
Normal 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
|
||||
|
|
@ -288,43 +288,40 @@ struct ProcArstPass : public Pass {
|
|||
extra_args(args, argidx, design);
|
||||
pool<Wire*> delete_initattr_wires;
|
||||
|
||||
for (auto mod : design->modules())
|
||||
if (design->selected(mod)) {
|
||||
SigMap assign_map(mod);
|
||||
for (auto &proc_it : mod->processes) {
|
||||
if (!design->selected(mod, proc_it.second))
|
||||
continue;
|
||||
proc_arst(mod, proc_it.second, assign_map);
|
||||
if (global_arst.empty() || mod->wire(global_arst) == nullptr)
|
||||
continue;
|
||||
std::vector<RTLIL::SigSig> arst_actions;
|
||||
for (auto sync : proc_it.second->syncs)
|
||||
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
|
||||
for (auto &act : sync->actions) {
|
||||
RTLIL::SigSpec arst_sig, arst_val;
|
||||
for (auto &chunk : act.first.chunks())
|
||||
if (chunk.wire && chunk.wire->attributes.count(ID::init)) {
|
||||
RTLIL::SigSpec value = chunk.wire->attributes.at(ID::init);
|
||||
value.extend_u0(chunk.wire->width, false);
|
||||
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));
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
SigMap assign_map(mod);
|
||||
for (auto proc : mod->selected_processes()) {
|
||||
proc_arst(mod, proc, assign_map);
|
||||
if (global_arst.empty() || mod->wire(global_arst) == nullptr)
|
||||
continue;
|
||||
std::vector<RTLIL::SigSig> arst_actions;
|
||||
for (auto sync : proc->syncs)
|
||||
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
|
||||
for (auto &act : sync->actions) {
|
||||
RTLIL::SigSpec arst_sig, arst_val;
|
||||
for (auto &chunk : act.first.chunks())
|
||||
if (chunk.wire && chunk.wire->attributes.count(ID::init)) {
|
||||
RTLIL::SigSpec value = chunk.wire->attributes.at(ID::init);
|
||||
value.extend_u0(chunk.wire->width, false);
|
||||
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->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;
|
||||
sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1;
|
||||
sync->signal = mod->wire(global_arst);
|
||||
sync->actions = arst_actions;
|
||||
proc_it.second->syncs.push_back(sync);
|
||||
}
|
||||
}
|
||||
if (!arst_actions.empty()) {
|
||||
RTLIL::SyncRule *sync = new RTLIL::SyncRule;
|
||||
sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1;
|
||||
sync->signal = mod->wire(global_arst);
|
||||
sync->actions = arst_actions;
|
||||
proc->syncs.push_back(sync);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto wire : delete_initattr_wires)
|
||||
wire->attributes.erase(ID::init);
|
||||
|
|
|
|||
|
|
@ -208,19 +208,15 @@ struct ProcCleanPass : public Pass {
|
|||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (auto mod : design->modules()) {
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
std::vector<RTLIL::Process *> delme;
|
||||
if (!design->selected(mod))
|
||||
continue;
|
||||
for (auto &proc_it : mod->processes) {
|
||||
if (!design->selected(mod, proc_it.second))
|
||||
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) {
|
||||
for (auto proc : mod->selected_processes()) {
|
||||
proc_clean(mod, proc, total_count, quiet);
|
||||
if (proc->syncs.size() == 0 && proc->root_case.switches.size() == 0 &&
|
||||
proc->root_case.actions.size() == 0) {
|
||||
if (!quiet)
|
||||
log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str());
|
||||
delme.push_back(proc_it.second);
|
||||
log("Removing empty process `%s.%s'.\n", log_id(mod), proc->name.c_str());
|
||||
delme.push_back(proc);
|
||||
}
|
||||
}
|
||||
for (auto proc : delme) {
|
||||
|
|
|
|||
|
|
@ -306,13 +306,11 @@ struct ProcDffPass : public Pass {
|
|||
|
||||
extra_args(args, 1, design);
|
||||
|
||||
for (auto mod : design->modules())
|
||||
if (design->selected(mod)) {
|
||||
ConstEval ce(mod);
|
||||
for (auto &proc_it : mod->processes)
|
||||
if (design->selected(mod, proc_it.second))
|
||||
proc_dff(mod, proc_it.second, ce);
|
||||
}
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
ConstEval ce(mod);
|
||||
for (auto proc : mod->selected_processes())
|
||||
proc_dff(mod, proc, ce);
|
||||
}
|
||||
}
|
||||
} ProcDffPass;
|
||||
|
||||
|
|
|
|||
|
|
@ -463,11 +463,10 @@ struct ProcDlatchPass : public Pass {
|
|||
|
||||
extra_args(args, 1, design);
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
proc_dlatch_db_t db(module);
|
||||
for (auto &proc_it : module->processes)
|
||||
if (design->selected(module, proc_it.second))
|
||||
proc_dlatch(db, proc_it.second);
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
proc_dlatch_db_t db(mod);
|
||||
for (auto proc : mod->selected_processes())
|
||||
proc_dlatch(db, proc);
|
||||
db.fixup_muxes();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,13 +91,11 @@ struct ProcInitPass : public Pass {
|
|||
|
||||
extra_args(args, 1, design);
|
||||
|
||||
for (auto mod : design->modules())
|
||||
if (design->selected(mod)) {
|
||||
SigMap sigmap(mod);
|
||||
for (auto &proc_it : mod->processes)
|
||||
if (design->selected(mod, proc_it.second))
|
||||
proc_init(mod, sigmap, proc_it.second);
|
||||
}
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
SigMap sigmap(mod);
|
||||
for (auto proc : mod->selected_processes())
|
||||
proc_init(mod, sigmap, proc);
|
||||
}
|
||||
}
|
||||
} ProcInitPass;
|
||||
|
||||
|
|
|
|||
|
|
@ -99,9 +99,9 @@ struct ProcMemWrPass : public Pass {
|
|||
|
||||
extra_args(args, 1, design);
|
||||
|
||||
for (auto module : design->selected_modules()) {
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
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))) {
|
||||
bool is_compat = cell->type == ID($memwr);
|
||||
IdString memid = cell->parameters.at(ID::MEMID).decode_string();
|
||||
|
|
@ -110,9 +110,8 @@ struct ProcMemWrPass : public Pass {
|
|||
next_port_id[memid] = port_id + 1;
|
||||
}
|
||||
}
|
||||
for (auto &proc_it : module->processes)
|
||||
if (design->selected(module, proc_it.second))
|
||||
proc_memwr(module, proc_it.second, next_port_id);
|
||||
for (auto proc : mod->selected_processes())
|
||||
proc_memwr(mod, proc, next_port_id);
|
||||
}
|
||||
}
|
||||
} ProcMemWrPass;
|
||||
|
|
|
|||
|
|
@ -468,11 +468,9 @@ struct ProcMuxPass : public Pass {
|
|||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
for (auto mod : design->modules())
|
||||
if (design->selected(mod))
|
||||
for (auto &proc_it : mod->processes)
|
||||
if (design->selected(mod, proc_it.second))
|
||||
proc_mux(mod, proc_it.second, ifxmode);
|
||||
for (auto mod : design->all_selected_modules())
|
||||
for (auto proc : mod->selected_processes())
|
||||
proc_mux(mod, proc, ifxmode);
|
||||
}
|
||||
} ProcMuxPass;
|
||||
|
||||
|
|
|
|||
|
|
@ -127,15 +127,10 @@ struct ProcPrunePass : public Pass {
|
|||
|
||||
extra_args(args, 1, design);
|
||||
|
||||
for (auto mod : design->modules()) {
|
||||
if (!design->selected(mod))
|
||||
continue;
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
PruneWorker worker(mod);
|
||||
for (auto &proc_it : mod->processes) {
|
||||
if (!design->selected(mod, proc_it.second))
|
||||
continue;
|
||||
worker.do_process(proc_it.second);
|
||||
}
|
||||
for (auto proc : mod->selected_processes())
|
||||
worker.do_process(proc);
|
||||
total_removed_count += worker.removed_count;
|
||||
total_promoted_count += worker.promoted_count;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,21 +147,17 @@ struct ProcRmdeadPass : public Pass {
|
|||
extra_args(args, 1, design);
|
||||
|
||||
int total_counter = 0;
|
||||
for (auto mod : design->modules()) {
|
||||
if (!design->selected(mod))
|
||||
continue;
|
||||
for (auto &proc_it : mod->processes) {
|
||||
if (!design->selected(mod, proc_it.second))
|
||||
continue;
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
for (auto proc : mod->selected_processes()) {
|
||||
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);
|
||||
if (counter > 0)
|
||||
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)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,15 +243,10 @@ struct ProcRomPass : public Pass {
|
|||
|
||||
extra_args(args, 1, design);
|
||||
|
||||
for (auto mod : design->modules()) {
|
||||
if (!design->selected(mod))
|
||||
continue;
|
||||
for (auto mod : design->all_selected_modules()) {
|
||||
RomWorker worker(mod);
|
||||
for (auto &proc_it : mod->processes) {
|
||||
if (!design->selected(mod, proc_it.second))
|
||||
continue;
|
||||
worker.do_process(proc_it.second);
|
||||
}
|
||||
for (auto proc : mod->selected_processes())
|
||||
worker.do_process(proc);
|
||||
total_count += worker.count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,20 @@ struct CutpointPass : public Pass {
|
|||
|
||||
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);
|
||||
pool<SigBit> cutpoint_bits;
|
||||
|
||||
|
|
|
|||
|
|
@ -691,7 +691,7 @@ struct SatHelper
|
|||
fprintf(f, " %s\n", stime);
|
||||
fprintf(f, "$end\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, "$comment\n");
|
||||
fprintf(f, " Generated from SAT problem in module %s (declared at %s)\n",
|
||||
|
|
|
|||
|
|
@ -1546,36 +1546,27 @@ struct SimWorker : SimShared
|
|||
log(" for %d clock cycle(s)",numcycles);
|
||||
log("\n");
|
||||
bool all_samples = fst_clock.empty();
|
||||
unsigned int end_cycle = cycles_set ? numcycles*2 : INT_MAX;
|
||||
|
||||
try {
|
||||
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
|
||||
if (verbose)
|
||||
log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
|
||||
bool did_something = top->setInputs();
|
||||
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, end_cycle, [&](uint64_t time) {
|
||||
if (verbose)
|
||||
log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
|
||||
bool did_something = top->setInputs();
|
||||
|
||||
if (initial) {
|
||||
if (!fst_noinit) did_something |= top->setInitState();
|
||||
initialize_stable_past();
|
||||
initial = false;
|
||||
}
|
||||
if (did_something)
|
||||
update(true);
|
||||
register_output_step(time);
|
||||
if (initial) {
|
||||
if (!fst_noinit) did_something |= top->setInitState();
|
||||
initialize_stable_past();
|
||||
initial = false;
|
||||
}
|
||||
if (did_something)
|
||||
update(true);
|
||||
register_output_step(time);
|
||||
|
||||
bool status = top->checkSignals();
|
||||
if (status)
|
||||
log_error("Signal difference\n");
|
||||
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
|
||||
}
|
||||
bool status = top->checkSignals();
|
||||
if (status)
|
||||
log_error("Signal difference\n");
|
||||
cycle++;
|
||||
});
|
||||
|
||||
write_output_files();
|
||||
delete fst;
|
||||
|
|
@ -2065,7 +2056,7 @@ struct SimWorker : SimShared
|
|||
|
||||
json.begin_object();
|
||||
json.entry("version", "Yosys sim summary");
|
||||
json.entry("generator", yosys_version_str);
|
||||
json.entry("generator", yosys_maybe_version());
|
||||
json.entry("steps", step);
|
||||
json.entry("top", log_id(top->module->name));
|
||||
json.name("assertions");
|
||||
|
|
@ -2248,40 +2239,31 @@ struct SimWorker : SimShared
|
|||
log("Writing data to `%s`\n", (tb_filename+".txt").c_str());
|
||||
std::ofstream data_file(tb_filename+".txt");
|
||||
std::stringstream initstate;
|
||||
try {
|
||||
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
|
||||
for(auto &item : clocks)
|
||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||
for(auto &item : inputs)
|
||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||
for(auto &item : outputs)
|
||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||
data_file << stringf("%s\n",Const(time-prev_time).as_string().c_str());
|
||||
unsigned int end_cycle = cycles_set ? numcycles*2 : INT_MAX;
|
||||
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, end_cycle, [&](uint64_t time) {
|
||||
for(auto &item : clocks)
|
||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||
for(auto &item : inputs)
|
||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||
for(auto &item : outputs)
|
||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||
data_file << stringf("%s\n",Const(time-prev_time).as_string().c_str());
|
||||
|
||||
if (time==startCount) {
|
||||
// initial state
|
||||
for(auto var : fst->getVars()) {
|
||||
if (var.is_reg && !Const::from_string(fst->valueOf(var.id).c_str()).is_fully_undef()) {
|
||||
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());
|
||||
} 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());
|
||||
}
|
||||
if (time==startCount) {
|
||||
// initial state
|
||||
for(auto var : fst->getVars()) {
|
||||
if (var.is_reg && !Const::from_string(fst->valueOf(var.id).c_str()).is_fully_undef()) {
|
||||
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());
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
cycle++;
|
||||
prev_time = time;
|
||||
});
|
||||
|
||||
f << stringf("\treg [0:%d] data [0:%d];\n", data_len-1, cycle-1);
|
||||
f << "\tinitial begin;\n";
|
||||
|
|
@ -2344,7 +2326,7 @@ struct VCDWriter : public OutputWriter
|
|||
void write(std::map<int, bool> &use_signal) override
|
||||
{
|
||||
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) {
|
||||
std::time_t t = std::time(nullptr);
|
||||
|
|
@ -2400,7 +2382,7 @@ struct VCDWriter : public OutputWriter
|
|||
struct FSTWriter : public OutputWriter
|
||||
{
|
||||
FSTWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) {
|
||||
fstfile = (struct fstContext *)fstWriterCreate(filename.c_str(),1);
|
||||
fstfile = fstWriterCreate(filename.c_str(),1);
|
||||
}
|
||||
|
||||
virtual ~FSTWriter()
|
||||
|
|
@ -2412,7 +2394,7 @@ struct FSTWriter : public OutputWriter
|
|||
{
|
||||
if (!fstfile) return;
|
||||
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)
|
||||
fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
|
||||
else
|
||||
|
|
@ -2456,7 +2438,7 @@ struct FSTWriter : public OutputWriter
|
|||
}
|
||||
}
|
||||
|
||||
struct fstContext *fstfile = nullptr;
|
||||
struct fstWriterContext *fstfile = nullptr;
|
||||
std::map<int,fstHandle> mapping;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
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::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;
|
||||
|
||||
|
|
@ -186,6 +186,10 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
|
|||
}
|
||||
if (!constr_file.empty())
|
||||
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());
|
||||
|
|
@ -384,9 +388,14 @@ struct Abc9ExePass : public Pass {
|
|||
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("\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(" 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(" -D <picoseconds>\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 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 tempdir_name;
|
||||
bool fast_mode = false, dff_mode = false;
|
||||
|
|
@ -530,9 +539,15 @@ struct Abc9ExePass : public Pass {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-liberty" && argidx+1 < args.size()) {
|
||||
rewrite_filename(args[argidx+1]);
|
||||
liberty_files.push_back(args[++argidx]);
|
||||
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()) {
|
||||
dont_use_cells.push_back(args[++argidx]);
|
||||
continue;
|
||||
|
|
@ -601,11 +616,13 @@ struct Abc9ExePass : public Pass {
|
|||
if (tempdir_name.empty())
|
||||
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,
|
||||
delay_target, lutin_shared, fast_mode, show_tempdir,
|
||||
box_file, lut_file, liberty_files, wire_delay, tempdir_name,
|
||||
constr_file, dont_use_cells);
|
||||
constr_file, dont_use_cells, genlib_files);
|
||||
}
|
||||
} Abc9ExePass;
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
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;
|
||||
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 (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)) {
|
||||
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);
|
||||
|
||||
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;
|
||||
for (auto port_name : box_ports.at(cell->type)) {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ struct AbcNewPass : public ScriptPass {
|
|||
log(" -constr <file>\n");
|
||||
log(" -dont_use <cell_name>\n");
|
||||
log(" -liberty <file>\n");
|
||||
log(" -genlib <file>\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(" 'help abc9_exe' for more details\n");
|
||||
|
|
@ -90,7 +91,7 @@ struct AbcNewPass : public ScriptPass {
|
|||
if (args[argidx] == "-exe" || args[argidx] == "-script" ||
|
||||
args[argidx] == "-D" ||
|
||||
args[argidx] == "-constr" || args[argidx] == "-dont_use" ||
|
||||
args[argidx] == "-liberty") {
|
||||
args[argidx] == "-liberty" || args[argidx] == "-genlib") {
|
||||
abc_exe_options += " " + args[argidx] + " " + args[argidx + 1];
|
||||
argidx++;
|
||||
} else if (args[argidx] == "-run" && argidx + 1 < args.size()) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,13 @@
|
|||
log("\n");
|
||||
log("Displays the current cache settings and cached paths.\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
|
||||
{
|
||||
|
|
@ -55,6 +62,8 @@
|
|||
bool purge = false;
|
||||
bool all = false;
|
||||
bool list = false;
|
||||
bool verbose = false;
|
||||
bool quiet = false;
|
||||
std::vector<std::string> paths;
|
||||
|
||||
size_t argidx;
|
||||
|
|
@ -79,16 +88,24 @@
|
|||
list = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-verbose") {
|
||||
verbose = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-quiet") {
|
||||
quiet = true;
|
||||
continue;
|
||||
}
|
||||
std::string fname = args[argidx];
|
||||
rewrite_filename(fname);
|
||||
paths.push_back(fname);
|
||||
break;
|
||||
}
|
||||
int modes = enable + disable + purge + list;
|
||||
int modes = enable + disable + purge + list + verbose + quiet;
|
||||
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)
|
||||
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())
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else if (verbose) {
|
||||
LibertyAstCache::instance.verbose = true;
|
||||
} else if (quiet) {
|
||||
LibertyAstCache::instance.verbose = false;
|
||||
} else {
|
||||
log_assert(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ std::shared_ptr<const LibertyAst> LibertyAstCache::cached_ast(const std::string
|
|||
auto it = cached.find(fname);
|
||||
if (it == cached.end())
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
if (!should_cache)
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ namespace Yosys
|
|||
dict<std::string, std::shared_ptr<const LibertyAst>> cached;
|
||||
|
||||
bool cache_by_default = false;
|
||||
bool verbose = false;
|
||||
dict<std::string, bool> cache_path;
|
||||
|
||||
std::shared_ptr<const LibertyAst> cached_ast(const std::string &fname);
|
||||
|
|
|
|||
|
|
@ -35,3 +35,25 @@ ram huge $__XILINX_URAM_ {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,3 +150,141 @@ module $__XILINX_URAM_ (...);
|
|||
.SLEEP(1'b0)
|
||||
);
|
||||
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
10
tests/aiger/io.ys
Normal 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
|
||||
|
|
@ -2,7 +2,7 @@ module priority_memory (
|
|||
clk, wren_a, rden_a, addr_a, wdata_a, rdata_a,
|
||||
wren_b, rden_b, addr_b, wdata_b, rdata_b
|
||||
);
|
||||
|
||||
|
||||
parameter ABITS = 12;
|
||||
parameter WIDTH = 72;
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ module priority_memory (
|
|||
mem[addr_a] <= wdata_a;
|
||||
else if (rden_a)
|
||||
rdata_a <= mem[addr_a];
|
||||
|
||||
|
||||
// B port
|
||||
if (wren_b)
|
||||
mem[addr_b] <= wdata_b;
|
||||
|
|
@ -47,7 +47,7 @@ module priority_memory (
|
|||
mem[addr_b] <= wdata_b;
|
||||
else if (rden_b)
|
||||
rdata_b <= mem[addr_b];
|
||||
|
||||
|
||||
// B port
|
||||
if (wren_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;
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
// A port
|
||||
if (wren_a)
|
||||
mem[addr_a] <= wdata_a;
|
||||
if (rden_a)
|
||||
if (rden_a)
|
||||
if (wren_a)
|
||||
rdata_a <= wdata_a;
|
||||
else
|
||||
|
|
@ -111,12 +110,39 @@ module sp_read_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
|
|||
rdata_a <= 'h0;
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
// A port
|
||||
if (wren_a)
|
||||
mem[addr_a] <= wdata_a;
|
||||
if (rden_a)
|
||||
if (rden_a)
|
||||
rdata_a <= mem[addr_a];
|
||||
end
|
||||
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
|
||||
|
|
|
|||
|
|
@ -58,3 +58,13 @@ select -assert-count 1 t:URAM288
|
|||
# see above for details
|
||||
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
|
||||
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
libcache -verbose
|
||||
libcache -enable busdef.lib
|
||||
|
||||
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
|
||||
logger -check-expected
|
||||
|
||||
logger -expect log "Using caching data" 1
|
||||
log Using caching data
|
||||
logger -expect log "Using cached data" 1
|
||||
log Using cached data
|
||||
read_liberty normal.lib; design -reset
|
||||
logger -check-expected
|
||||
|
||||
|
|
@ -23,6 +24,13 @@ logger -expect log "Using cached data" 1
|
|||
read_liberty -lib busdef.lib; design -reset
|
||||
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
|
||||
|
||||
logger -expect log "Caching is disabled by default." 1
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ module top (
|
|||
output wire [7:0] sshr_uu,
|
||||
output wire signed [7:0] sshr_us,
|
||||
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_us = in_u << 20;
|
||||
|
|
@ -38,9 +42,20 @@ module top (
|
|||
assign sshr_us = in_u >>> 20;
|
||||
assign sshr_su = 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
|
||||
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
|
||||
|
||||
design -load postopt
|
||||
|
|
@ -48,3 +63,98 @@ 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 << 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
1
tests/peepopt/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/*.log
|
||||
343
tests/peepopt/muldiv_c.ys
Normal file
343
tests/peepopt/muldiv_c.ys
Normal 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 (divider’s 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 (divider’s 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 (divider’s 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 (divider’s 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 divider’s A input signedness is confused & (A input is unsigned)"
|
||||
log -push
|
||||
# Transform even if:
|
||||
# (a*b) result would overflow if divider’s 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
|
||||
6
tests/peepopt/run-test.sh
Normal file
6
tests/peepopt/run-test.sh
Normal 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
51
tests/sim/sim_cycles.ys
Normal 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
|
||||
13
tests/svtypes/typedef_struct_global.ys
Normal file
13
tests/svtypes/typedef_struct_global.ys
Normal 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
|
||||
50
tests/various/cutpoint_whole.ys
Normal file
50
tests/various/cutpoint_whole.ys
Normal 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
|
||||
132
tests/verilog/func_task_arg_copying.ys
Normal file
132
tests/verilog/func_task_arg_copying.ys
Normal 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
68
tests/verilog/incdec.ys
Normal 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
|
||||
41
tests/verilog/priority_if_enc.ys
Normal file
41
tests/verilog/priority_if_enc.ys
Normal 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
30
tests/verilog/sbvector.ys
Normal 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
|
||||
41
tests/verilog/unique0_if_enc.ys
Normal file
41
tests/verilog/unique0_if_enc.ys
Normal 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
|
||||
10
tests/verilog/unique_if.ys
Normal file
10
tests/verilog/unique_if.ys
Normal 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
|
||||
11
tests/verilog/unique_if_else.ys
Normal file
11
tests/verilog/unique_if_else.ys
Normal 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
|
||||
12
tests/verilog/unique_if_else_begin.ys
Normal file
12
tests/verilog/unique_if_else_begin.ys
Normal 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
Loading…
Add table
Add a link
Reference in a new issue