mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-04 14:36:10 +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
|
List of major changes and improvements between releases
|
||||||
=======================================================
|
=======================================================
|
||||||
|
|
||||||
Yosys 0.53 .. Yosys 0.54-dev
|
Yosys 0.54 .. Yosys 0.55-dev
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
Yosys 0.53 .. Yosys 0.54
|
||||||
|
--------------------------
|
||||||
|
* New commands and options
|
||||||
|
- Added "-genlib" option to "abc_new" and "abc9_exe" passes.
|
||||||
|
- Added "-verbose" and "-quiet" options to "libcache" pass.
|
||||||
|
- Added "-no-sort" option to "write_aiger" pass.
|
||||||
|
|
||||||
|
* Various
|
||||||
|
- Added "muldiv_c" peepopt.
|
||||||
|
- Accept (and ignore) SystemVerilog unique/priority if.
|
||||||
|
- "read_verilog" copy inout ports in and out of functions/tasks.
|
||||||
|
- Enable single-bit vector wires in RTLIL.
|
||||||
|
|
||||||
|
* Xilinx support
|
||||||
|
- Single-port URAM mapping to support memories 2048 x 144b
|
||||||
|
|
||||||
Yosys 0.52 .. Yosys 0.53
|
Yosys 0.52 .. Yosys 0.53
|
||||||
--------------------------
|
--------------------------
|
||||||
* New commands and options
|
* New commands and options
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ passes/opt/opt_lut.cc @whitequark
|
||||||
passes/techmap/abc9*.cc @eddiehung @Ravenslofty
|
passes/techmap/abc9*.cc @eddiehung @Ravenslofty
|
||||||
backends/aiger/xaiger.cc @eddiehung
|
backends/aiger/xaiger.cc @eddiehung
|
||||||
docs/ @KrystalDelusion
|
docs/ @KrystalDelusion
|
||||||
|
docs/source/using_yosys/synthesis/abc.rst @KrystalDelusion @Ravenslofty
|
||||||
.github/workflows/*.yml @mmicko
|
.github/workflows/*.yml @mmicko
|
||||||
|
|
||||||
## External Contributors
|
## External Contributors
|
||||||
|
|
|
||||||
16
Makefile
16
Makefile
|
|
@ -160,7 +160,7 @@ ifeq ($(OS), Haiku)
|
||||||
CXXFLAGS += -D_DEFAULT_SOURCE
|
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
YOSYS_VER := 0.53+3
|
YOSYS_VER := 0.54+0
|
||||||
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
|
||||||
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
|
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
|
||||||
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
|
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
|
||||||
|
|
@ -183,7 +183,7 @@ endif
|
||||||
OBJS = kernel/version_$(GIT_REV).o
|
OBJS = kernel/version_$(GIT_REV).o
|
||||||
|
|
||||||
bumpversion:
|
bumpversion:
|
||||||
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 53c22ab.. | wc -l`/;" Makefile
|
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline db72ec3.. | wc -l`/;" Makefile
|
||||||
|
|
||||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
|
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
|
||||||
|
|
||||||
|
|
@ -204,7 +204,7 @@ endif
|
||||||
include Makefile.conf
|
include Makefile.conf
|
||||||
endif
|
endif
|
||||||
|
|
||||||
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
|
PYTHON_EXECUTABLE ?= $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
|
||||||
ifeq ($(ENABLE_PYOSYS),1)
|
ifeq ($(ENABLE_PYOSYS),1)
|
||||||
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
|
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
|
||||||
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
|
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
|
||||||
|
|
@ -455,6 +455,7 @@ endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_DEBUG),1)
|
ifeq ($(ENABLE_DEBUG),1)
|
||||||
CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS))
|
CXXFLAGS := -Og -DDEBUG $(filter-out $(OPT_LEVEL),$(CXXFLAGS))
|
||||||
|
STRIP :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_ABC),1)
|
ifeq ($(ENABLE_ABC),1)
|
||||||
|
|
@ -894,6 +895,7 @@ SH_TEST_DIRS += tests/bram
|
||||||
SH_TEST_DIRS += tests/svinterfaces
|
SH_TEST_DIRS += tests/svinterfaces
|
||||||
SH_TEST_DIRS += tests/xprop
|
SH_TEST_DIRS += tests/xprop
|
||||||
SH_TEST_DIRS += tests/select
|
SH_TEST_DIRS += tests/select
|
||||||
|
SH_TEST_DIRS += tests/peepopt
|
||||||
SH_TEST_DIRS += tests/proc
|
SH_TEST_DIRS += tests/proc
|
||||||
SH_TEST_DIRS += tests/blif
|
SH_TEST_DIRS += tests/blif
|
||||||
SH_TEST_DIRS += tests/arch
|
SH_TEST_DIRS += tests/arch
|
||||||
|
|
@ -982,20 +984,20 @@ install: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
|
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
|
||||||
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR)
|
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR)
|
||||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),)
|
ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),)
|
||||||
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys
|
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys; fi
|
||||||
endif
|
endif
|
||||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),)
|
ifneq ($(filter $(PROGRAM_PREFIX)yosys-abc,$(TARGETS)),)
|
||||||
$(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc
|
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-abc; fi
|
||||||
endif
|
endif
|
||||||
ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),)
|
ifneq ($(filter $(PROGRAM_PREFIX)yosys-filterlib,$(TARGETS)),)
|
||||||
$(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib
|
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys-filterlib; fi
|
||||||
endif
|
endif
|
||||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
|
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
|
||||||
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
|
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
|
||||||
ifeq ($(ENABLE_LIBYOSYS),1)
|
ifeq ($(ENABLE_LIBYOSYS),1)
|
||||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
|
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
|
||||||
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
|
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
|
||||||
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
|
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so; fi
|
||||||
ifeq ($(ENABLE_PYOSYS),1)
|
ifeq ($(ENABLE_PYOSYS),1)
|
||||||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
|
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
|
||||||
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
|
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ struct AigerWriter
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
AigerWriter(Module *module, bool no_sort, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module)
|
||||||
{
|
{
|
||||||
pool<SigBit> undriven_bits;
|
pool<SigBit> undriven_bits;
|
||||||
pool<SigBit> unused_bits;
|
pool<SigBit> unused_bits;
|
||||||
|
|
@ -152,6 +152,37 @@ struct AigerWriter
|
||||||
if (wire->port_input)
|
if (wire->port_input)
|
||||||
sigmap.add(wire);
|
sigmap.add(wire);
|
||||||
|
|
||||||
|
// handle ports
|
||||||
|
// provided the input_bits and output_bits don't get sorted they
|
||||||
|
// will be returned in reverse order, so add them in reverse to
|
||||||
|
// match
|
||||||
|
for (auto riter = module->ports.rbegin(); riter != module->ports.rend(); ++riter) {
|
||||||
|
auto *wire = module->wire(*riter);
|
||||||
|
for (int i = 0; i < GetSize(wire); i++)
|
||||||
|
{
|
||||||
|
SigBit wirebit(wire, i);
|
||||||
|
SigBit bit = sigmap(wirebit);
|
||||||
|
|
||||||
|
if (bit.wire == nullptr) {
|
||||||
|
if (wire->port_output) {
|
||||||
|
aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
|
||||||
|
output_bits.insert(wirebit);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wire->port_input)
|
||||||
|
input_bits.insert(bit);
|
||||||
|
|
||||||
|
if (wire->port_output) {
|
||||||
|
if (bit != wirebit)
|
||||||
|
alias_map[wirebit] = bit;
|
||||||
|
output_bits.insert(wirebit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle wires
|
||||||
for (auto wire : module->wires())
|
for (auto wire : module->wires())
|
||||||
{
|
{
|
||||||
if (wire->attributes.count(ID::init)) {
|
if (wire->attributes.count(ID::init)) {
|
||||||
|
|
@ -167,25 +198,13 @@ struct AigerWriter
|
||||||
SigBit wirebit(wire, i);
|
SigBit wirebit(wire, i);
|
||||||
SigBit bit = sigmap(wirebit);
|
SigBit bit = sigmap(wirebit);
|
||||||
|
|
||||||
if (bit.wire == nullptr) {
|
if (bit.wire == nullptr)
|
||||||
if (wire->port_output) {
|
continue;
|
||||||
aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
|
if (wire->port_input || wire->port_output)
|
||||||
output_bits.insert(wirebit);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
undriven_bits.insert(bit);
|
undriven_bits.insert(bit);
|
||||||
unused_bits.insert(bit);
|
unused_bits.insert(bit);
|
||||||
|
|
||||||
if (wire->port_input)
|
|
||||||
input_bits.insert(bit);
|
|
||||||
|
|
||||||
if (wire->port_output) {
|
|
||||||
if (bit != wirebit)
|
|
||||||
alias_map[wirebit] = bit;
|
|
||||||
output_bits.insert(wirebit);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire->width == 1) {
|
if (wire->width == 1) {
|
||||||
|
|
@ -200,12 +219,6 @@ struct AigerWriter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto bit : input_bits)
|
|
||||||
undriven_bits.erase(bit);
|
|
||||||
|
|
||||||
for (auto bit : output_bits)
|
|
||||||
unused_bits.erase(bit);
|
|
||||||
|
|
||||||
for (auto cell : module->cells())
|
for (auto cell : module->cells())
|
||||||
{
|
{
|
||||||
if (cell->type == ID($_NOT_))
|
if (cell->type == ID($_NOT_))
|
||||||
|
|
@ -343,8 +356,11 @@ struct AigerWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
init_map.sort();
|
init_map.sort();
|
||||||
input_bits.sort();
|
// we are relying here on unsorted pools iterating last-in-first-out
|
||||||
output_bits.sort();
|
if (!no_sort) {
|
||||||
|
input_bits.sort();
|
||||||
|
output_bits.sort();
|
||||||
|
}
|
||||||
not_map.sort();
|
not_map.sort();
|
||||||
ff_map.sort();
|
ff_map.sort();
|
||||||
and_map.sort();
|
and_map.sort();
|
||||||
|
|
@ -662,8 +678,7 @@ struct AigerWriter
|
||||||
f << std::endl;
|
f << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
f << stringf("c\nGenerated by %s\n", yosys_maybe_version());
|
||||||
f << stringf("c\nGenerated by %s\n", yosys_version_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_map(std::ostream &f, bool verbose_map, bool no_startoffset)
|
void write_map(std::ostream &f, bool verbose_map, bool no_startoffset)
|
||||||
|
|
@ -698,7 +713,7 @@ struct AigerWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire->port_output) {
|
if (wire->port_output) {
|
||||||
int o = ordered_outputs.at(sig[i]);
|
int o = ordered_outputs.at(SigSpec(wire, i));
|
||||||
output_lines[o] += stringf("output %d %d %s\n", o, index, log_id(wire));
|
output_lines[o] += stringf("output %d %d %s\n", o, index, log_id(wire));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -746,7 +761,7 @@ struct AigerWriter
|
||||||
{
|
{
|
||||||
json.begin_object();
|
json.begin_object();
|
||||||
json.entry("version", "Yosys Witness Aiger map");
|
json.entry("version", "Yosys Witness Aiger map");
|
||||||
json.entry("gennerator", yosys_version_str);
|
json.entry("gennerator", yosys_maybe_version());
|
||||||
|
|
||||||
json.entry("latch_count", aig_l);
|
json.entry("latch_count", aig_l);
|
||||||
json.entry("input_count", aig_i);
|
json.entry("input_count", aig_i);
|
||||||
|
|
@ -902,6 +917,9 @@ struct AigerBackend : public Backend {
|
||||||
log(" -symbols\n");
|
log(" -symbols\n");
|
||||||
log(" include a symbol table in the generated AIGER file\n");
|
log(" include a symbol table in the generated AIGER file\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -no-sort\n");
|
||||||
|
log(" don't sort input/output ports\n");
|
||||||
|
log("\n");
|
||||||
log(" -map <filename>\n");
|
log(" -map <filename>\n");
|
||||||
log(" write an extra file with port and latch symbols\n");
|
log(" write an extra file with port and latch symbols\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
|
@ -926,6 +944,7 @@ struct AigerBackend : public Backend {
|
||||||
bool zinit_mode = false;
|
bool zinit_mode = false;
|
||||||
bool miter_mode = false;
|
bool miter_mode = false;
|
||||||
bool symbols_mode = false;
|
bool symbols_mode = false;
|
||||||
|
bool no_sort = false;
|
||||||
bool verbose_map = false;
|
bool verbose_map = false;
|
||||||
bool imode = false;
|
bool imode = false;
|
||||||
bool omode = false;
|
bool omode = false;
|
||||||
|
|
@ -956,6 +975,10 @@ struct AigerBackend : public Backend {
|
||||||
symbols_mode = true;
|
symbols_mode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-no-sort") {
|
||||||
|
no_sort = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
|
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
|
||||||
map_filename = args[++argidx];
|
map_filename = args[++argidx];
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1009,7 +1032,7 @@ struct AigerBackend : public Backend {
|
||||||
if (!top_module->memories.empty())
|
if (!top_module->memories.empty())
|
||||||
log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", log_id(top_module));
|
log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", log_id(top_module));
|
||||||
|
|
||||||
AigerWriter writer(top_module, zinit_mode, imode, omode, bmode, lmode);
|
AigerWriter writer(top_module, no_sort, zinit_mode, imode, omode, bmode, lmode);
|
||||||
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
|
writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode);
|
||||||
|
|
||||||
if (!map_filename.empty()) {
|
if (!map_filename.empty()) {
|
||||||
|
|
|
||||||
|
|
@ -671,7 +671,7 @@ struct XAigerWriter
|
||||||
//f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
|
//f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
|
||||||
//f.write(buffer_str.data(), buffer_str.size());
|
//f.write(buffer_str.data(), buffer_str.size());
|
||||||
|
|
||||||
f << stringf("Generated by %s\n", yosys_version_str);
|
f << stringf("Generated by %s\n", yosys_maybe_version());
|
||||||
|
|
||||||
design->scratchpad_set_int("write_xaiger.num_ands", and_map.size());
|
design->scratchpad_set_int("write_xaiger.num_ands", and_map.size());
|
||||||
design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size());
|
design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size());
|
||||||
|
|
|
||||||
|
|
@ -649,7 +649,7 @@ struct BlifBackend : public Backend {
|
||||||
if (module->get_bool_attribute(ID::top))
|
if (module->get_bool_attribute(ID::top))
|
||||||
top_module_name = module->name.str();
|
top_module_name = module->name.str();
|
||||||
|
|
||||||
*f << stringf("# Generated by %s\n", yosys_version_str);
|
*f << stringf("# Generated by %s\n", yosys_maybe_version());
|
||||||
|
|
||||||
std::vector<RTLIL::Module*> mod_list;
|
std::vector<RTLIL::Module*> mod_list;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1499,7 +1499,7 @@ struct BtorWorker
|
||||||
{
|
{
|
||||||
ywmap_json.begin_object();
|
ywmap_json.begin_object();
|
||||||
ywmap_json.entry("version", "Yosys Witness BTOR map");
|
ywmap_json.entry("version", "Yosys Witness BTOR map");
|
||||||
ywmap_json.entry("generator", yosys_version_str);
|
ywmap_json.entry("generator", yosys_maybe_version());
|
||||||
|
|
||||||
ywmap_json.name("clocks");
|
ywmap_json.name("clocks");
|
||||||
ywmap_json.begin_array();
|
ywmap_json.begin_array();
|
||||||
|
|
@ -1613,7 +1613,7 @@ struct BtorBackend : public Backend {
|
||||||
log_cmd_error("No top module found.\n");
|
log_cmd_error("No top module found.\n");
|
||||||
|
|
||||||
*f << stringf("; BTOR description generated by %s for module %s.\n",
|
*f << stringf("; BTOR description generated by %s for module %s.\n",
|
||||||
yosys_version_str, log_id(topmod));
|
yosys_maybe_version(), log_id(topmod));
|
||||||
|
|
||||||
BtorWorker(*f, topmod, verbose, single_bad, cover_mode, print_internal_names, info_filename, ywmap_filename);
|
BtorWorker(*f, topmod, verbose, single_bad, cover_mode, print_internal_names, info_filename, ywmap_filename);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2429,8 +2429,6 @@ struct CxxrtlWorker {
|
||||||
inc_indent();
|
inc_indent();
|
||||||
for (auto wire : module->wires()) {
|
for (auto wire : module->wires()) {
|
||||||
const auto &debug_wire_type = debug_wire_types[wire];
|
const auto &debug_wire_type = debug_wire_types[wire];
|
||||||
if (!wire->name.isPublic())
|
|
||||||
continue;
|
|
||||||
count_public_wires++;
|
count_public_wires++;
|
||||||
switch (debug_wire_type.type) {
|
switch (debug_wire_type.type) {
|
||||||
case WireType::BUFFERED:
|
case WireType::BUFFERED:
|
||||||
|
|
@ -2438,6 +2436,9 @@ struct CxxrtlWorker {
|
||||||
// Member wire
|
// Member wire
|
||||||
std::vector<std::string> flags;
|
std::vector<std::string> flags;
|
||||||
|
|
||||||
|
if (!wire->name.isPublic())
|
||||||
|
flags.push_back("GENERATED");
|
||||||
|
|
||||||
if (wire->port_input && wire->port_output)
|
if (wire->port_input && wire->port_output)
|
||||||
flags.push_back("INOUT");
|
flags.push_back("INOUT");
|
||||||
else if (wire->port_output)
|
else if (wire->port_output)
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,10 @@ enum cxxrtl_flag {
|
||||||
// node, such as inputs and dangling wires.
|
// node, such as inputs and dangling wires.
|
||||||
CXXRTL_UNDRIVEN = 1 << 4,
|
CXXRTL_UNDRIVEN = 1 << 4,
|
||||||
|
|
||||||
|
// Generated correspond to netlist nodes that correspond to state with an internal name, that
|
||||||
|
// need to be saved, but wouldn't otherwise have a debug item generated.
|
||||||
|
CXXRTL_GENERATED = 1 << 5,
|
||||||
|
|
||||||
// More object flags may be added in the future, but the existing ones will never change.
|
// More object flags may be added in the future, but the existing ones will never change.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1294,6 +1294,7 @@ struct debug_item : ::cxxrtl_object {
|
||||||
DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC,
|
DRIVEN_SYNC = CXXRTL_DRIVEN_SYNC,
|
||||||
DRIVEN_COMB = CXXRTL_DRIVEN_COMB,
|
DRIVEN_COMB = CXXRTL_DRIVEN_COMB,
|
||||||
UNDRIVEN = CXXRTL_UNDRIVEN,
|
UNDRIVEN = CXXRTL_UNDRIVEN,
|
||||||
|
GENERATED = CXXRTL_GENERATED,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {}
|
debug_item(const ::cxxrtl_object &object) : cxxrtl_object(object) {}
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,8 @@ struct EdifBackend : public Backend {
|
||||||
*f << stringf(" (edifVersion 2 0 0)\n");
|
*f << stringf(" (edifVersion 2 0 0)\n");
|
||||||
*f << stringf(" (edifLevel 0)\n");
|
*f << stringf(" (edifLevel 0)\n");
|
||||||
*f << stringf(" (keywordMap (keywordLevel 0))\n");
|
*f << stringf(" (keywordMap (keywordLevel 0))\n");
|
||||||
*f << stringf(" (comment \"Generated by %s\")\n", yosys_version_str);
|
|
||||||
|
*f << stringf(" (comment \"Generated by %s\")\n", yosys_maybe_version());
|
||||||
|
|
||||||
*f << stringf(" (external LIB\n");
|
*f << stringf(" (external LIB\n");
|
||||||
*f << stringf(" (edifLevel 0)\n");
|
*f << stringf(" (edifLevel 0)\n");
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ struct JnyWriter
|
||||||
|
|
||||||
f << "{\n";
|
f << "{\n";
|
||||||
f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/main/misc/jny.schema.json\",\n";
|
f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/main/misc/jny.schema.json\",\n";
|
||||||
f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_version_str).c_str());
|
f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_maybe_version()).c_str());
|
||||||
f << " \"version\": \"0.0.1\",\n";
|
f << " \"version\": \"0.0.1\",\n";
|
||||||
f << " \"invocation\": \"" << escape_string(invk) << "\",\n";
|
f << " \"invocation\": \"" << escape_string(invk) << "\",\n";
|
||||||
f << " \"features\": [";
|
f << " \"features\": [";
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,7 @@ struct JsonWriter
|
||||||
design->sort();
|
design->sort();
|
||||||
|
|
||||||
f << stringf("{\n");
|
f << stringf("{\n");
|
||||||
f << stringf(" \"creator\": %s,\n", get_string(yosys_version_str).c_str());
|
f << stringf(" \"creator\": %s,\n", get_string(yosys_maybe_version()).c_str());
|
||||||
f << stringf(" \"modules\": {\n");
|
f << stringf(" \"modules\": {\n");
|
||||||
vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
|
vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
|
||||||
bool first_module = true;
|
bool first_module = true;
|
||||||
|
|
|
||||||
|
|
@ -459,7 +459,8 @@ struct RTLILBackend : public Backend {
|
||||||
design->sort();
|
design->sort();
|
||||||
|
|
||||||
log("Output filename: %s\n", filename.c_str());
|
log("Output filename: %s\n", filename.c_str());
|
||||||
*f << stringf("# Generated by %s\n", yosys_version_str);
|
|
||||||
|
*f << stringf("# Generated by %s\n", yosys_maybe_version());
|
||||||
RTLIL_BACKEND::dump_design(*f, design, selected, true, false);
|
RTLIL_BACKEND::dump_design(*f, design, selected, true, false);
|
||||||
}
|
}
|
||||||
} RTLILBackend;
|
} RTLILBackend;
|
||||||
|
|
|
||||||
|
|
@ -1831,7 +1831,7 @@ struct Smt2Backend : public Backend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_version_str);
|
*f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_maybe_version());
|
||||||
|
|
||||||
if (!bvmode)
|
if (!bvmode)
|
||||||
*f << stringf("; yosys-smt2-nobv\n");
|
*f << stringf("; yosys-smt2-nobv\n");
|
||||||
|
|
|
||||||
|
|
@ -797,7 +797,7 @@ struct SmvBackend : public Backend {
|
||||||
if (module == nullptr)
|
if (module == nullptr)
|
||||||
log_error("Module '%s' not found.\n", stmt[1].c_str());
|
log_error("Module '%s' not found.\n", stmt[1].c_str());
|
||||||
|
|
||||||
*f << stringf("-- SMV description generated by %s\n", yosys_version_str);
|
*f << stringf("-- SMV description generated by %s\n", yosys_maybe_version());
|
||||||
|
|
||||||
log("Creating SMV representation of module %s.\n", log_id(module));
|
log("Creating SMV representation of module %s.\n", log_id(module));
|
||||||
SmvWorker worker(module, verbose, *f);
|
SmvWorker worker(module, verbose, *f);
|
||||||
|
|
@ -816,7 +816,7 @@ struct SmvBackend : public Backend {
|
||||||
|
|
||||||
if (!modules.empty())
|
if (!modules.empty())
|
||||||
{
|
{
|
||||||
*f << stringf("-- SMV description generated by %s\n", yosys_version_str);
|
*f << stringf("-- SMV description generated by %s\n", yosys_maybe_version());
|
||||||
|
|
||||||
for (auto module : modules) {
|
for (auto module : modules) {
|
||||||
log("Creating SMV representation of module %s.\n", log_id(module));
|
log("Creating SMV representation of module %s.\n", log_id(module));
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ struct SpiceBackend : public Backend {
|
||||||
if (module->get_bool_attribute(ID::top))
|
if (module->get_bool_attribute(ID::top))
|
||||||
top_module_name = module->name.str();
|
top_module_name = module->name.str();
|
||||||
|
|
||||||
*f << stringf("* SPICE netlist generated by %s\n", yosys_version_str);
|
*f << stringf("* SPICE netlist generated by %s\n", yosys_maybe_version());
|
||||||
*f << stringf("\n");
|
*f << stringf("\n");
|
||||||
|
|
||||||
for (auto module : design->modules())
|
for (auto module : design->modules())
|
||||||
|
|
|
||||||
|
|
@ -383,6 +383,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString,
|
||||||
if (attr2comment)
|
if (attr2comment)
|
||||||
as_comment = true;
|
as_comment = true;
|
||||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||||
|
if (it->first == ID::single_bit_vector) continue;
|
||||||
if (it->first == ID::init && regattr) continue;
|
if (it->first == ID::init && regattr) continue;
|
||||||
f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str());
|
f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str());
|
||||||
f << stringf(" = ");
|
f << stringf(" = ");
|
||||||
|
|
@ -419,6 +420,9 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
|
||||||
range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
|
range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
|
||||||
else
|
else
|
||||||
range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
|
range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
|
||||||
|
} else {
|
||||||
|
if (wire->attributes.count(ID::single_bit_vector))
|
||||||
|
range = stringf(" [%d:%d]", wire->start_offset, wire->start_offset);
|
||||||
}
|
}
|
||||||
if (wire->port_input && !wire->port_output)
|
if (wire->port_input && !wire->port_output)
|
||||||
f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
||||||
|
|
@ -2596,7 +2600,8 @@ struct VerilogBackend : public Backend {
|
||||||
|
|
||||||
design->sort();
|
design->sort();
|
||||||
|
|
||||||
*f << stringf("/* Generated by %s */\n", yosys_version_str);
|
*f << stringf("/* Generated by %s */\n", yosys_maybe_version());
|
||||||
|
|
||||||
for (auto module : design->modules()) {
|
for (auto module : design->modules()) {
|
||||||
if (module->get_blackbox_attribute() != blackboxes)
|
if (module->get_blackbox_attribute() != blackboxes)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ circuits.
|
||||||
Tools exist to synthesize high level code (usually in the form of C/C++/SystemC
|
Tools exist to synthesize high level code (usually in the form of C/C++/SystemC
|
||||||
code with additional metadata) to behavioural HDL code (usually in the form of
|
code with additional metadata) to behavioural HDL code (usually in the form of
|
||||||
Verilog or VHDL code). Aside from the many commercial tools for high level
|
Verilog or VHDL code). Aside from the many commercial tools for high level
|
||||||
synthesis there are also a number of FOSS tools for high level synthesis .
|
synthesis there are also a number of FOSS tools for high level synthesis.
|
||||||
|
|
||||||
Behavioural level
|
Behavioural level
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
@ -185,7 +185,7 @@ advantage that it has a unique normalized form. The latter has much better worst
|
||||||
case performance and is therefore better suited for the synthesis of large logic
|
case performance and is therefore better suited for the synthesis of large logic
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
Good FOSS tools exists for multi-level logic synthesis .
|
Good FOSS tools exists for multi-level logic synthesis.
|
||||||
|
|
||||||
Yosys contains basic logic synthesis functionality but can also use ABC for the
|
Yosys contains basic logic synthesis functionality but can also use ABC for the
|
||||||
logic synthesis step. Using ABC is recommended.
|
logic synthesis step. Using ABC is recommended.
|
||||||
|
|
@ -221,7 +221,7 @@ design description as input and generates an RTL, logical gate or physical gate
|
||||||
level description of the design as output. Yosys' main strengths are behavioural
|
level description of the design as output. Yosys' main strengths are behavioural
|
||||||
and RTL synthesis. A wide range of commands (synthesis passes) exist within
|
and RTL synthesis. A wide range of commands (synthesis passes) exist within
|
||||||
Yosys that can be used to perform a wide range of synthesis tasks within the
|
Yosys that can be used to perform a wide range of synthesis tasks within the
|
||||||
domain of behavioural, rtl and logic synthesis. Yosys is designed to be
|
domain of behavioural, RTL and logic synthesis. Yosys is designed to be
|
||||||
extensible and therefore is a good basis for implementing custom synthesis tools
|
extensible and therefore is a good basis for implementing custom synthesis tools
|
||||||
for specialised tasks.
|
for specialised tasks.
|
||||||
|
|
||||||
|
|
@ -572,7 +572,7 @@ of lexical tokens given in :numref:`Tab. %s <tab:Basics_tokens>`.
|
||||||
TOK_SEMICOLON \-
|
TOK_SEMICOLON \-
|
||||||
============== ===============
|
============== ===============
|
||||||
|
|
||||||
The lexer is usually generated by a lexer generator (e.g. flex ) from a
|
The lexer is usually generated by a lexer generator (e.g. flex) from a
|
||||||
description file that is using regular expressions to specify the text pattern
|
description file that is using regular expressions to specify the text pattern
|
||||||
that should match the individual tokens.
|
that should match the individual tokens.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import os
|
||||||
project = 'YosysHQ Yosys'
|
project = 'YosysHQ Yosys'
|
||||||
author = 'YosysHQ GmbH'
|
author = 'YosysHQ GmbH'
|
||||||
copyright ='2025 YosysHQ GmbH'
|
copyright ='2025 YosysHQ GmbH'
|
||||||
yosys_ver = "0.53"
|
yosys_ver = "0.54"
|
||||||
|
|
||||||
# select HTML theme
|
# select HTML theme
|
||||||
html_theme = 'furo-ys'
|
html_theme = 'furo-ys'
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ contain bits that are not 0 or 1 (i.e. ``x`` or ``z``). Ordinary 32-bit
|
||||||
constants are written using decimal numbers.
|
constants are written using decimal numbers.
|
||||||
|
|
||||||
Single-bit signals are shown as thin arrows pointing from the driver to the
|
Single-bit signals are shown as thin arrows pointing from the driver to the
|
||||||
load. Signals that are multiple bits wide are shown as think arrows.
|
load. Signals that are multiple bits wide are shown as thick arrows.
|
||||||
|
|
||||||
Finally *processes* are shown in boxes with round corners. Processes are Yosys'
|
Finally *processes* are shown in boxes with round corners. Processes are Yosys'
|
||||||
internal representation of the decision-trees and synchronization events
|
internal representation of the decision-trees and synchronization events
|
||||||
|
|
|
||||||
|
|
@ -176,5 +176,6 @@ implemented as whiteboxes too.
|
||||||
Boxes are arguably the biggest advantage that ABC9 has over ABC: by being aware
|
Boxes are arguably the biggest advantage that ABC9 has over ABC: by being aware
|
||||||
of carry chains and DSPs, it avoids optimising for a path that isn't the actual
|
of carry chains and DSPs, it avoids optimising for a path that isn't the actual
|
||||||
critical path, while the generally-longer paths result in ABC9 being able to
|
critical path, while the generally-longer paths result in ABC9 being able to
|
||||||
reduce design area by mapping other logic to larger-but-slower cells.
|
reduce design area by mapping other logic to slower cells with greater logic
|
||||||
|
density.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -626,7 +626,7 @@ pass and the passes it launches:
|
||||||
| This pass replaces the ``RTLIL::SyncRule``\ s to d-type flip-flops (with
|
| This pass replaces the ``RTLIL::SyncRule``\ s to d-type flip-flops (with
|
||||||
asynchronous resets if necessary).
|
asynchronous resets if necessary).
|
||||||
|
|
||||||
- | `proc_dff`
|
- | `proc_memwr`
|
||||||
| This pass replaces the ``RTLIL::MemWriteAction``\ s with `$memwr` cells.
|
| This pass replaces the ``RTLIL::MemWriteAction``\ s with `$memwr` cells.
|
||||||
|
|
||||||
- | `proc_clean`
|
- | `proc_clean`
|
||||||
|
|
|
||||||
|
|
@ -375,3 +375,9 @@ from SystemVerilog:
|
||||||
ports are inputs or outputs are supported.
|
ports are inputs or outputs are supported.
|
||||||
|
|
||||||
- Assignments within expressions are supported.
|
- Assignments within expressions are supported.
|
||||||
|
|
||||||
|
- The ``unique``, ``unique0``, and ``priority`` SystemVerilog keywords are
|
||||||
|
accepted on ``if`` and ``case`` conditionals. (Those keywords are currently
|
||||||
|
handled in the same way as their equivalent ``full_case`` and
|
||||||
|
``parallel_case`` attributes on ``case`` statements, and checked
|
||||||
|
for syntactic validity but otherwise ignored on ``if`` statements.)
|
||||||
|
|
|
||||||
|
|
@ -1446,6 +1446,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
wire->port_input = is_input;
|
wire->port_input = is_input;
|
||||||
wire->port_output = is_output;
|
wire->port_output = is_output;
|
||||||
wire->upto = range_swapped;
|
wire->upto = range_swapped;
|
||||||
|
|
||||||
wire->is_signed = is_signed;
|
wire->is_signed = is_signed;
|
||||||
|
|
||||||
for (auto &attr : attributes) {
|
for (auto &attr : attributes) {
|
||||||
|
|
|
||||||
|
|
@ -1433,6 +1433,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
||||||
current_ast_mod->children.push_back(wnode);
|
current_ast_mod->children.push_back(wnode);
|
||||||
}
|
}
|
||||||
basic_prep = true;
|
basic_prep = true;
|
||||||
|
is_custom_type = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1932,6 +1933,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
||||||
// Prepare replacement node.
|
// Prepare replacement node.
|
||||||
newNode = template_node->clone();
|
newNode = template_node->clone();
|
||||||
newNode->str = str;
|
newNode->str = str;
|
||||||
|
if (newNode->attributes.count(ID::wiretype))
|
||||||
|
delete newNode->attributes[ID::wiretype];
|
||||||
newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
|
newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
|
||||||
newNode->is_input = is_input;
|
newNode->is_input = is_input;
|
||||||
newNode->is_output = is_output;
|
newNode->is_output = is_output;
|
||||||
|
|
@ -2084,6 +2087,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
||||||
std::swap(range_left, range_right);
|
std::swap(range_left, range_right);
|
||||||
range_swapped = force_upto;
|
range_swapped = force_upto;
|
||||||
}
|
}
|
||||||
|
if (range_left == range_right && !attributes.count(ID::single_bit_vector))
|
||||||
|
set_attribute(ID::single_bit_vector, mkconst_int(1, false));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!range_valid)
|
if (!range_valid)
|
||||||
|
|
@ -2092,6 +2097,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
||||||
range_swapped = false;
|
range_swapped = false;
|
||||||
range_left = 0;
|
range_left = 0;
|
||||||
range_right = 0;
|
range_right = 0;
|
||||||
|
if (attributes.count(ID::single_bit_vector)) {
|
||||||
|
delete attributes[ID::single_bit_vector];
|
||||||
|
attributes.erase(ID::single_bit_vector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4091,16 +4100,24 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
delete arg;
|
delete arg;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *wire_id = new AstNode(AST_IDENTIFIER);
|
AstNode *wire_id = new AstNode(AST_IDENTIFIER);
|
||||||
wire_id->str = wire->str;
|
wire_id->str = wire->str;
|
||||||
AstNode *assign = child->is_input ?
|
|
||||||
new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
|
if (child->is_input) {
|
||||||
new AstNode(AST_ASSIGN_EQ, arg, wire_id);
|
AstNode *assign = new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg->clone());
|
||||||
assign->children[0]->was_checked = true;
|
assign->children[0]->was_checked = true;
|
||||||
if (child->is_input)
|
|
||||||
new_stmts.push_back(assign);
|
new_stmts.push_back(assign);
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (child->is_output) {
|
||||||
|
AstNode *assign = new AstNode(AST_ASSIGN_EQ, arg->clone(), wire_id->clone());
|
||||||
|
assign->children[0]->was_checked = true;
|
||||||
output_assignments.push_back(assign);
|
output_assignments.push_back(assign);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete arg;
|
||||||
|
delete wire_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1557,6 +1557,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
|
wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());
|
||||||
wire->upto = portbus->IsUp();
|
wire->upto = portbus->IsUp();
|
||||||
import_attributes(wire->attributes, portbus, nl, portbus->Size());
|
import_attributes(wire->attributes, portbus, nl, portbus->Size());
|
||||||
|
if (portbus->Size() == 1)
|
||||||
|
wire->set_bool_attribute(ID::single_bit_vector);
|
||||||
SetIter si ;
|
SetIter si ;
|
||||||
Port *port ;
|
Port *port ;
|
||||||
FOREACH_PORT_OF_PORTBUS(portbus, si, port) {
|
FOREACH_PORT_OF_PORTBUS(portbus, si, port) {
|
||||||
|
|
@ -1755,6 +1757,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
import_attributes(wire->attributes, netbus, nl, netbus->Size());
|
import_attributes(wire->attributes, netbus, nl, netbus->Size());
|
||||||
|
if (netbus->Size() == 1)
|
||||||
|
wire->set_bool_attribute(ID::single_bit_vector);
|
||||||
|
|
||||||
RTLIL::Const initval = Const(State::Sx, GetSize(wire));
|
RTLIL::Const initval = Const(State::Sx, GetSize(wire));
|
||||||
bool initval_valid = false;
|
bool initval_valid = false;
|
||||||
|
|
@ -3485,6 +3489,14 @@ struct VerificPass : public Pass {
|
||||||
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
|
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
|
||||||
Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
|
Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
|
||||||
|
|
||||||
|
// Downgrade warnings about things that are normal
|
||||||
|
// VERIFIC-WARNING [VERI-1209] foo.sv:98: expression size 7 truncated to fit in target size 6
|
||||||
|
Message::SetMessageType("VERI-1209", VERIFIC_INFO);
|
||||||
|
// VERIFIC-WARNING [VERI-1142] foo.sv:55: system task 'display' is ignored for synthesis
|
||||||
|
Message::SetMessageType("VERI-1142", VERIFIC_INFO);
|
||||||
|
// VERIFIC-WARNING [VERI-2418] foo.svh:503: parameter 'all_cfgs_gp' declared inside package 'bp_common_pkg' shall be treated as localparam
|
||||||
|
Message::SetMessageType("VERI-2418", VERIFIC_INFO);
|
||||||
|
|
||||||
// https://github.com/YosysHQ/yosys/issues/1055
|
// https://github.com/YosysHQ/yosys/issues/1055
|
||||||
RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ;
|
RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -3543,6 +3555,9 @@ struct VerificPass : public Pass {
|
||||||
} else if (Strings::compare(args[argidx].c_str(), "warnings")) {
|
} else if (Strings::compare(args[argidx].c_str(), "warnings")) {
|
||||||
Message::SetAllMessageType(VERIFIC_WARNING, new_type);
|
Message::SetAllMessageType(VERIFIC_WARNING, new_type);
|
||||||
} else if (Strings::compare(args[argidx].c_str(), "infos")) {
|
} else if (Strings::compare(args[argidx].c_str(), "infos")) {
|
||||||
|
Message::SetMessageType("VERI-1209", new_type);
|
||||||
|
Message::SetMessageType("VERI-1142", new_type);
|
||||||
|
Message::SetMessageType("VERI-2418", new_type);
|
||||||
Message::SetAllMessageType(VERIFIC_INFO, new_type);
|
Message::SetAllMessageType(VERIFIC_INFO, new_type);
|
||||||
} else if (Strings::compare(args[argidx].c_str(), "comments")) {
|
} else if (Strings::compare(args[argidx].c_str(), "comments")) {
|
||||||
Message::SetAllMessageType(VERIFIC_COMMENT, new_type);
|
Message::SetAllMessageType(VERIFIC_COMMENT, new_type);
|
||||||
|
|
|
||||||
|
|
@ -336,7 +336,8 @@ static AstNode *addIncOrDecExpr(AstNode *lhs, dict<IdString, AstNode*> *attr, AS
|
||||||
log_assert(stmt->type == AST_ASSIGN_EQ);
|
log_assert(stmt->type == AST_ASSIGN_EQ);
|
||||||
AstNode *expr = stmt->children[0]->clone();
|
AstNode *expr = stmt->children[0]->clone();
|
||||||
if (undo) {
|
if (undo) {
|
||||||
AstNode *minus_one = AstNode::mkconst_int(-1, true, 1);
|
AstNode *one = AstNode::mkconst_int(1, false, 1);
|
||||||
|
AstNode *minus_one = new AstNode(AST_NEG, one);
|
||||||
expr = new AstNode(op, expr, minus_one);
|
expr = new AstNode(op, expr, minus_one);
|
||||||
}
|
}
|
||||||
SET_AST_NODE_LOC(expr, begin, end);
|
SET_AST_NODE_LOC(expr, begin, end);
|
||||||
|
|
@ -426,7 +427,7 @@ static const AstNode *addAsgnBinopStmt(dict<IdString, AstNode*> *attr, AstNode *
|
||||||
%type <boolean> opt_property always_comb_or_latch always_or_always_ff
|
%type <boolean> opt_property always_comb_or_latch always_or_always_ff
|
||||||
%type <boolean> opt_signedness_default_signed opt_signedness_default_unsigned
|
%type <boolean> opt_signedness_default_signed opt_signedness_default_unsigned
|
||||||
%type <integer> integer_atom_type integer_vector_type
|
%type <integer> integer_atom_type integer_vector_type
|
||||||
%type <al> attr case_attr
|
%type <al> attr if_attr case_attr
|
||||||
%type <ast> struct_union
|
%type <ast> struct_union
|
||||||
%type <ast_node_type> asgn_binop inc_or_dec_op
|
%type <ast_node_type> asgn_binop inc_or_dec_op
|
||||||
%type <ast> genvar_identifier
|
%type <ast> genvar_identifier
|
||||||
|
|
@ -1855,7 +1856,7 @@ struct_decl:
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
struct_type: struct_union { astbuf2 = $1; } struct_body { $$ = astbuf2; }
|
struct_type: struct_union { astbuf2 = $1; astbuf2->is_custom_type = true; } struct_body { $$ = astbuf2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
struct_union:
|
struct_union:
|
||||||
|
|
@ -2871,7 +2872,7 @@ behavioral_stmt:
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
} |
|
} |
|
||||||
attr TOK_IF '(' expr ')' {
|
if_attr TOK_IF '(' expr ')' {
|
||||||
AstNode *node = new AstNode(AST_CASE);
|
AstNode *node = new AstNode(AST_CASE);
|
||||||
AstNode *block = new AstNode(AST_BLOCK);
|
AstNode *block = new AstNode(AST_BLOCK);
|
||||||
AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block);
|
AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block);
|
||||||
|
|
@ -2901,6 +2902,29 @@ behavioral_stmt:
|
||||||
ast_stack.pop_back();
|
ast_stack.pop_back();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if_attr:
|
||||||
|
attr {
|
||||||
|
$$ = $1;
|
||||||
|
} |
|
||||||
|
attr TOK_UNIQUE0 {
|
||||||
|
AstNode *context = ast_stack.back();
|
||||||
|
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) )
|
||||||
|
frontend_verilog_yyerror("unique0 keyword cannot be used for 'else if' branch.");
|
||||||
|
$$ = $1; // accept unique0 keyword, but ignore it for now
|
||||||
|
} |
|
||||||
|
attr TOK_PRIORITY {
|
||||||
|
AstNode *context = ast_stack.back();
|
||||||
|
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) )
|
||||||
|
frontend_verilog_yyerror("priority keyword cannot be used for 'else if' branch.");
|
||||||
|
$$ = $1; // accept priority keyword, but ignore it for now
|
||||||
|
} |
|
||||||
|
attr TOK_UNIQUE {
|
||||||
|
AstNode *context = ast_stack.back();
|
||||||
|
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) )
|
||||||
|
frontend_verilog_yyerror("unique keyword cannot be used for 'else if' branch.");
|
||||||
|
$$ = $1; // accept unique keyword, but ignore it for now
|
||||||
|
};
|
||||||
|
|
||||||
case_attr:
|
case_attr:
|
||||||
attr {
|
attr {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
|
|
@ -2948,6 +2972,7 @@ behavioral_stmt_list:
|
||||||
optional_else:
|
optional_else:
|
||||||
TOK_ELSE {
|
TOK_ELSE {
|
||||||
AstNode *block = new AstNode(AST_BLOCK);
|
AstNode *block = new AstNode(AST_BLOCK);
|
||||||
|
block->attributes[ID::promoted_if] = AstNode::mkconst_int(1, false );
|
||||||
AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block);
|
AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block);
|
||||||
SET_AST_NODE_LOC(cond, @1, @1);
|
SET_AST_NODE_LOC(cond, @1, @1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,7 @@ X(parameter)
|
||||||
X(PORTID)
|
X(PORTID)
|
||||||
X(PRIORITY)
|
X(PRIORITY)
|
||||||
X(PRIORITY_MASK)
|
X(PRIORITY_MASK)
|
||||||
|
X(promoted_if)
|
||||||
X(Q)
|
X(Q)
|
||||||
X(R)
|
X(R)
|
||||||
X(ram_block)
|
X(ram_block)
|
||||||
|
|
@ -184,6 +185,7 @@ X(romstyle)
|
||||||
X(S)
|
X(S)
|
||||||
X(SET)
|
X(SET)
|
||||||
X(SET_POLARITY)
|
X(SET_POLARITY)
|
||||||
|
X(single_bit_vector)
|
||||||
X(SIZE)
|
X(SIZE)
|
||||||
X(SRC)
|
X(SRC)
|
||||||
X(src)
|
X(src)
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,7 @@ int main(int argc, char **argv)
|
||||||
options.add_options("logging")
|
options.add_options("logging")
|
||||||
("Q", "suppress printing of banner (copyright, disclaimer, version)")
|
("Q", "suppress printing of banner (copyright, disclaimer, version)")
|
||||||
("T", "suppress printing of footer (log hash, version, timing statistics)")
|
("T", "suppress printing of footer (log hash, version, timing statistics)")
|
||||||
|
("no-version", "suppress writing out Yosys version anywhere excluding -V, --version")
|
||||||
("q,quiet", "quiet operation. Only write warnings and error messages to console. " \
|
("q,quiet", "quiet operation. Only write warnings and error messages to console. " \
|
||||||
"Use this option twice to also quiet warning messages")
|
"Use this option twice to also quiet warning messages")
|
||||||
("v,verbose", "print log headers up to <level> to the console. " \
|
("v,verbose", "print log headers up to <level> to the console. " \
|
||||||
|
|
@ -318,6 +319,7 @@ int main(int argc, char **argv)
|
||||||
if (result.count("A")) call_abort = true;
|
if (result.count("A")) call_abort = true;
|
||||||
if (result.count("Q")) print_banner = false;
|
if (result.count("Q")) print_banner = false;
|
||||||
if (result.count("T")) print_stats = false;
|
if (result.count("T")) print_stats = false;
|
||||||
|
if (result.count("no-version")) yosys_write_versions = false;
|
||||||
if (result.count("V")) {
|
if (result.count("V")) {
|
||||||
std::cout << yosys_version_str << std::endl;
|
std::cout << yosys_version_str << std::endl;
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
@ -691,7 +693,7 @@ int main(int argc, char **argv)
|
||||||
stats_divider.c_str(), ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
|
stats_divider.c_str(), ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
|
||||||
ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec, meminfo.c_str());
|
ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec, meminfo.c_str());
|
||||||
#endif
|
#endif
|
||||||
log("%s\n", yosys_version_str);
|
log("%s\n", yosys_maybe_version());
|
||||||
|
|
||||||
int64_t total_ns = 0;
|
int64_t total_ns = 0;
|
||||||
std::set<tuple<int64_t, int, std::string>> timedat;
|
std::set<tuple<int64_t, int, std::string>> timedat;
|
||||||
|
|
@ -731,7 +733,7 @@ int main(int argc, char **argv)
|
||||||
log_error("Can't open performance log file for writing: %s\n", strerror(errno));
|
log_error("Can't open performance log file for writing: %s\n", strerror(errno));
|
||||||
|
|
||||||
fprintf(f, "{\n");
|
fprintf(f, "{\n");
|
||||||
fprintf(f, " \"generator\": \"%s\",\n", yosys_version_str);
|
fprintf(f, " \"generator\": \"%s\",\n", yosys_maybe_version());
|
||||||
fprintf(f, " \"total_ns\": %" PRIu64 ",\n", total_ns);
|
fprintf(f, " \"total_ns\": %" PRIu64 ",\n", total_ns);
|
||||||
fprintf(f, " \"passes\": {");
|
fprintf(f, " \"passes\": {");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,7 @@ static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandl
|
||||||
void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
|
void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
|
||||||
{
|
{
|
||||||
if (pnt_time > end_time || !pnt_value) return;
|
if (pnt_time > end_time || !pnt_value) return;
|
||||||
|
if (curr_cycle > last_cycle) return;
|
||||||
// if we are past the timestamp
|
// if we are past the timestamp
|
||||||
bool is_clock = false;
|
bool is_clock = false;
|
||||||
if (!all_samples) {
|
if (!all_samples) {
|
||||||
|
|
@ -225,6 +226,7 @@ void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_faci
|
||||||
if (pnt_time > last_time) {
|
if (pnt_time > last_time) {
|
||||||
if (all_samples) {
|
if (all_samples) {
|
||||||
callback(last_time);
|
callback(last_time);
|
||||||
|
curr_cycle++;
|
||||||
last_time = pnt_time;
|
last_time = pnt_time;
|
||||||
} else {
|
} else {
|
||||||
if (is_clock) {
|
if (is_clock) {
|
||||||
|
|
@ -232,6 +234,7 @@ void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_faci
|
||||||
std::string prev = past_data[pnt_facidx];
|
std::string prev = past_data[pnt_facidx];
|
||||||
if ((prev!="1" && val=="1") || (prev!="0" && val=="0")) {
|
if ((prev!="1" && val=="1") || (prev!="0" && val=="0")) {
|
||||||
callback(last_time);
|
callback(last_time);
|
||||||
|
curr_cycle++;
|
||||||
last_time = pnt_time;
|
last_time = pnt_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -241,12 +244,14 @@ void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_faci
|
||||||
last_data[pnt_facidx] = std::string((const char *)pnt_value);
|
last_data[pnt_facidx] = std::string((const char *)pnt_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start, uint64_t end, CallbackFunction cb)
|
void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start, uint64_t end, unsigned int end_cycle, CallbackFunction cb)
|
||||||
{
|
{
|
||||||
clk_signals = signal;
|
clk_signals = signal;
|
||||||
callback = cb;
|
callback = cb;
|
||||||
start_time = start;
|
start_time = start;
|
||||||
end_time = end;
|
end_time = end;
|
||||||
|
curr_cycle = 0;
|
||||||
|
last_cycle = end_cycle;
|
||||||
last_data.clear();
|
last_data.clear();
|
||||||
last_time = start_time;
|
last_time = start_time;
|
||||||
past_data.clear();
|
past_data.clear();
|
||||||
|
|
@ -256,12 +261,16 @@ void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t sta
|
||||||
fstReaderSetUnlimitedTimeRange(ctx);
|
fstReaderSetUnlimitedTimeRange(ctx);
|
||||||
fstReaderSetFacProcessMaskAll(ctx);
|
fstReaderSetFacProcessMaskAll(ctx);
|
||||||
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
|
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
|
||||||
if (last_time!=end_time) {
|
if (last_time!=end_time && curr_cycle <= last_cycle) {
|
||||||
past_data = last_data;
|
past_data = last_data;
|
||||||
callback(last_time);
|
callback(last_time);
|
||||||
|
curr_cycle++;
|
||||||
|
}
|
||||||
|
if (curr_cycle <= last_cycle) {
|
||||||
|
past_data = last_data;
|
||||||
|
callback(end_time);
|
||||||
|
curr_cycle++;
|
||||||
}
|
}
|
||||||
past_data = last_data;
|
|
||||||
callback(end_time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FstData::valueOf(fstHandle signal)
|
std::string FstData::valueOf(fstHandle signal)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class FstData
|
||||||
std::vector<FstVar>& getVars() { return vars; };
|
std::vector<FstVar>& getVars() { return vars; };
|
||||||
|
|
||||||
void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
|
void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
|
||||||
void reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time, CallbackFunction cb);
|
void reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time, unsigned int end_cycle, CallbackFunction cb);
|
||||||
|
|
||||||
std::string valueOf(fstHandle signal);
|
std::string valueOf(fstHandle signal);
|
||||||
fstHandle getHandle(std::string name);
|
fstHandle getHandle(std::string name);
|
||||||
|
|
@ -73,6 +73,8 @@ private:
|
||||||
std::string timescale_str;
|
std::string timescale_str;
|
||||||
uint64_t start_time;
|
uint64_t start_time;
|
||||||
uint64_t end_time;
|
uint64_t end_time;
|
||||||
|
unsigned int last_cycle;
|
||||||
|
unsigned int curr_cycle;
|
||||||
CallbackFunction callback;
|
CallbackFunction callback;
|
||||||
std::vector<fstHandle> clk_signals;
|
std::vector<fstHandle> clk_signals;
|
||||||
bool all_samples;
|
bool all_samples;
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,8 @@ gzip_istream::ibuf::~ibuf() {
|
||||||
// returns the original ifstream, rewound to the start.
|
// returns the original ifstream, rewound to the start.
|
||||||
// Never returns nullptr or failed state istream*
|
// Never returns nullptr or failed state istream*
|
||||||
std::istream* uncompressed(const std::string filename, std::ios_base::openmode mode) {
|
std::istream* uncompressed(const std::string filename, std::ios_base::openmode mode) {
|
||||||
|
if (!check_file_exists(filename))
|
||||||
|
log_cmd_error("File `%s' not found or is a directory\n", filename.c_str());
|
||||||
std::ifstream* f = new std::ifstream();
|
std::ifstream* f = new std::ifstream();
|
||||||
f->open(filename, mode);
|
f->open(filename, mode);
|
||||||
if (f->fail())
|
if (f->fail())
|
||||||
|
|
@ -125,7 +127,8 @@ std::istream* uncompressed(const std::string filename, std::ios_base::openmode m
|
||||||
filename.c_str(), unsigned(magic[2]));
|
filename.c_str(), unsigned(magic[2]));
|
||||||
gzip_istream* s = new gzip_istream();
|
gzip_istream* s = new gzip_istream();
|
||||||
delete f;
|
delete f;
|
||||||
log_assert(s->open(filename.c_str()));
|
bool ok = s->open(filename.c_str());
|
||||||
|
log_assert(ok && "Failed to open gzipped file.\n");
|
||||||
return s;
|
return s;
|
||||||
#else
|
#else
|
||||||
log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());
|
log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
||||||
25
kernel/io.cc
25
kernel/io.cc
|
|
@ -247,11 +247,19 @@ std::string make_temp_dir(std::string template_str)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_directory_exists(const std::string& dirname)
|
bool check_is_directory(const std::string& dirname)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
struct _stat info;
|
struct _stat info;
|
||||||
if (_stat(dirname.c_str(), &info) != 0)
|
auto dirname_ = dirname;
|
||||||
|
|
||||||
|
/* On old versions of Visual Studio and current versions on MinGW,
|
||||||
|
_stat will fail if the path ends with a trailing slash. */
|
||||||
|
if (dirname.back() == '/' || dirname.back() == '\\') {
|
||||||
|
dirname_ = dirname.substr(0, dirname.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_stat(dirname_.c_str(), &info) != 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -267,17 +275,26 @@ bool check_directory_exists(const std::string& dirname)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
bool check_file_exists(std::string filename, bool)
|
bool check_accessible(const std::string& filename, bool)
|
||||||
{
|
{
|
||||||
return _access(filename.c_str(), 0) == 0;
|
return _access(filename.c_str(), 0) == 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
bool check_file_exists(std::string filename, bool is_exec)
|
bool check_accessible(const std::string& filename, bool is_exec)
|
||||||
{
|
{
|
||||||
return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
|
return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool check_file_exists(const std::string& filename, bool is_exec)
|
||||||
|
{
|
||||||
|
return check_accessible(filename, is_exec) && !check_is_directory(filename);
|
||||||
|
}
|
||||||
|
bool check_directory_exists(const std::string& filename, bool is_exec)
|
||||||
|
{
|
||||||
|
return check_accessible(filename, is_exec) && check_is_directory(filename);
|
||||||
|
}
|
||||||
|
|
||||||
bool is_absolute_path(std::string filename)
|
bool is_absolute_path(std::string filename)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
|
||||||
17
kernel/io.h
17
kernel/io.h
|
|
@ -64,6 +64,23 @@ inline std::string stringf(const char *fmt, ...)
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int readsome(std::istream &f, char *s, int n);
|
||||||
|
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
|
||||||
|
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
|
||||||
|
bool patmatch(const char *pattern, const char *string);
|
||||||
|
#if !defined(YOSYS_DISABLE_SPAWN)
|
||||||
|
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
|
||||||
|
#endif
|
||||||
|
std::string get_base_tmpdir();
|
||||||
|
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
||||||
|
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
||||||
|
bool check_file_exists(const std::string& filename, bool is_exec = false);
|
||||||
|
bool check_directory_exists(const std::string& dirname, bool is_exec = false);
|
||||||
|
bool is_absolute_path(std::string filename);
|
||||||
|
void remove_directory(std::string dirname);
|
||||||
|
bool create_directory(const std::string& dirname);
|
||||||
|
std::string escape_filename_spaces(const std::string& filename);
|
||||||
|
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
#endif // YOSYS_IO_H
|
#endif // YOSYS_IO_H
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_d
|
||||||
#else
|
#else
|
||||||
static inline bool ys_debug(int = 0) { return false; }
|
static inline bool ys_debug(int = 0) { return false; }
|
||||||
#endif
|
#endif
|
||||||
static inline void log_debug(const char *format, ...) { if (ys_debug(1)) { va_list args; va_start(args, format); logv(format, args); va_end(args); } }
|
# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
|
||||||
|
|
||||||
static inline void log_suppressed() {
|
static inline void log_suppressed() {
|
||||||
if (log_debug_suppressed && !log_make_debug) {
|
if (log_debug_suppressed && !log_make_debug) {
|
||||||
|
|
|
||||||
|
|
@ -860,7 +860,7 @@ struct HelpPass : public Pass {
|
||||||
// init json
|
// init json
|
||||||
json.begin_object();
|
json.begin_object();
|
||||||
json.entry("version", "Yosys internal cells");
|
json.entry("version", "Yosys internal cells");
|
||||||
json.entry("generator", yosys_version_str);
|
json.entry("generator", yosys_maybe_version());
|
||||||
|
|
||||||
dict<string, vector<string>> groups;
|
dict<string, vector<string>> groups;
|
||||||
dict<string, pair<SimHelper, CellType>> cells;
|
dict<string, pair<SimHelper, CellType>> cells;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ struct Pass
|
||||||
{
|
{
|
||||||
std::string pass_name, short_help;
|
std::string pass_name, short_help;
|
||||||
Pass(std::string name, std::string short_help = "** document me **");
|
Pass(std::string name, std::string short_help = "** document me **");
|
||||||
|
// Prefer overriding 'Pass::on_shutdown()' if possible
|
||||||
virtual ~Pass();
|
virtual ~Pass();
|
||||||
|
|
||||||
virtual void help();
|
virtual void help();
|
||||||
|
|
|
||||||
|
|
@ -380,6 +380,49 @@ int RTLIL::Const::as_int(bool is_signed) const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RTLIL::Const::convertible_to_int(bool is_signed) const
|
||||||
|
{
|
||||||
|
auto size = get_min_size(is_signed);
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If it fits in 31 bits it is definitely convertible
|
||||||
|
if (size <= 31)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If it fits in 32 bits, it is convertible if signed or if unsigned and the
|
||||||
|
// leading bit is not 1
|
||||||
|
if (size == 32) {
|
||||||
|
if (is_signed)
|
||||||
|
return true;
|
||||||
|
return get_bits().at(31) != State::S1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> RTLIL::Const::try_as_int(bool is_signed) const
|
||||||
|
{
|
||||||
|
if (!convertible_to_int(is_signed))
|
||||||
|
return std::nullopt;
|
||||||
|
return as_int(is_signed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RTLIL::Const::as_int_saturating(bool is_signed) const
|
||||||
|
{
|
||||||
|
if (!convertible_to_int(is_signed)) {
|
||||||
|
if (!is_signed)
|
||||||
|
return std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
const auto min_size = get_min_size(is_signed);
|
||||||
|
log_assert(min_size > 0);
|
||||||
|
const auto neg = get_bits().at(min_size - 1);
|
||||||
|
return neg ? std::numeric_limits<int>::min() : std::numeric_limits<int>::max();
|
||||||
|
}
|
||||||
|
return as_int(is_signed);
|
||||||
|
}
|
||||||
|
|
||||||
int RTLIL::Const::get_min_size(bool is_signed) const
|
int RTLIL::Const::get_min_size(bool is_signed) const
|
||||||
{
|
{
|
||||||
if (empty()) return 0;
|
if (empty()) return 0;
|
||||||
|
|
@ -412,18 +455,7 @@ void RTLIL::Const::compress(bool is_signed)
|
||||||
|
|
||||||
std::optional<int> RTLIL::Const::as_int_compress(bool is_signed) const
|
std::optional<int> RTLIL::Const::as_int_compress(bool is_signed) const
|
||||||
{
|
{
|
||||||
auto size = get_min_size(is_signed);
|
return try_as_int(is_signed);
|
||||||
if(size == 0 || size > 32)
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
int32_t ret = 0;
|
|
||||||
for (auto i = 0; i < size && i < 32; i++)
|
|
||||||
if ((*this)[i] == State::S1)
|
|
||||||
ret |= 1 << i;
|
|
||||||
if (is_signed && (*this)[size-1] == State::S1)
|
|
||||||
for (auto i = size; i < 32; i++)
|
|
||||||
ret |= 1 << i;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RTLIL::Const::as_string(const char* any) const
|
std::string RTLIL::Const::as_string(const char* any) const
|
||||||
|
|
@ -2377,7 +2409,14 @@ void RTLIL::Module::check()
|
||||||
// assertion check below to make sure that there are no
|
// assertion check below to make sure that there are no
|
||||||
// cases where a cell has a blackbox attribute since
|
// cases where a cell has a blackbox attribute since
|
||||||
// that is deprecated
|
// that is deprecated
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
#endif
|
||||||
log_assert(!it.second->get_blackbox_attribute());
|
log_assert(!it.second->get_blackbox_attribute());
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5462,6 +5501,38 @@ int RTLIL::SigSpec::as_int(bool is_signed) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const
|
||||||
|
{
|
||||||
|
cover("kernel.rtlil.sigspec.convertible_to_int");
|
||||||
|
|
||||||
|
pack();
|
||||||
|
if (!is_fully_const())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return RTLIL::Const(chunks_[0].data).convertible_to_int(is_signed);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> RTLIL::SigSpec::try_as_int(bool is_signed) const
|
||||||
|
{
|
||||||
|
cover("kernel.rtlil.sigspec.try_as_int");
|
||||||
|
|
||||||
|
pack();
|
||||||
|
if (!is_fully_const())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return RTLIL::Const(chunks_[0].data).try_as_int(is_signed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RTLIL::SigSpec::as_int_saturating(bool is_signed) const
|
||||||
|
{
|
||||||
|
cover("kernel.rtlil.sigspec.try_as_int");
|
||||||
|
|
||||||
|
pack();
|
||||||
|
log_assert(is_fully_const() && GetSize(chunks_) <= 1);
|
||||||
|
log_assert(!empty());
|
||||||
|
return RTLIL::Const(chunks_[0].data).as_int_saturating(is_signed);
|
||||||
|
}
|
||||||
|
|
||||||
std::string RTLIL::SigSpec::as_string() const
|
std::string RTLIL::SigSpec::as_string() const
|
||||||
{
|
{
|
||||||
cover("kernel.rtlil.sigspec.as_string");
|
cover("kernel.rtlil.sigspec.as_string");
|
||||||
|
|
|
||||||
|
|
@ -753,7 +753,26 @@ public:
|
||||||
|
|
||||||
std::vector<RTLIL::State>& bits();
|
std::vector<RTLIL::State>& bits();
|
||||||
bool as_bool() const;
|
bool as_bool() const;
|
||||||
|
|
||||||
|
// Convert the constant value to a C++ int.
|
||||||
|
// NOTE: If the constant is too wide to fit in int (32 bits) this will
|
||||||
|
// truncate any higher bits, potentially over/underflowing. Consider using
|
||||||
|
// try_as_int, as_int_saturating, or guarding behind convertible_to_int
|
||||||
|
// instead.
|
||||||
int as_int(bool is_signed = false) const;
|
int as_int(bool is_signed = false) const;
|
||||||
|
|
||||||
|
// Returns true iff the constant can be converted to an int without
|
||||||
|
// over/underflow.
|
||||||
|
bool convertible_to_int(bool is_signed = false) const;
|
||||||
|
|
||||||
|
// Returns the constant's value as an int if it can be represented without
|
||||||
|
// over/underflow, or std::nullopt otherwise.
|
||||||
|
std::optional<int> try_as_int(bool is_signed = false) const;
|
||||||
|
|
||||||
|
// Returns the constant's value as an int if it can be represented without
|
||||||
|
// over/underflow, otherwise the max/min value for int depending on the sign.
|
||||||
|
int as_int_saturating(bool is_signed = false) const;
|
||||||
|
|
||||||
std::string as_string(const char* any = "-") const;
|
std::string as_string(const char* any = "-") const;
|
||||||
static Const from_string(const std::string &str);
|
static Const from_string(const std::string &str);
|
||||||
std::vector<RTLIL::State> to_bits() const;
|
std::vector<RTLIL::State> to_bits() const;
|
||||||
|
|
@ -1130,7 +1149,27 @@ public:
|
||||||
bool is_onehot(int *pos = nullptr) const;
|
bool is_onehot(int *pos = nullptr) const;
|
||||||
|
|
||||||
bool as_bool() const;
|
bool as_bool() const;
|
||||||
|
|
||||||
|
// Convert the SigSpec to a C++ int, assuming all bits are constant.
|
||||||
|
// NOTE: If the value is too wide to fit in int (32 bits) this will
|
||||||
|
// truncate any higher bits, potentially over/underflowing. Consider using
|
||||||
|
// try_as_int, as_int_saturating, or guarding behind convertible_to_int
|
||||||
|
// instead.
|
||||||
int as_int(bool is_signed = false) const;
|
int as_int(bool is_signed = false) const;
|
||||||
|
|
||||||
|
// Returns true iff the SigSpec is constant and can be converted to an int
|
||||||
|
// without over/underflow.
|
||||||
|
bool convertible_to_int(bool is_signed = false) const;
|
||||||
|
|
||||||
|
// Returns the SigSpec's value as an int if it is a constant and can be
|
||||||
|
// represented without over/underflow, or std::nullopt otherwise.
|
||||||
|
std::optional<int> try_as_int(bool is_signed = false) const;
|
||||||
|
|
||||||
|
// Returns an all constant SigSpec's value as an int if it can be represented
|
||||||
|
// without over/underflow, otherwise the max/min value for int depending on
|
||||||
|
// the sign.
|
||||||
|
int as_int_saturating(bool is_signed = false) const;
|
||||||
|
|
||||||
std::string as_string() const;
|
std::string as_string() const;
|
||||||
RTLIL::Const as_const() const;
|
RTLIL::Const as_const() const;
|
||||||
RTLIL::Wire *as_wire() const;
|
RTLIL::Wire *as_wire() const;
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,14 @@ YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
int autoidx = 1;
|
int autoidx = 1;
|
||||||
int yosys_xtrace = 0;
|
int yosys_xtrace = 0;
|
||||||
|
bool yosys_write_versions = true;
|
||||||
|
const char* yosys_maybe_version() {
|
||||||
|
if (yosys_write_versions)
|
||||||
|
return yosys_version_str;
|
||||||
|
else
|
||||||
|
return "Yosys";
|
||||||
|
}
|
||||||
|
|
||||||
RTLIL::Design *yosys_design = NULL;
|
RTLIL::Design *yosys_design = NULL;
|
||||||
CellTypes yosys_celltypes;
|
CellTypes yosys_celltypes;
|
||||||
|
|
||||||
|
|
@ -144,7 +152,7 @@ void yosys_banner()
|
||||||
log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||||
log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n");
|
log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n");
|
||||||
log(" \\----------------------------------------------------------------------------/\n");
|
log(" \\----------------------------------------------------------------------------/\n");
|
||||||
log(" %s\n", yosys_version_str);
|
log(" %s\n", yosys_maybe_version());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(YOSYS_DISABLE_SPAWN)
|
#if !defined(YOSYS_DISABLE_SPAWN)
|
||||||
|
|
@ -548,29 +556,29 @@ void init_share_dirname()
|
||||||
std::string proc_self_path = proc_self_dirname();
|
std::string proc_self_path = proc_self_dirname();
|
||||||
# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR)
|
# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR)
|
||||||
std::string proc_share_path = proc_self_path + "share\\";
|
std::string proc_share_path = proc_self_path + "share\\";
|
||||||
if (check_file_exists(proc_share_path, true)) {
|
if (check_directory_exists(proc_share_path, true)) {
|
||||||
yosys_share_dirname = proc_share_path;
|
yosys_share_dirname = proc_share_path;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
proc_share_path = proc_self_path + "..\\share\\";
|
proc_share_path = proc_self_path + "..\\share\\";
|
||||||
if (check_file_exists(proc_share_path, true)) {
|
if (check_directory_exists(proc_share_path, true)) {
|
||||||
yosys_share_dirname = proc_share_path;
|
yosys_share_dirname = proc_share_path;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
std::string proc_share_path = proc_self_path + "share/";
|
std::string proc_share_path = proc_self_path + "share/";
|
||||||
if (check_file_exists(proc_share_path, true)) {
|
if (check_directory_exists(proc_share_path, true)) {
|
||||||
yosys_share_dirname = proc_share_path;
|
yosys_share_dirname = proc_share_path;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
proc_share_path = proc_self_path + "../share/" + proc_program_prefix()+ "yosys/";
|
proc_share_path = proc_self_path + "../share/" + proc_program_prefix()+ "yosys/";
|
||||||
if (check_file_exists(proc_share_path, true)) {
|
if (check_directory_exists(proc_share_path, true)) {
|
||||||
yosys_share_dirname = proc_share_path;
|
yosys_share_dirname = proc_share_path;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
# ifdef YOSYS_DATDIR
|
# ifdef YOSYS_DATDIR
|
||||||
proc_share_path = YOSYS_DATDIR "/";
|
proc_share_path = YOSYS_DATDIR "/";
|
||||||
if (check_file_exists(proc_share_path, true)) {
|
if (check_directory_exists(proc_share_path, true)) {
|
||||||
yosys_share_dirname = proc_share_path;
|
yosys_share_dirname = proc_share_path;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ extern std::set<std::string> yosys_input_files, yosys_output_files;
|
||||||
|
|
||||||
// from kernel/version_*.o (cc source generated from Makefile)
|
// from kernel/version_*.o (cc source generated from Makefile)
|
||||||
extern const char *yosys_version_str;
|
extern const char *yosys_version_str;
|
||||||
|
const char* yosys_maybe_version();
|
||||||
|
|
||||||
// from passes/cmds/design.cc
|
// from passes/cmds/design.cc
|
||||||
extern std::map<std::string, RTLIL::Design*> saved_designs;
|
extern std::map<std::string, RTLIL::Design*> saved_designs;
|
||||||
|
|
|
||||||
|
|
@ -252,28 +252,12 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); }
|
||||||
void yosys_banner();
|
void yosys_banner();
|
||||||
int ceil_log2(int x) YS_ATTRIBUTE(const);
|
int ceil_log2(int x) YS_ATTRIBUTE(const);
|
||||||
|
|
||||||
int readsome(std::istream &f, char *s, int n);
|
|
||||||
std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false);
|
|
||||||
std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n");
|
|
||||||
bool patmatch(const char *pattern, const char *string);
|
|
||||||
#if !defined(YOSYS_DISABLE_SPAWN)
|
|
||||||
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
|
|
||||||
#endif
|
|
||||||
std::string get_base_tmpdir();
|
|
||||||
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
|
||||||
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
|
||||||
bool check_file_exists(std::string filename, bool is_exec = false);
|
|
||||||
bool check_directory_exists(const std::string& dirname);
|
|
||||||
bool is_absolute_path(std::string filename);
|
|
||||||
void remove_directory(std::string dirname);
|
|
||||||
bool create_directory(const std::string& dirname);
|
|
||||||
std::string escape_filename_spaces(const std::string& filename);
|
|
||||||
|
|
||||||
template<typename T> int GetSize(const T &obj) { return obj.size(); }
|
template<typename T> int GetSize(const T &obj) { return obj.size(); }
|
||||||
inline int GetSize(RTLIL::Wire *wire);
|
inline int GetSize(RTLIL::Wire *wire);
|
||||||
|
|
||||||
extern int autoidx;
|
extern int autoidx;
|
||||||
extern int yosys_xtrace;
|
extern int yosys_xtrace;
|
||||||
|
extern bool yosys_write_versions;
|
||||||
|
|
||||||
RTLIL::IdString new_id(std::string file, int line, std::string func);
|
RTLIL::IdString new_id(std::string file, int line, std::string func);
|
||||||
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
|
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
--- fstapi.cc
|
--- fstapi.cc
|
||||||
+++ fstapi.cc
|
+++ fstapi.cc
|
||||||
@@ -4723,7 +4723,10 @@ if(gzread_pass_status)
|
@@ -4723,7 +4723,10 @@ if(gzread_pass_status)
|
||||||
hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0);
|
hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0);
|
||||||
|
|
||||||
fstFread(&dcheck, 8, 1, xc->f);
|
fstFread(&dcheck, 8, 1, xc->f);
|
||||||
- xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
|
- xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
|
||||||
+ /*
|
+ /*
|
||||||
+ * Yosys patch: Fix double endian check for i386 targets built in modern gcc
|
+ * Yosys patch: Fix double endian check for i386 targets built in modern gcc
|
||||||
+ */
|
+ */
|
||||||
+ xc->double_endian_match = (dcheck == (double)FST_DOUBLE_ENDTEST);
|
+ xc->double_endian_match = (dcheck == (double)FST_DOUBLE_ENDTEST);
|
||||||
if(!xc->double_endian_match)
|
if (!xc->double_endian_match) {
|
||||||
{
|
union
|
||||||
union {
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@
|
||||||
@@ -137,7 +137,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
|
@@ -137,7 +137,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
|
||||||
-#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
- defined(__NetBSD__)
|
||||||
+#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(_MSC_VER) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
+ defined(__NetBSD__) || defined(_MSC_VER)
|
||||||
#define FST_UNBUFFERED_IO
|
#define FST_UNBUFFERED_IO
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@
|
||||||
-#include <zlib.h>
|
-#include <zlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
+ #include "libs/zlib/zlib.h"
|
+#include "libs/zlib/zlib.h"
|
||||||
#include "fst_win_unistd.h"
|
#include "fst_win_unistd.h"
|
||||||
#else
|
#else
|
||||||
+ #include <zlib.h>
|
+#include <zlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
--- fstapi.cc
|
--- fstapi.cc
|
||||||
+++ fstapi.cc
|
+++ fstapi.cc
|
||||||
@@ -6072,6 +6072,7 @@ for(;;)
|
@@ -6072,6 +6072,7 @@ for(;;)
|
||||||
}
|
}
|
||||||
|
|
||||||
wx_len = snprintf(wx_buf, 32, "r%.16g", d);
|
wx_len = snprintf(wx_buf, 32, "r%.16g", d);
|
||||||
+ if (wx_len > 32 || wx_len < 0) wx_len = 32;
|
+ if (wx_len > 32 || wx_len < 0) wx_len = 32;
|
||||||
fstWritex(xc, wx_buf, wx_len);
|
fstWritex(xc, wx_buf, wx_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
mv config.h config.h.bak
|
mv config.h config.h.bak
|
||||||
rm -f *.txt *.cc *.h
|
rm -f *.txt *.cc *.h
|
||||||
git clone --depth 1 https://github.com/gtkwave/gtkwave fst_upstream
|
git clone --depth 1 https://github.com/gtkwave/libfst fst_upstream
|
||||||
rm fst_upstream/lib/libfst/CMakeLists.txt
|
rm fst_upstream/src/meson.build
|
||||||
mv fst_upstream/lib/libfst/*.{h,c,txt} .
|
mv fst_upstream/src/*.{h,c} .
|
||||||
|
mv fst_upstream/doc/block_format.txt .
|
||||||
rm -rf fst_upstream
|
rm -rf fst_upstream
|
||||||
|
|
||||||
for src in *.c; do
|
for src in *.c; do
|
||||||
|
|
|
||||||
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
|
#define FST_API_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -35,430 +36,510 @@ extern "C" {
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#include "libs/zlib/zlib.h"
|
#include "libs/zlib/zlib.h"
|
||||||
#include "fst_win_unistd.h"
|
#include "fst_win_unistd.h"
|
||||||
#else
|
#else
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#define FST_RDLOAD "FSTLOAD | "
|
|
||||||
|
|
||||||
typedef uint32_t fstHandle;
|
typedef uint32_t fstHandle;
|
||||||
typedef uint32_t fstEnumHandle;
|
typedef uint32_t fstEnumHandle;
|
||||||
|
|
||||||
enum fstWriterPackType {
|
enum fstWriterPackType
|
||||||
FST_WR_PT_ZLIB = 0,
|
{
|
||||||
FST_WR_PT_FASTLZ = 1,
|
FST_WR_PT_ZLIB = 0,
|
||||||
FST_WR_PT_LZ4 = 2
|
FST_WR_PT_FASTLZ = 1,
|
||||||
|
FST_WR_PT_LZ4 = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstFileType {
|
enum fstFileType
|
||||||
FST_FT_MIN = 0,
|
{
|
||||||
|
FST_FT_MIN = 0,
|
||||||
|
|
||||||
FST_FT_VERILOG = 0,
|
FST_FT_VERILOG = 0,
|
||||||
FST_FT_VHDL = 1,
|
FST_FT_VHDL = 1,
|
||||||
FST_FT_VERILOG_VHDL = 2,
|
FST_FT_VERILOG_VHDL = 2,
|
||||||
|
|
||||||
FST_FT_MAX = 2
|
FST_FT_MAX = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstBlockType {
|
enum fstBlockType
|
||||||
FST_BL_HDR = 0,
|
{
|
||||||
FST_BL_VCDATA = 1,
|
FST_BL_HDR = 0,
|
||||||
FST_BL_BLACKOUT = 2,
|
FST_BL_VCDATA = 1,
|
||||||
FST_BL_GEOM = 3,
|
FST_BL_BLACKOUT = 2,
|
||||||
FST_BL_HIER = 4,
|
FST_BL_GEOM = 3,
|
||||||
FST_BL_VCDATA_DYN_ALIAS = 5,
|
FST_BL_HIER = 4,
|
||||||
FST_BL_HIER_LZ4 = 6,
|
FST_BL_VCDATA_DYN_ALIAS = 5,
|
||||||
FST_BL_HIER_LZ4DUO = 7,
|
FST_BL_HIER_LZ4 = 6,
|
||||||
FST_BL_VCDATA_DYN_ALIAS2 = 8,
|
FST_BL_HIER_LZ4DUO = 7,
|
||||||
|
FST_BL_VCDATA_DYN_ALIAS2 = 8,
|
||||||
|
|
||||||
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
|
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
|
||||||
FST_BL_SKIP = 255 /* used while block is being written */
|
FST_BL_SKIP = 255 /* used while block is being written */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstScopeType {
|
enum fstScopeType
|
||||||
FST_ST_MIN = 0,
|
{
|
||||||
|
FST_ST_MIN = 0,
|
||||||
|
|
||||||
FST_ST_VCD_MODULE = 0,
|
FST_ST_VCD_MODULE = 0,
|
||||||
FST_ST_VCD_TASK = 1,
|
FST_ST_VCD_TASK = 1,
|
||||||
FST_ST_VCD_FUNCTION = 2,
|
FST_ST_VCD_FUNCTION = 2,
|
||||||
FST_ST_VCD_BEGIN = 3,
|
FST_ST_VCD_BEGIN = 3,
|
||||||
FST_ST_VCD_FORK = 4,
|
FST_ST_VCD_FORK = 4,
|
||||||
FST_ST_VCD_GENERATE = 5,
|
FST_ST_VCD_GENERATE = 5,
|
||||||
FST_ST_VCD_STRUCT = 6,
|
FST_ST_VCD_STRUCT = 6,
|
||||||
FST_ST_VCD_UNION = 7,
|
FST_ST_VCD_UNION = 7,
|
||||||
FST_ST_VCD_CLASS = 8,
|
FST_ST_VCD_CLASS = 8,
|
||||||
FST_ST_VCD_INTERFACE = 9,
|
FST_ST_VCD_INTERFACE = 9,
|
||||||
FST_ST_VCD_PACKAGE = 10,
|
FST_ST_VCD_PACKAGE = 10,
|
||||||
FST_ST_VCD_PROGRAM = 11,
|
FST_ST_VCD_PROGRAM = 11,
|
||||||
|
|
||||||
FST_ST_VHDL_ARCHITECTURE = 12,
|
FST_ST_VHDL_ARCHITECTURE = 12,
|
||||||
FST_ST_VHDL_PROCEDURE = 13,
|
FST_ST_VHDL_PROCEDURE = 13,
|
||||||
FST_ST_VHDL_FUNCTION = 14,
|
FST_ST_VHDL_FUNCTION = 14,
|
||||||
FST_ST_VHDL_RECORD = 15,
|
FST_ST_VHDL_RECORD = 15,
|
||||||
FST_ST_VHDL_PROCESS = 16,
|
FST_ST_VHDL_PROCESS = 16,
|
||||||
FST_ST_VHDL_BLOCK = 17,
|
FST_ST_VHDL_BLOCK = 17,
|
||||||
FST_ST_VHDL_FOR_GENERATE = 18,
|
FST_ST_VHDL_FOR_GENERATE = 18,
|
||||||
FST_ST_VHDL_IF_GENERATE = 19,
|
FST_ST_VHDL_IF_GENERATE = 19,
|
||||||
FST_ST_VHDL_GENERATE = 20,
|
FST_ST_VHDL_GENERATE = 20,
|
||||||
FST_ST_VHDL_PACKAGE = 21,
|
FST_ST_VHDL_PACKAGE = 21,
|
||||||
|
|
||||||
FST_ST_MAX = 21,
|
FST_ST_MAX = 21,
|
||||||
|
|
||||||
FST_ST_GEN_ATTRBEGIN = 252,
|
FST_ST_GEN_ATTRBEGIN = 252,
|
||||||
FST_ST_GEN_ATTREND = 253,
|
FST_ST_GEN_ATTREND = 253,
|
||||||
|
|
||||||
FST_ST_VCD_SCOPE = 254,
|
FST_ST_VCD_SCOPE = 254,
|
||||||
FST_ST_VCD_UPSCOPE = 255
|
FST_ST_VCD_UPSCOPE = 255
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstVarType {
|
enum fstVarType
|
||||||
FST_VT_MIN = 0, /* start of vartypes */
|
{
|
||||||
|
FST_VT_MIN = 0, /* start of vartypes */
|
||||||
|
|
||||||
FST_VT_VCD_EVENT = 0,
|
FST_VT_VCD_EVENT = 0,
|
||||||
FST_VT_VCD_INTEGER = 1,
|
FST_VT_VCD_INTEGER = 1,
|
||||||
FST_VT_VCD_PARAMETER = 2,
|
FST_VT_VCD_PARAMETER = 2,
|
||||||
FST_VT_VCD_REAL = 3,
|
FST_VT_VCD_REAL = 3,
|
||||||
FST_VT_VCD_REAL_PARAMETER = 4,
|
FST_VT_VCD_REAL_PARAMETER = 4,
|
||||||
FST_VT_VCD_REG = 5,
|
FST_VT_VCD_REG = 5,
|
||||||
FST_VT_VCD_SUPPLY0 = 6,
|
FST_VT_VCD_SUPPLY0 = 6,
|
||||||
FST_VT_VCD_SUPPLY1 = 7,
|
FST_VT_VCD_SUPPLY1 = 7,
|
||||||
FST_VT_VCD_TIME = 8,
|
FST_VT_VCD_TIME = 8,
|
||||||
FST_VT_VCD_TRI = 9,
|
FST_VT_VCD_TRI = 9,
|
||||||
FST_VT_VCD_TRIAND = 10,
|
FST_VT_VCD_TRIAND = 10,
|
||||||
FST_VT_VCD_TRIOR = 11,
|
FST_VT_VCD_TRIOR = 11,
|
||||||
FST_VT_VCD_TRIREG = 12,
|
FST_VT_VCD_TRIREG = 12,
|
||||||
FST_VT_VCD_TRI0 = 13,
|
FST_VT_VCD_TRI0 = 13,
|
||||||
FST_VT_VCD_TRI1 = 14,
|
FST_VT_VCD_TRI1 = 14,
|
||||||
FST_VT_VCD_WAND = 15,
|
FST_VT_VCD_WAND = 15,
|
||||||
FST_VT_VCD_WIRE = 16,
|
FST_VT_VCD_WIRE = 16,
|
||||||
FST_VT_VCD_WOR = 17,
|
FST_VT_VCD_WOR = 17,
|
||||||
FST_VT_VCD_PORT = 18,
|
FST_VT_VCD_PORT = 18,
|
||||||
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
|
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
|
||||||
FST_VT_VCD_REALTIME = 20,
|
FST_VT_VCD_REALTIME = 20,
|
||||||
|
|
||||||
FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */
|
FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via
|
||||||
|
fstWriterEmitVariableLengthValueChange) */
|
||||||
|
|
||||||
FST_VT_SV_BIT = 22,
|
FST_VT_SV_BIT = 22,
|
||||||
FST_VT_SV_LOGIC = 23,
|
FST_VT_SV_LOGIC = 23,
|
||||||
FST_VT_SV_INT = 24, /* declare as size = 32 */
|
FST_VT_SV_INT = 24, /* declare as size = 32 */
|
||||||
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
|
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
|
||||||
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
|
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
|
||||||
FST_VT_SV_BYTE = 27, /* declare as size = 8 */
|
FST_VT_SV_BYTE = 27, /* declare as size = 8 */
|
||||||
FST_VT_SV_ENUM = 28, /* declare as appropriate type range */
|
FST_VT_SV_ENUM = 28, /* declare as appropriate type range */
|
||||||
FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */
|
FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted
|
||||||
|
as double, not a float) */
|
||||||
|
|
||||||
FST_VT_MAX = 29 /* end of vartypes */
|
FST_VT_MAX = 29 /* end of vartypes */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstVarDir {
|
enum fstVarDir
|
||||||
FST_VD_MIN = 0,
|
{
|
||||||
|
FST_VD_MIN = 0,
|
||||||
|
|
||||||
FST_VD_IMPLICIT = 0,
|
FST_VD_IMPLICIT = 0,
|
||||||
FST_VD_INPUT = 1,
|
FST_VD_INPUT = 1,
|
||||||
FST_VD_OUTPUT = 2,
|
FST_VD_OUTPUT = 2,
|
||||||
FST_VD_INOUT = 3,
|
FST_VD_INOUT = 3,
|
||||||
FST_VD_BUFFER = 4,
|
FST_VD_BUFFER = 4,
|
||||||
FST_VD_LINKAGE = 5,
|
FST_VD_LINKAGE = 5,
|
||||||
|
|
||||||
FST_VD_MAX = 5
|
FST_VD_MAX = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstHierType {
|
enum fstHierType
|
||||||
FST_HT_MIN = 0,
|
{
|
||||||
|
FST_HT_MIN = 0,
|
||||||
|
|
||||||
FST_HT_SCOPE = 0,
|
FST_HT_SCOPE = 0,
|
||||||
FST_HT_UPSCOPE = 1,
|
FST_HT_UPSCOPE = 1,
|
||||||
FST_HT_VAR = 2,
|
FST_HT_VAR = 2,
|
||||||
FST_HT_ATTRBEGIN = 3,
|
FST_HT_ATTRBEGIN = 3,
|
||||||
FST_HT_ATTREND = 4,
|
FST_HT_ATTREND = 4,
|
||||||
|
|
||||||
/* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when fstHier bridges other formats */
|
/* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when
|
||||||
FST_HT_TREEBEGIN = 5,
|
fstHier bridges other formats */
|
||||||
FST_HT_TREEEND = 6,
|
FST_HT_TREEBEGIN = 5,
|
||||||
|
FST_HT_TREEEND = 6,
|
||||||
|
|
||||||
FST_HT_MAX = 6
|
FST_HT_MAX = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstAttrType {
|
enum fstAttrType
|
||||||
FST_AT_MIN = 0,
|
{
|
||||||
|
FST_AT_MIN = 0,
|
||||||
|
|
||||||
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
|
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
|
||||||
FST_AT_ARRAY = 1,
|
FST_AT_ARRAY = 1,
|
||||||
FST_AT_ENUM = 2,
|
FST_AT_ENUM = 2,
|
||||||
FST_AT_PACK = 3,
|
FST_AT_PACK = 3,
|
||||||
|
|
||||||
FST_AT_MAX = 3
|
FST_AT_MAX = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstMiscType {
|
enum fstMiscType
|
||||||
FST_MT_MIN = 0,
|
{
|
||||||
|
FST_MT_MIN = 0,
|
||||||
|
|
||||||
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
|
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
|
||||||
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
|
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
|
||||||
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
|
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
|
||||||
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
|
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
|
||||||
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
|
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
|
||||||
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
|
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
|
||||||
FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
|
FST_MT_VALUELIST =
|
||||||
FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
|
6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
|
||||||
FST_MT_UNKNOWN = 8,
|
FST_MT_ENUMTABLE =
|
||||||
|
7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
|
||||||
|
FST_MT_UNKNOWN = 8,
|
||||||
|
|
||||||
FST_MT_MAX = 8
|
FST_MT_MAX = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstArrayType {
|
enum fstArrayType
|
||||||
FST_AR_MIN = 0,
|
{
|
||||||
|
FST_AR_MIN = 0,
|
||||||
|
|
||||||
FST_AR_NONE = 0,
|
FST_AR_NONE = 0,
|
||||||
FST_AR_UNPACKED = 1,
|
FST_AR_UNPACKED = 1,
|
||||||
FST_AR_PACKED = 2,
|
FST_AR_PACKED = 2,
|
||||||
FST_AR_SPARSE = 3,
|
FST_AR_SPARSE = 3,
|
||||||
|
|
||||||
FST_AR_MAX = 3
|
FST_AR_MAX = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstEnumValueType {
|
enum fstEnumValueType
|
||||||
FST_EV_SV_INTEGER = 0,
|
{
|
||||||
FST_EV_SV_BIT = 1,
|
FST_EV_SV_INTEGER = 0,
|
||||||
FST_EV_SV_LOGIC = 2,
|
FST_EV_SV_BIT = 1,
|
||||||
FST_EV_SV_INT = 3,
|
FST_EV_SV_LOGIC = 2,
|
||||||
FST_EV_SV_SHORTINT = 4,
|
FST_EV_SV_INT = 3,
|
||||||
FST_EV_SV_LONGINT = 5,
|
FST_EV_SV_SHORTINT = 4,
|
||||||
FST_EV_SV_BYTE = 6,
|
FST_EV_SV_LONGINT = 5,
|
||||||
FST_EV_SV_UNSIGNED_INTEGER = 7,
|
FST_EV_SV_BYTE = 6,
|
||||||
FST_EV_SV_UNSIGNED_BIT = 8,
|
FST_EV_SV_UNSIGNED_INTEGER = 7,
|
||||||
FST_EV_SV_UNSIGNED_LOGIC = 9,
|
FST_EV_SV_UNSIGNED_BIT = 8,
|
||||||
FST_EV_SV_UNSIGNED_INT = 10,
|
FST_EV_SV_UNSIGNED_LOGIC = 9,
|
||||||
|
FST_EV_SV_UNSIGNED_INT = 10,
|
||||||
FST_EV_SV_UNSIGNED_SHORTINT = 11,
|
FST_EV_SV_UNSIGNED_SHORTINT = 11,
|
||||||
FST_EV_SV_UNSIGNED_LONGINT = 12,
|
FST_EV_SV_UNSIGNED_LONGINT = 12,
|
||||||
FST_EV_SV_UNSIGNED_BYTE = 13,
|
FST_EV_SV_UNSIGNED_BYTE = 13,
|
||||||
|
|
||||||
FST_EV_REG = 14,
|
FST_EV_REG = 14,
|
||||||
FST_EV_TIME = 15,
|
FST_EV_TIME = 15,
|
||||||
|
|
||||||
FST_EV_MAX = 15
|
FST_EV_MAX = 15
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstPackType {
|
enum fstPackType
|
||||||
FST_PT_NONE = 0,
|
{
|
||||||
FST_PT_UNPACKED = 1,
|
FST_PT_NONE = 0,
|
||||||
FST_PT_PACKED = 2,
|
FST_PT_UNPACKED = 1,
|
||||||
|
FST_PT_PACKED = 2,
|
||||||
FST_PT_TAGGED_PACKED = 3,
|
FST_PT_TAGGED_PACKED = 3,
|
||||||
|
|
||||||
FST_PT_MAX = 3
|
FST_PT_MAX = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstSupplementalVarType {
|
enum fstSupplementalVarType
|
||||||
FST_SVT_MIN = 0,
|
{
|
||||||
|
FST_SVT_MIN = 0,
|
||||||
|
|
||||||
FST_SVT_NONE = 0,
|
FST_SVT_NONE = 0,
|
||||||
|
|
||||||
FST_SVT_VHDL_SIGNAL = 1,
|
FST_SVT_VHDL_SIGNAL = 1,
|
||||||
FST_SVT_VHDL_VARIABLE = 2,
|
FST_SVT_VHDL_VARIABLE = 2,
|
||||||
FST_SVT_VHDL_CONSTANT = 3,
|
FST_SVT_VHDL_CONSTANT = 3,
|
||||||
FST_SVT_VHDL_FILE = 4,
|
FST_SVT_VHDL_FILE = 4,
|
||||||
FST_SVT_VHDL_MEMORY = 5,
|
FST_SVT_VHDL_MEMORY = 5,
|
||||||
|
|
||||||
FST_SVT_MAX = 5
|
FST_SVT_MAX = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fstSupplementalDataType {
|
enum fstSupplementalDataType
|
||||||
FST_SDT_MIN = 0,
|
{
|
||||||
|
FST_SDT_MIN = 0,
|
||||||
|
|
||||||
FST_SDT_NONE = 0,
|
FST_SDT_NONE = 0,
|
||||||
|
|
||||||
FST_SDT_VHDL_BOOLEAN = 1,
|
FST_SDT_VHDL_BOOLEAN = 1,
|
||||||
FST_SDT_VHDL_BIT = 2,
|
FST_SDT_VHDL_BIT = 2,
|
||||||
FST_SDT_VHDL_BIT_VECTOR = 3,
|
FST_SDT_VHDL_BIT_VECTOR = 3,
|
||||||
FST_SDT_VHDL_STD_ULOGIC = 4,
|
FST_SDT_VHDL_STD_ULOGIC = 4,
|
||||||
FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5,
|
FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5,
|
||||||
FST_SDT_VHDL_STD_LOGIC = 6,
|
FST_SDT_VHDL_STD_LOGIC = 6,
|
||||||
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
|
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
|
||||||
FST_SDT_VHDL_UNSIGNED = 8,
|
FST_SDT_VHDL_UNSIGNED = 8,
|
||||||
FST_SDT_VHDL_SIGNED = 9,
|
FST_SDT_VHDL_SIGNED = 9,
|
||||||
FST_SDT_VHDL_INTEGER = 10,
|
FST_SDT_VHDL_INTEGER = 10,
|
||||||
FST_SDT_VHDL_REAL = 11,
|
FST_SDT_VHDL_REAL = 11,
|
||||||
FST_SDT_VHDL_NATURAL = 12,
|
FST_SDT_VHDL_NATURAL = 12,
|
||||||
FST_SDT_VHDL_POSITIVE = 13,
|
FST_SDT_VHDL_POSITIVE = 13,
|
||||||
FST_SDT_VHDL_TIME = 14,
|
FST_SDT_VHDL_TIME = 14,
|
||||||
FST_SDT_VHDL_CHARACTER = 15,
|
FST_SDT_VHDL_CHARACTER = 15,
|
||||||
FST_SDT_VHDL_STRING = 16,
|
FST_SDT_VHDL_STRING = 16,
|
||||||
|
|
||||||
FST_SDT_MAX = 16,
|
FST_SDT_MAX = 16,
|
||||||
|
|
||||||
FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */
|
FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left
|
||||||
FST_SDT_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1)
|
after shifting FST_SDT_SVT_SHIFT_COUNT */
|
||||||
|
FST_SDT_ABS_MAX = ((1 << (FST_SDT_SVT_SHIFT_COUNT)) - 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct fstHier
|
struct fstHier
|
||||||
{
|
{
|
||||||
unsigned char htyp;
|
unsigned char htyp;
|
||||||
|
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
/* if htyp == FST_HT_SCOPE */
|
/* if htyp == FST_HT_SCOPE */
|
||||||
struct fstHierScope {
|
struct fstHierScope
|
||||||
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
|
{
|
||||||
const char *name;
|
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
|
||||||
const char *component;
|
const char *name;
|
||||||
uint32_t name_length; /* strlen(u.scope.name) */
|
const char *component;
|
||||||
uint32_t component_length; /* strlen(u.scope.component) */
|
uint32_t name_length; /* strlen(u.scope.name) */
|
||||||
} scope;
|
uint32_t component_length; /* strlen(u.scope.component) */
|
||||||
|
} scope;
|
||||||
|
|
||||||
/* if htyp == FST_HT_VAR */
|
/* if htyp == FST_HT_VAR */
|
||||||
struct fstHierVar {
|
struct fstHierVar
|
||||||
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
|
{
|
||||||
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
|
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
|
||||||
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
|
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
|
||||||
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
|
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
|
||||||
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
|
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
|
||||||
const char *name;
|
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
|
||||||
uint32_t length;
|
const char *name;
|
||||||
fstHandle handle;
|
uint32_t length;
|
||||||
uint32_t name_length; /* strlen(u.var.name) */
|
fstHandle handle;
|
||||||
unsigned is_alias : 1;
|
uint32_t name_length; /* strlen(u.var.name) */
|
||||||
} var;
|
unsigned is_alias : 1;
|
||||||
|
} var;
|
||||||
|
|
||||||
/* if htyp == FST_HT_ATTRBEGIN */
|
/* if htyp == FST_HT_ATTRBEGIN */
|
||||||
struct fstHierAttr {
|
struct fstHierAttr
|
||||||
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
|
{
|
||||||
unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
|
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
|
||||||
const char *name;
|
unsigned char
|
||||||
uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */
|
subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
|
||||||
uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */
|
const char *name;
|
||||||
uint32_t name_length; /* strlen(u.attr.name) */
|
uint64_t arg; /* number of array elements, struct members, or some other payload
|
||||||
} attr;
|
(possibly ignored) */
|
||||||
} u;
|
uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer
|
||||||
|
(FST_AT_MISC + FST_MT_SOURCESTEM) */
|
||||||
|
uint32_t name_length; /* strlen(u.attr.name) */
|
||||||
|
} attr;
|
||||||
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct fstETab
|
struct fstETab
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
uint32_t elem_count;
|
uint32_t elem_count;
|
||||||
char **literal_arr;
|
char **literal_arr;
|
||||||
char **val_arr;
|
char **val_arr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* writer functions
|
* writer functions
|
||||||
*/
|
*/
|
||||||
void fstWriterClose(void *ctx);
|
|
||||||
void * fstWriterCreate(const char *nam, int use_compressed_hier);
|
|
||||||
fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr);
|
|
||||||
/* used for Verilog/SV */
|
|
||||||
fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
|
|
||||||
uint32_t len, const char *nam, fstHandle aliasHandle);
|
|
||||||
/* future expansion for VHDL and other languages. The variable type, data type, etc map onto
|
|
||||||
the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */
|
|
||||||
fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd,
|
|
||||||
uint32_t len, const char *nam, fstHandle aliasHandle,
|
|
||||||
const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt);
|
|
||||||
void fstWriterEmitDumpActive(void *ctx, int enable);
|
|
||||||
void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle);
|
|
||||||
void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val);
|
|
||||||
void fstWriterEmitValueChange32(void *ctx, fstHandle handle,
|
|
||||||
uint32_t bits, uint32_t val);
|
|
||||||
void fstWriterEmitValueChange64(void *ctx, fstHandle handle,
|
|
||||||
uint32_t bits, uint64_t val);
|
|
||||||
void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle,
|
|
||||||
uint32_t bits, const uint32_t *val);
|
|
||||||
void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle,
|
|
||||||
uint32_t bits, const uint64_t *val);
|
|
||||||
void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len);
|
|
||||||
void fstWriterEmitTimeChange(void *ctx, uint64_t tim);
|
|
||||||
void fstWriterFlushContext(void *ctx);
|
|
||||||
int fstWriterGetDumpSizeLimitReached(void *ctx);
|
|
||||||
int fstWriterGetFseekFailed(void *ctx);
|
|
||||||
void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype,
|
|
||||||
const char *attrname, uint64_t arg);
|
|
||||||
void fstWriterSetAttrEnd(void *ctx);
|
|
||||||
void fstWriterSetComment(void *ctx, const char *comm);
|
|
||||||
void fstWriterSetDate(void *ctx, const char *dat);
|
|
||||||
void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes);
|
|
||||||
void fstWriterSetEnvVar(void *ctx, const char *envvar);
|
|
||||||
void fstWriterSetFileType(void *ctx, enum fstFileType filetype);
|
|
||||||
void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ);
|
|
||||||
void fstWriterSetParallelMode(void *ctx, int enable);
|
|
||||||
void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */
|
|
||||||
void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
|
|
||||||
const char *scopename, const char *scopecomp);
|
|
||||||
void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
|
|
||||||
void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
|
|
||||||
void fstWriterSetTimescale(void *ctx, int ts);
|
|
||||||
void fstWriterSetTimescaleFromString(void *ctx, const char *s);
|
|
||||||
void fstWriterSetTimezero(void *ctx, int64_t tim);
|
|
||||||
void fstWriterSetUpscope(void *ctx);
|
|
||||||
void fstWriterSetValueList(void *ctx, const char *vl);
|
|
||||||
void fstWriterSetVersion(void *ctx, const char *vers);
|
|
||||||
|
|
||||||
|
typedef struct fstWriterContext fstWriterContext;
|
||||||
|
|
||||||
|
void fstWriterClose(fstWriterContext *ctx);
|
||||||
|
fstWriterContext *fstWriterCreate(const char *nam, int use_compressed_hier);
|
||||||
|
fstEnumHandle fstWriterCreateEnumTable(fstWriterContext *ctx,
|
||||||
|
const char *name,
|
||||||
|
uint32_t elem_count,
|
||||||
|
unsigned int min_valbits,
|
||||||
|
const char **literal_arr,
|
||||||
|
const char **val_arr);
|
||||||
|
/* used for Verilog/SV */
|
||||||
|
fstHandle fstWriterCreateVar(fstWriterContext *ctx,
|
||||||
|
enum fstVarType vt,
|
||||||
|
enum fstVarDir vd,
|
||||||
|
uint32_t len,
|
||||||
|
const char *nam,
|
||||||
|
fstHandle aliasHandle);
|
||||||
|
/* future expansion for VHDL and other languages. The variable type, data type, etc map onto
|
||||||
|
the current Verilog/SV one. The "type" string is optional for a more verbose or custom
|
||||||
|
description */
|
||||||
|
fstHandle fstWriterCreateVar2(fstWriterContext *ctx,
|
||||||
|
enum fstVarType vt,
|
||||||
|
enum fstVarDir vd,
|
||||||
|
uint32_t len,
|
||||||
|
const char *nam,
|
||||||
|
fstHandle aliasHandle,
|
||||||
|
const char *type,
|
||||||
|
enum fstSupplementalVarType svt,
|
||||||
|
enum fstSupplementalDataType sdt);
|
||||||
|
void fstWriterEmitDumpActive(fstWriterContext *ctx, int enable);
|
||||||
|
void fstWriterEmitEnumTableRef(fstWriterContext *ctx, fstEnumHandle handle);
|
||||||
|
void fstWriterEmitValueChange(fstWriterContext *ctx, fstHandle handle, const void *val);
|
||||||
|
void fstWriterEmitValueChange32(fstWriterContext *ctx,
|
||||||
|
fstHandle handle,
|
||||||
|
uint32_t bits,
|
||||||
|
uint32_t val);
|
||||||
|
void fstWriterEmitValueChange64(fstWriterContext *ctx,
|
||||||
|
fstHandle handle,
|
||||||
|
uint32_t bits,
|
||||||
|
uint64_t val);
|
||||||
|
void fstWriterEmitValueChangeVec32(fstWriterContext *ctx,
|
||||||
|
fstHandle handle,
|
||||||
|
uint32_t bits,
|
||||||
|
const uint32_t *val);
|
||||||
|
void fstWriterEmitValueChangeVec64(fstWriterContext *ctx,
|
||||||
|
fstHandle handle,
|
||||||
|
uint32_t bits,
|
||||||
|
const uint64_t *val);
|
||||||
|
void fstWriterEmitVariableLengthValueChange(fstWriterContext *ctx,
|
||||||
|
fstHandle handle,
|
||||||
|
const void *val,
|
||||||
|
uint32_t len);
|
||||||
|
void fstWriterEmitTimeChange(fstWriterContext *ctx, uint64_t tim);
|
||||||
|
void fstWriterFlushContext(fstWriterContext *ctx);
|
||||||
|
int fstWriterGetDumpSizeLimitReached(fstWriterContext *ctx);
|
||||||
|
int fstWriterGetFseekFailed(fstWriterContext *ctx);
|
||||||
|
int fstWriterGetFlushContextPending(fstWriterContext *ctx);
|
||||||
|
void fstWriterSetAttrBegin(fstWriterContext *ctx,
|
||||||
|
enum fstAttrType attrtype,
|
||||||
|
int subtype,
|
||||||
|
const char *attrname,
|
||||||
|
uint64_t arg);
|
||||||
|
void fstWriterSetAttrEnd(fstWriterContext *ctx);
|
||||||
|
void fstWriterSetComment(fstWriterContext *ctx, const char *comm);
|
||||||
|
void fstWriterSetDate(fstWriterContext *ctx, const char *dat);
|
||||||
|
void fstWriterSetDumpSizeLimit(fstWriterContext *ctx, uint64_t numbytes);
|
||||||
|
void fstWriterSetEnvVar(fstWriterContext *ctx, const char *envvar);
|
||||||
|
void fstWriterSetFileType(fstWriterContext *ctx, enum fstFileType filetype);
|
||||||
|
void fstWriterSetPackType(fstWriterContext *ctx, enum fstWriterPackType typ);
|
||||||
|
void fstWriterSetParallelMode(fstWriterContext *ctx, int enable);
|
||||||
|
void fstWriterSetRepackOnClose(fstWriterContext *ctx,
|
||||||
|
int enable); /* type = 0 (none), 1 (libz) */
|
||||||
|
void fstWriterSetScope(fstWriterContext *ctx,
|
||||||
|
enum fstScopeType scopetype,
|
||||||
|
const char *scopename,
|
||||||
|
const char *scopecomp);
|
||||||
|
void fstWriterSetSourceInstantiationStem(fstWriterContext *ctx,
|
||||||
|
const char *path,
|
||||||
|
unsigned int line,
|
||||||
|
unsigned int use_realpath);
|
||||||
|
void fstWriterSetSourceStem(fstWriterContext *ctx,
|
||||||
|
const char *path,
|
||||||
|
unsigned int line,
|
||||||
|
unsigned int use_realpath);
|
||||||
|
void fstWriterSetTimescale(fstWriterContext *ctx, int ts);
|
||||||
|
void fstWriterSetTimescaleFromString(fstWriterContext *ctx, const char *s);
|
||||||
|
void fstWriterSetTimezero(fstWriterContext *ctx, int64_t tim);
|
||||||
|
void fstWriterSetUpscope(fstWriterContext *ctx);
|
||||||
|
void fstWriterSetValueList(fstWriterContext *ctx, const char *vl);
|
||||||
|
void fstWriterSetVersion(fstWriterContext *ctx, const char *vers);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* reader functions
|
* reader functions
|
||||||
*/
|
*/
|
||||||
void fstReaderClose(void *ctx);
|
|
||||||
void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx);
|
|
||||||
void fstReaderClrFacProcessMaskAll(void *ctx);
|
|
||||||
uint64_t fstReaderGetAliasCount(void *ctx);
|
|
||||||
const char * fstReaderGetCurrentFlatScope(void *ctx);
|
|
||||||
void * fstReaderGetCurrentScopeUserInfo(void *ctx);
|
|
||||||
int fstReaderGetCurrentScopeLen(void *ctx);
|
|
||||||
const char * fstReaderGetDateString(void *ctx);
|
|
||||||
int fstReaderGetDoubleEndianMatchState(void *ctx);
|
|
||||||
uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx);
|
|
||||||
unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx);
|
|
||||||
uint64_t fstReaderGetEndTime(void *ctx);
|
|
||||||
int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx);
|
|
||||||
int fstReaderGetFileType(void *ctx);
|
|
||||||
int fstReaderGetFseekFailed(void *ctx);
|
|
||||||
fstHandle fstReaderGetMaxHandle(void *ctx);
|
|
||||||
uint64_t fstReaderGetMemoryUsedByWriter(void *ctx);
|
|
||||||
uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx);
|
|
||||||
uint64_t fstReaderGetScopeCount(void *ctx);
|
|
||||||
uint64_t fstReaderGetStartTime(void *ctx);
|
|
||||||
signed char fstReaderGetTimescale(void *ctx);
|
|
||||||
int64_t fstReaderGetTimezero(void *ctx);
|
|
||||||
uint64_t fstReaderGetValueChangeSectionCount(void *ctx);
|
|
||||||
char * fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf);
|
|
||||||
uint64_t fstReaderGetVarCount(void *ctx);
|
|
||||||
const char * fstReaderGetVersionString(void *ctx);
|
|
||||||
struct fstHier *fstReaderIterateHier(void *ctx);
|
|
||||||
int fstReaderIterateHierRewind(void *ctx);
|
|
||||||
int fstReaderIterBlocks(void *ctx,
|
|
||||||
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
|
|
||||||
void *user_callback_data_pointer, FILE *vcdhandle);
|
|
||||||
int fstReaderIterBlocks2(void *ctx,
|
|
||||||
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
|
|
||||||
void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len),
|
|
||||||
void *user_callback_data_pointer, FILE *vcdhandle);
|
|
||||||
void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable);
|
|
||||||
void * fstReaderOpen(const char *nam);
|
|
||||||
void * fstReaderOpenForUtilitiesOnly(void);
|
|
||||||
const char * fstReaderPopScope(void *ctx);
|
|
||||||
int fstReaderProcessHier(void *ctx, FILE *vcdhandle);
|
|
||||||
const char * fstReaderPushScope(void *ctx, const char *nam, void *user_info);
|
|
||||||
void fstReaderResetScope(void *ctx);
|
|
||||||
void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx);
|
|
||||||
void fstReaderSetFacProcessMaskAll(void *ctx);
|
|
||||||
void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time);
|
|
||||||
void fstReaderSetUnlimitedTimeRange(void *ctx);
|
|
||||||
void fstReaderSetVcdExtensions(void *ctx, int enable);
|
|
||||||
|
|
||||||
|
typedef struct fstReaderContext fstReaderContext;
|
||||||
|
|
||||||
|
void fstReaderClose(fstReaderContext *ctx);
|
||||||
|
void fstReaderClrFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
|
||||||
|
void fstReaderClrFacProcessMaskAll(fstReaderContext *ctx);
|
||||||
|
uint64_t fstReaderGetAliasCount(fstReaderContext *ctx);
|
||||||
|
const char *fstReaderGetCurrentFlatScope(fstReaderContext *ctx);
|
||||||
|
void *fstReaderGetCurrentScopeUserInfo(fstReaderContext *ctx);
|
||||||
|
int fstReaderGetCurrentScopeLen(fstReaderContext *ctx);
|
||||||
|
const char *fstReaderGetDateString(fstReaderContext *ctx);
|
||||||
|
int fstReaderGetDoubleEndianMatchState(fstReaderContext *ctx);
|
||||||
|
uint64_t fstReaderGetDumpActivityChangeTime(fstReaderContext *ctx, uint32_t idx);
|
||||||
|
unsigned char fstReaderGetDumpActivityChangeValue(fstReaderContext *ctx, uint32_t idx);
|
||||||
|
uint64_t fstReaderGetEndTime(fstReaderContext *ctx);
|
||||||
|
int fstReaderGetFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
|
||||||
|
int fstReaderGetFileType(fstReaderContext *ctx);
|
||||||
|
int fstReaderGetFseekFailed(fstReaderContext *ctx);
|
||||||
|
fstHandle fstReaderGetMaxHandle(fstReaderContext *ctx);
|
||||||
|
uint64_t fstReaderGetMemoryUsedByWriter(fstReaderContext *ctx);
|
||||||
|
uint32_t fstReaderGetNumberDumpActivityChanges(fstReaderContext *ctx);
|
||||||
|
uint64_t fstReaderGetScopeCount(fstReaderContext *ctx);
|
||||||
|
uint64_t fstReaderGetStartTime(fstReaderContext *ctx);
|
||||||
|
signed char fstReaderGetTimescale(fstReaderContext *ctx);
|
||||||
|
int64_t fstReaderGetTimezero(fstReaderContext *ctx);
|
||||||
|
uint64_t fstReaderGetValueChangeSectionCount(fstReaderContext *ctx);
|
||||||
|
char *fstReaderGetValueFromHandleAtTime(fstReaderContext *ctx,
|
||||||
|
uint64_t tim,
|
||||||
|
fstHandle facidx,
|
||||||
|
char *buf);
|
||||||
|
uint64_t fstReaderGetVarCount(fstReaderContext *ctx);
|
||||||
|
const char *fstReaderGetVersionString(fstReaderContext *ctx);
|
||||||
|
struct fstHier *fstReaderIterateHier(fstReaderContext *ctx);
|
||||||
|
int fstReaderIterateHierRewind(fstReaderContext *ctx);
|
||||||
|
int fstReaderIterBlocks(fstReaderContext *ctx,
|
||||||
|
void (*value_change_callback)(void *user_callback_data_pointer,
|
||||||
|
uint64_t time,
|
||||||
|
fstHandle facidx,
|
||||||
|
const unsigned char *value),
|
||||||
|
void *user_callback_data_pointer,
|
||||||
|
FILE *vcdhandle);
|
||||||
|
int fstReaderIterBlocks2(fstReaderContext *ctx,
|
||||||
|
void (*value_change_callback)(void *user_callback_data_pointer,
|
||||||
|
uint64_t time,
|
||||||
|
fstHandle facidx,
|
||||||
|
const unsigned char *value),
|
||||||
|
void (*value_change_callback_varlen)(void *user_callback_data_pointer,
|
||||||
|
uint64_t time,
|
||||||
|
fstHandle facidx,
|
||||||
|
const unsigned char *value,
|
||||||
|
uint32_t len),
|
||||||
|
void *user_callback_data_pointer,
|
||||||
|
FILE *vcdhandle);
|
||||||
|
void fstReaderIterBlocksSetNativeDoublesOnCallback(fstReaderContext *ctx, int enable);
|
||||||
|
fstReaderContext *fstReaderOpen(const char *nam);
|
||||||
|
fstReaderContext *fstReaderOpenForUtilitiesOnly(void);
|
||||||
|
const char *fstReaderPopScope(fstReaderContext *ctx);
|
||||||
|
int fstReaderProcessHier(fstReaderContext *ctx, FILE *vcdhandle);
|
||||||
|
const char *fstReaderPushScope(fstReaderContext *ctx, const char *nam, void *user_info);
|
||||||
|
void fstReaderResetScope(fstReaderContext *ctx);
|
||||||
|
void fstReaderSetFacProcessMask(fstReaderContext *ctx, fstHandle facidx);
|
||||||
|
void fstReaderSetFacProcessMaskAll(fstReaderContext *ctx);
|
||||||
|
void fstReaderSetLimitTimeRange(fstReaderContext *ctx, uint64_t start_time, uint64_t end_time);
|
||||||
|
void fstReaderSetUnlimitedTimeRange(fstReaderContext *ctx);
|
||||||
|
void fstReaderSetVcdExtensions(fstReaderContext *ctx, int enable);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* utility functions
|
* utility functions
|
||||||
*/
|
*/
|
||||||
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */
|
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */
|
||||||
int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
|
int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
|
||||||
int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
|
int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
|
||||||
struct fstETab *fstUtilityExtractEnumTableFromString(const char *s);
|
struct fstETab *fstUtilityExtractEnumTableFromString(const char *s);
|
||||||
void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */
|
void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ std::vector<RTLIL::Design*> pushed_designs;
|
||||||
|
|
||||||
struct DesignPass : public Pass {
|
struct DesignPass : public Pass {
|
||||||
DesignPass() : Pass("design", "save, restore and reset current design") { }
|
DesignPass() : Pass("design", "save, restore and reset current design") { }
|
||||||
~DesignPass() override {
|
void on_shutdown() override {
|
||||||
for (auto &it : saved_designs)
|
for (auto &it : saved_designs)
|
||||||
delete it.second;
|
delete it.second;
|
||||||
saved_designs.clear();
|
saved_designs.clear();
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ struct InternalStatsPass : public Pass {
|
||||||
|
|
||||||
if (json_mode) {
|
if (json_mode) {
|
||||||
log("{\n");
|
log("{\n");
|
||||||
log(" \"creator\": %s,\n", json11::Json(yosys_version_str).dump().c_str());
|
log(" \"creator\": %s,\n", json11::Json(yosys_maybe_version()).dump().c_str());
|
||||||
std::stringstream invocation;
|
std::stringstream invocation;
|
||||||
std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
|
std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
|
||||||
log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());
|
log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ struct LoggerPass : public Pass {
|
||||||
log(" -check-expected\n");
|
log(" -check-expected\n");
|
||||||
log(" verifies that the patterns previously set up by -expect have actually\n");
|
log(" verifies that the patterns previously set up by -expect have actually\n");
|
||||||
log(" been met, then clears the expected log list. If this is not called\n");
|
log(" been met, then clears the expected log list. If this is not called\n");
|
||||||
log(" manually, the check will happen at yosys exist time instead.\n");
|
log(" manually, the check will happen at yosys exit time instead.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -444,7 +444,7 @@ struct StatPass : public Pass {
|
||||||
|
|
||||||
if (json_mode) {
|
if (json_mode) {
|
||||||
log("{\n");
|
log("{\n");
|
||||||
log(" \"creator\": %s,\n", json11::Json(yosys_version_str).dump().c_str());
|
log(" \"creator\": %s,\n", json11::Json(yosys_maybe_version()).dump().c_str());
|
||||||
std::stringstream invocation;
|
std::stringstream invocation;
|
||||||
std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
|
std::copy(args.begin(), args.end(), std::ostream_iterator<std::string>(invocation, " "));
|
||||||
log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());
|
log(" \"invocation\": %s,\n", json11::Json(invocation.str()).dump().c_str());
|
||||||
|
|
|
||||||
|
|
@ -1452,7 +1452,7 @@ struct HierarchyPass : public Pass {
|
||||||
|
|
||||||
bool resize_widths = !keep_portwidths && GetSize(w) != GetSize(conn.second);
|
bool resize_widths = !keep_portwidths && GetSize(w) != GetSize(conn.second);
|
||||||
if (resize_widths && verific_mod && boxed_params)
|
if (resize_widths && verific_mod && boxed_params)
|
||||||
log_warning("Ignoring width mismatch on %s.%s.%s from verific, is port width parametrizable?\n",
|
log_debug("Ignoring width mismatch on %s.%s.%s from verific, is port width parametrizable?\n",
|
||||||
log_id(module), log_id(cell), log_id(conn.first)
|
log_id(module), log_id(cell), log_id(conn.first)
|
||||||
);
|
);
|
||||||
else if (resize_widths) {
|
else if (resize_widths) {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ PEEPOPT_PATTERN = passes/opt/peepopt_shiftmul_right.pmg
|
||||||
PEEPOPT_PATTERN += passes/opt/peepopt_shiftmul_left.pmg
|
PEEPOPT_PATTERN += passes/opt/peepopt_shiftmul_left.pmg
|
||||||
PEEPOPT_PATTERN += passes/opt/peepopt_shiftadd.pmg
|
PEEPOPT_PATTERN += passes/opt/peepopt_shiftadd.pmg
|
||||||
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv.pmg
|
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv.pmg
|
||||||
|
PEEPOPT_PATTERN += passes/opt/peepopt_muldiv_c.pmg
|
||||||
PEEPOPT_PATTERN += passes/opt/peepopt_formal_clockgateff.pmg
|
PEEPOPT_PATTERN += passes/opt/peepopt_formal_clockgateff.pmg
|
||||||
|
|
||||||
passes/opt/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
passes/opt/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
||||||
|
|
|
||||||
|
|
@ -1307,7 +1307,12 @@ skip_fine_alu:
|
||||||
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)) && (keepdc ? assign_map(cell->getPort(ID::B)).is_fully_def() : assign_map(cell->getPort(ID::B)).is_fully_const()))
|
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)) && (keepdc ? assign_map(cell->getPort(ID::B)).is_fully_def() : assign_map(cell->getPort(ID::B)).is_fully_const()))
|
||||||
{
|
{
|
||||||
bool sign_ext = cell->type == ID($sshr) && cell->getParam(ID::A_SIGNED).as_bool();
|
bool sign_ext = cell->type == ID($sshr) && cell->getParam(ID::A_SIGNED).as_bool();
|
||||||
int shift_bits = assign_map(cell->getPort(ID::B)).as_int(cell->type.in(ID($shift), ID($shiftx)) && cell->getParam(ID::B_SIGNED).as_bool());
|
RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B));
|
||||||
|
const bool b_sign_ext = cell->type.in(ID($shift), ID($shiftx)) && cell->getParam(ID::B_SIGNED).as_bool();
|
||||||
|
// We saturate the value to prevent overflow, but note that this could
|
||||||
|
// cause incorrect opimization in the impractical case that A is 2^32 bits
|
||||||
|
// wide
|
||||||
|
int shift_bits = sig_b.as_int_saturating(b_sign_ext);
|
||||||
|
|
||||||
if (cell->type.in(ID($shl), ID($sshl)))
|
if (cell->type.in(ID($shl), ID($sshl)))
|
||||||
shift_bits *= -1;
|
shift_bits *= -1;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,14 @@ bool did_something;
|
||||||
// scratchpad configurations for pmgen
|
// scratchpad configurations for pmgen
|
||||||
int shiftadd_max_ratio;
|
int shiftadd_max_ratio;
|
||||||
|
|
||||||
|
// Helper function, removes LSB 0s
|
||||||
|
SigSpec remove_bottom_padding(SigSpec sig)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (; i < sig.size() - 1 && sig[i] == State::S0; i++);
|
||||||
|
return sig.extract(i, sig.size() - i);
|
||||||
|
}
|
||||||
|
|
||||||
#include "passes/opt/peepopt_pm.h"
|
#include "passes/opt/peepopt_pm.h"
|
||||||
|
|
||||||
struct PeepoptPass : public Pass {
|
struct PeepoptPass : public Pass {
|
||||||
|
|
@ -45,6 +53,8 @@ struct PeepoptPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" * muldiv - Replace (A*B)/B with A\n");
|
log(" * muldiv - Replace (A*B)/B with A\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" * muldiv_c - Replace (A*B)/C with A*(B/C) when C is a const divisible by B.\n");
|
||||||
|
log("\n");
|
||||||
log(" * shiftmul - Replace A>>(B*C) with A'>>(B<<K) where C and K are constants\n");
|
log(" * shiftmul - Replace A>>(B*C) with A'>>(B<<K) where C and K are constants\n");
|
||||||
log(" and A' is derived from A by appropriately inserting padding\n");
|
log(" and A' is derived from A by appropriately inserting padding\n");
|
||||||
log(" into the signal. (right variant)\n");
|
log(" into the signal. (right variant)\n");
|
||||||
|
|
@ -106,6 +116,7 @@ struct PeepoptPass : public Pass {
|
||||||
pm.run_shiftmul_right();
|
pm.run_shiftmul_right();
|
||||||
pm.run_shiftmul_left();
|
pm.run_shiftmul_left();
|
||||||
pm.run_muldiv();
|
pm.run_muldiv();
|
||||||
|
pm.run_muldiv_c();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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);
|
extra_args(args, argidx, design);
|
||||||
pool<Wire*> delete_initattr_wires;
|
pool<Wire*> delete_initattr_wires;
|
||||||
|
|
||||||
for (auto mod : design->modules())
|
for (auto mod : design->all_selected_modules()) {
|
||||||
if (design->selected(mod)) {
|
SigMap assign_map(mod);
|
||||||
SigMap assign_map(mod);
|
for (auto proc : mod->selected_processes()) {
|
||||||
for (auto &proc_it : mod->processes) {
|
proc_arst(mod, proc, assign_map);
|
||||||
if (!design->selected(mod, proc_it.second))
|
if (global_arst.empty() || mod->wire(global_arst) == nullptr)
|
||||||
continue;
|
continue;
|
||||||
proc_arst(mod, proc_it.second, assign_map);
|
std::vector<RTLIL::SigSig> arst_actions;
|
||||||
if (global_arst.empty() || mod->wire(global_arst) == nullptr)
|
for (auto sync : proc->syncs)
|
||||||
continue;
|
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
|
||||||
std::vector<RTLIL::SigSig> arst_actions;
|
for (auto &act : sync->actions) {
|
||||||
for (auto sync : proc_it.second->syncs)
|
RTLIL::SigSpec arst_sig, arst_val;
|
||||||
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
|
for (auto &chunk : act.first.chunks())
|
||||||
for (auto &act : sync->actions) {
|
if (chunk.wire && chunk.wire->attributes.count(ID::init)) {
|
||||||
RTLIL::SigSpec arst_sig, arst_val;
|
RTLIL::SigSpec value = chunk.wire->attributes.at(ID::init);
|
||||||
for (auto &chunk : act.first.chunks())
|
value.extend_u0(chunk.wire->width, false);
|
||||||
if (chunk.wire && chunk.wire->attributes.count(ID::init)) {
|
arst_sig.append(chunk);
|
||||||
RTLIL::SigSpec value = chunk.wire->attributes.at(ID::init);
|
arst_val.append(value.extract(chunk.offset, chunk.width));
|
||||||
value.extend_u0(chunk.wire->width, false);
|
delete_initattr_wires.insert(chunk.wire);
|
||||||
arst_sig.append(chunk);
|
|
||||||
arst_val.append(value.extract(chunk.offset, chunk.width));
|
|
||||||
delete_initattr_wires.insert(chunk.wire);
|
|
||||||
}
|
|
||||||
if (arst_sig.size()) {
|
|
||||||
log("Added global reset to process %s: %s <- %s\n",
|
|
||||||
proc_it.first.c_str(), log_signal(arst_sig), log_signal(arst_val));
|
|
||||||
arst_actions.push_back(RTLIL::SigSig(arst_sig, arst_val));
|
|
||||||
}
|
}
|
||||||
|
if (arst_sig.size()) {
|
||||||
|
log("Added global reset to process %s: %s <- %s\n",
|
||||||
|
proc->name.c_str(), log_signal(arst_sig), log_signal(arst_val));
|
||||||
|
arst_actions.push_back(RTLIL::SigSig(arst_sig, arst_val));
|
||||||
}
|
}
|
||||||
if (!arst_actions.empty()) {
|
}
|
||||||
RTLIL::SyncRule *sync = new RTLIL::SyncRule;
|
if (!arst_actions.empty()) {
|
||||||
sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1;
|
RTLIL::SyncRule *sync = new RTLIL::SyncRule;
|
||||||
sync->signal = mod->wire(global_arst);
|
sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1;
|
||||||
sync->actions = arst_actions;
|
sync->signal = mod->wire(global_arst);
|
||||||
proc_it.second->syncs.push_back(sync);
|
sync->actions = arst_actions;
|
||||||
}
|
proc->syncs.push_back(sync);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto wire : delete_initattr_wires)
|
for (auto wire : delete_initattr_wires)
|
||||||
wire->attributes.erase(ID::init);
|
wire->attributes.erase(ID::init);
|
||||||
|
|
|
||||||
|
|
@ -208,19 +208,15 @@ struct ProcCleanPass : public Pass {
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
for (auto mod : design->modules()) {
|
for (auto mod : design->all_selected_modules()) {
|
||||||
std::vector<RTLIL::Process *> delme;
|
std::vector<RTLIL::Process *> delme;
|
||||||
if (!design->selected(mod))
|
for (auto proc : mod->selected_processes()) {
|
||||||
continue;
|
proc_clean(mod, proc, total_count, quiet);
|
||||||
for (auto &proc_it : mod->processes) {
|
if (proc->syncs.size() == 0 && proc->root_case.switches.size() == 0 &&
|
||||||
if (!design->selected(mod, proc_it.second))
|
proc->root_case.actions.size() == 0) {
|
||||||
continue;
|
|
||||||
proc_clean(mod, proc_it.second, total_count, quiet);
|
|
||||||
if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 &&
|
|
||||||
proc_it.second->root_case.actions.size() == 0) {
|
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str());
|
log("Removing empty process `%s.%s'.\n", log_id(mod), proc->name.c_str());
|
||||||
delme.push_back(proc_it.second);
|
delme.push_back(proc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto proc : delme) {
|
for (auto proc : delme) {
|
||||||
|
|
|
||||||
|
|
@ -306,13 +306,11 @@ struct ProcDffPass : public Pass {
|
||||||
|
|
||||||
extra_args(args, 1, design);
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
for (auto mod : design->modules())
|
for (auto mod : design->all_selected_modules()) {
|
||||||
if (design->selected(mod)) {
|
ConstEval ce(mod);
|
||||||
ConstEval ce(mod);
|
for (auto proc : mod->selected_processes())
|
||||||
for (auto &proc_it : mod->processes)
|
proc_dff(mod, proc, ce);
|
||||||
if (design->selected(mod, proc_it.second))
|
}
|
||||||
proc_dff(mod, proc_it.second, ce);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} ProcDffPass;
|
} ProcDffPass;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -463,11 +463,10 @@ struct ProcDlatchPass : public Pass {
|
||||||
|
|
||||||
extra_args(args, 1, design);
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
for (auto module : design->selected_modules()) {
|
for (auto mod : design->all_selected_modules()) {
|
||||||
proc_dlatch_db_t db(module);
|
proc_dlatch_db_t db(mod);
|
||||||
for (auto &proc_it : module->processes)
|
for (auto proc : mod->selected_processes())
|
||||||
if (design->selected(module, proc_it.second))
|
proc_dlatch(db, proc);
|
||||||
proc_dlatch(db, proc_it.second);
|
|
||||||
db.fixup_muxes();
|
db.fixup_muxes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,13 +91,11 @@ struct ProcInitPass : public Pass {
|
||||||
|
|
||||||
extra_args(args, 1, design);
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
for (auto mod : design->modules())
|
for (auto mod : design->all_selected_modules()) {
|
||||||
if (design->selected(mod)) {
|
SigMap sigmap(mod);
|
||||||
SigMap sigmap(mod);
|
for (auto proc : mod->selected_processes())
|
||||||
for (auto &proc_it : mod->processes)
|
proc_init(mod, sigmap, proc);
|
||||||
if (design->selected(mod, proc_it.second))
|
}
|
||||||
proc_init(mod, sigmap, proc_it.second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} ProcInitPass;
|
} ProcInitPass;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,9 +99,9 @@ struct ProcMemWrPass : public Pass {
|
||||||
|
|
||||||
extra_args(args, 1, design);
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
for (auto module : design->selected_modules()) {
|
for (auto mod : design->all_selected_modules()) {
|
||||||
dict<IdString, int> next_port_id;
|
dict<IdString, int> next_port_id;
|
||||||
for (auto cell : module->cells()) {
|
for (auto cell : mod->cells()) {
|
||||||
if (cell->type.in(ID($memwr), ID($memwr_v2))) {
|
if (cell->type.in(ID($memwr), ID($memwr_v2))) {
|
||||||
bool is_compat = cell->type == ID($memwr);
|
bool is_compat = cell->type == ID($memwr);
|
||||||
IdString memid = cell->parameters.at(ID::MEMID).decode_string();
|
IdString memid = cell->parameters.at(ID::MEMID).decode_string();
|
||||||
|
|
@ -110,9 +110,8 @@ struct ProcMemWrPass : public Pass {
|
||||||
next_port_id[memid] = port_id + 1;
|
next_port_id[memid] = port_id + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto &proc_it : module->processes)
|
for (auto proc : mod->selected_processes())
|
||||||
if (design->selected(module, proc_it.second))
|
proc_memwr(mod, proc, next_port_id);
|
||||||
proc_memwr(module, proc_it.second, next_port_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ProcMemWrPass;
|
} ProcMemWrPass;
|
||||||
|
|
|
||||||
|
|
@ -468,11 +468,9 @@ struct ProcMuxPass : public Pass {
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
for (auto mod : design->modules())
|
for (auto mod : design->all_selected_modules())
|
||||||
if (design->selected(mod))
|
for (auto proc : mod->selected_processes())
|
||||||
for (auto &proc_it : mod->processes)
|
proc_mux(mod, proc, ifxmode);
|
||||||
if (design->selected(mod, proc_it.second))
|
|
||||||
proc_mux(mod, proc_it.second, ifxmode);
|
|
||||||
}
|
}
|
||||||
} ProcMuxPass;
|
} ProcMuxPass;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,15 +127,10 @@ struct ProcPrunePass : public Pass {
|
||||||
|
|
||||||
extra_args(args, 1, design);
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
for (auto mod : design->modules()) {
|
for (auto mod : design->all_selected_modules()) {
|
||||||
if (!design->selected(mod))
|
|
||||||
continue;
|
|
||||||
PruneWorker worker(mod);
|
PruneWorker worker(mod);
|
||||||
for (auto &proc_it : mod->processes) {
|
for (auto proc : mod->selected_processes())
|
||||||
if (!design->selected(mod, proc_it.second))
|
worker.do_process(proc);
|
||||||
continue;
|
|
||||||
worker.do_process(proc_it.second);
|
|
||||||
}
|
|
||||||
total_removed_count += worker.removed_count;
|
total_removed_count += worker.removed_count;
|
||||||
total_promoted_count += worker.promoted_count;
|
total_promoted_count += worker.promoted_count;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,21 +147,17 @@ struct ProcRmdeadPass : public Pass {
|
||||||
extra_args(args, 1, design);
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
int total_counter = 0;
|
int total_counter = 0;
|
||||||
for (auto mod : design->modules()) {
|
for (auto mod : design->all_selected_modules()) {
|
||||||
if (!design->selected(mod))
|
for (auto proc : mod->selected_processes()) {
|
||||||
continue;
|
|
||||||
for (auto &proc_it : mod->processes) {
|
|
||||||
if (!design->selected(mod, proc_it.second))
|
|
||||||
continue;
|
|
||||||
int counter = 0, full_case_counter = 0;
|
int counter = 0, full_case_counter = 0;
|
||||||
for (auto switch_it : proc_it.second->root_case.switches)
|
for (auto switch_it : proc->root_case.switches)
|
||||||
proc_rmdead(switch_it, counter, full_case_counter);
|
proc_rmdead(switch_it, counter, full_case_counter);
|
||||||
if (counter > 0)
|
if (counter > 0)
|
||||||
log("Removed %d dead cases from process %s in module %s.\n", counter,
|
log("Removed %d dead cases from process %s in module %s.\n", counter,
|
||||||
log_id(proc_it.first), log_id(mod));
|
log_id(proc), log_id(mod));
|
||||||
if (full_case_counter > 0)
|
if (full_case_counter > 0)
|
||||||
log("Marked %d switch rules as full_case in process %s in module %s.\n",
|
log("Marked %d switch rules as full_case in process %s in module %s.\n",
|
||||||
full_case_counter, log_id(proc_it.first), log_id(mod));
|
full_case_counter, log_id(proc), log_id(mod));
|
||||||
total_counter += counter;
|
total_counter += counter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,15 +243,10 @@ struct ProcRomPass : public Pass {
|
||||||
|
|
||||||
extra_args(args, 1, design);
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
for (auto mod : design->modules()) {
|
for (auto mod : design->all_selected_modules()) {
|
||||||
if (!design->selected(mod))
|
|
||||||
continue;
|
|
||||||
RomWorker worker(mod);
|
RomWorker worker(mod);
|
||||||
for (auto &proc_it : mod->processes) {
|
for (auto proc : mod->selected_processes())
|
||||||
if (!design->selected(mod, proc_it.second))
|
worker.do_process(proc);
|
||||||
continue;
|
|
||||||
worker.do_process(proc_it.second);
|
|
||||||
}
|
|
||||||
total_count += worker.count;
|
total_count += worker.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,20 @@ struct CutpointPass : public Pass {
|
||||||
|
|
||||||
for (auto module : design->all_selected_modules())
|
for (auto module : design->all_selected_modules())
|
||||||
{
|
{
|
||||||
|
if (module->is_selected_whole()) {
|
||||||
|
log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module));
|
||||||
|
module->new_connections(std::vector<RTLIL::SigSig>());
|
||||||
|
for (auto cell : vector<Cell*>(module->cells()))
|
||||||
|
module->remove(cell);
|
||||||
|
vector<Wire*> output_wires;
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
if (wire->port_output)
|
||||||
|
output_wires.push_back(wire);
|
||||||
|
for (auto wire : output_wires)
|
||||||
|
module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SigMap sigmap(module);
|
SigMap sigmap(module);
|
||||||
pool<SigBit> cutpoint_bits;
|
pool<SigBit> cutpoint_bits;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -691,7 +691,7 @@ struct SatHelper
|
||||||
fprintf(f, " %s\n", stime);
|
fprintf(f, " %s\n", stime);
|
||||||
fprintf(f, "$end\n");
|
fprintf(f, "$end\n");
|
||||||
fprintf(f, "$version\n");
|
fprintf(f, "$version\n");
|
||||||
fprintf(f, " Generated by %s\n", yosys_version_str);
|
fprintf(f, " Generated by %s\n", yosys_maybe_version());
|
||||||
fprintf(f, "$end\n");
|
fprintf(f, "$end\n");
|
||||||
fprintf(f, "$comment\n");
|
fprintf(f, "$comment\n");
|
||||||
fprintf(f, " Generated from SAT problem in module %s (declared at %s)\n",
|
fprintf(f, " Generated from SAT problem in module %s (declared at %s)\n",
|
||||||
|
|
|
||||||
|
|
@ -1546,36 +1546,27 @@ struct SimWorker : SimShared
|
||||||
log(" for %d clock cycle(s)",numcycles);
|
log(" for %d clock cycle(s)",numcycles);
|
||||||
log("\n");
|
log("\n");
|
||||||
bool all_samples = fst_clock.empty();
|
bool all_samples = fst_clock.empty();
|
||||||
|
unsigned int end_cycle = cycles_set ? numcycles*2 : INT_MAX;
|
||||||
|
|
||||||
try {
|
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, end_cycle, [&](uint64_t time) {
|
||||||
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
|
if (verbose)
|
||||||
if (verbose)
|
log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
|
||||||
log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
|
bool did_something = top->setInputs();
|
||||||
bool did_something = top->setInputs();
|
|
||||||
|
|
||||||
if (initial) {
|
if (initial) {
|
||||||
if (!fst_noinit) did_something |= top->setInitState();
|
if (!fst_noinit) did_something |= top->setInitState();
|
||||||
initialize_stable_past();
|
initialize_stable_past();
|
||||||
initial = false;
|
initial = false;
|
||||||
}
|
}
|
||||||
if (did_something)
|
if (did_something)
|
||||||
update(true);
|
update(true);
|
||||||
register_output_step(time);
|
register_output_step(time);
|
||||||
|
|
||||||
bool status = top->checkSignals();
|
bool status = top->checkSignals();
|
||||||
if (status)
|
if (status)
|
||||||
log_error("Signal difference\n");
|
log_error("Signal difference\n");
|
||||||
cycle++;
|
cycle++;
|
||||||
|
});
|
||||||
// Limit to number of cycles if provided
|
|
||||||
if (cycles_set && cycle > numcycles *2)
|
|
||||||
throw fst_end_of_data_exception();
|
|
||||||
if (time==stopCount)
|
|
||||||
throw fst_end_of_data_exception();
|
|
||||||
});
|
|
||||||
} catch(fst_end_of_data_exception) {
|
|
||||||
// end of data detected
|
|
||||||
}
|
|
||||||
|
|
||||||
write_output_files();
|
write_output_files();
|
||||||
delete fst;
|
delete fst;
|
||||||
|
|
@ -2065,7 +2056,7 @@ struct SimWorker : SimShared
|
||||||
|
|
||||||
json.begin_object();
|
json.begin_object();
|
||||||
json.entry("version", "Yosys sim summary");
|
json.entry("version", "Yosys sim summary");
|
||||||
json.entry("generator", yosys_version_str);
|
json.entry("generator", yosys_maybe_version());
|
||||||
json.entry("steps", step);
|
json.entry("steps", step);
|
||||||
json.entry("top", log_id(top->module->name));
|
json.entry("top", log_id(top->module->name));
|
||||||
json.name("assertions");
|
json.name("assertions");
|
||||||
|
|
@ -2248,40 +2239,31 @@ struct SimWorker : SimShared
|
||||||
log("Writing data to `%s`\n", (tb_filename+".txt").c_str());
|
log("Writing data to `%s`\n", (tb_filename+".txt").c_str());
|
||||||
std::ofstream data_file(tb_filename+".txt");
|
std::ofstream data_file(tb_filename+".txt");
|
||||||
std::stringstream initstate;
|
std::stringstream initstate;
|
||||||
try {
|
unsigned int end_cycle = cycles_set ? numcycles*2 : INT_MAX;
|
||||||
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
|
fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, end_cycle, [&](uint64_t time) {
|
||||||
for(auto &item : clocks)
|
for(auto &item : clocks)
|
||||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||||
for(auto &item : inputs)
|
for(auto &item : inputs)
|
||||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||||
for(auto &item : outputs)
|
for(auto &item : outputs)
|
||||||
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
data_file << stringf("%s",fst->valueOf(item.second).c_str());
|
||||||
data_file << stringf("%s\n",Const(time-prev_time).as_string().c_str());
|
data_file << stringf("%s\n",Const(time-prev_time).as_string().c_str());
|
||||||
|
|
||||||
if (time==startCount) {
|
if (time==startCount) {
|
||||||
// initial state
|
// initial state
|
||||||
for(auto var : fst->getVars()) {
|
for(auto var : fst->getVars()) {
|
||||||
if (var.is_reg && !Const::from_string(fst->valueOf(var.id).c_str()).is_fully_undef()) {
|
if (var.is_reg && !Const::from_string(fst->valueOf(var.id).c_str()).is_fully_undef()) {
|
||||||
if (var.scope == scope) {
|
if (var.scope == scope) {
|
||||||
initstate << stringf("\t\tuut.%s = %d'b%s;\n", var.name.c_str(), var.width, fst->valueOf(var.id).c_str());
|
initstate << stringf("\t\tuut.%s = %d'b%s;\n", var.name.c_str(), var.width, fst->valueOf(var.id).c_str());
|
||||||
} else if (var.scope.find(scope+".")==0) {
|
} else if (var.scope.find(scope+".")==0) {
|
||||||
initstate << stringf("\t\tuut.%s.%s = %d'b%s;\n",var.scope.substr(scope.size()+1).c_str(), var.name.c_str(), var.width, fst->valueOf(var.id).c_str());
|
initstate << stringf("\t\tuut.%s.%s = %d'b%s;\n",var.scope.substr(scope.size()+1).c_str(), var.name.c_str(), var.width, fst->valueOf(var.id).c_str());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cycle++;
|
}
|
||||||
prev_time = time;
|
cycle++;
|
||||||
|
prev_time = time;
|
||||||
// Limit to number of cycles if provided
|
});
|
||||||
if (cycles_set && cycle > numcycles *2)
|
|
||||||
throw fst_end_of_data_exception();
|
|
||||||
if (time==stopCount)
|
|
||||||
throw fst_end_of_data_exception();
|
|
||||||
});
|
|
||||||
} catch(fst_end_of_data_exception) {
|
|
||||||
// end of data detected
|
|
||||||
}
|
|
||||||
|
|
||||||
f << stringf("\treg [0:%d] data [0:%d];\n", data_len-1, cycle-1);
|
f << stringf("\treg [0:%d] data [0:%d];\n", data_len-1, cycle-1);
|
||||||
f << "\tinitial begin;\n";
|
f << "\tinitial begin;\n";
|
||||||
|
|
@ -2344,7 +2326,7 @@ struct VCDWriter : public OutputWriter
|
||||||
void write(std::map<int, bool> &use_signal) override
|
void write(std::map<int, bool> &use_signal) override
|
||||||
{
|
{
|
||||||
if (!vcdfile.is_open()) return;
|
if (!vcdfile.is_open()) return;
|
||||||
vcdfile << stringf("$version %s $end\n", worker->date ? yosys_version_str : "Yosys");
|
vcdfile << stringf("$version %s $end\n", worker->date ? yosys_maybe_version() : "Yosys");
|
||||||
|
|
||||||
if (worker->date) {
|
if (worker->date) {
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(nullptr);
|
||||||
|
|
@ -2400,7 +2382,7 @@ struct VCDWriter : public OutputWriter
|
||||||
struct FSTWriter : public OutputWriter
|
struct FSTWriter : public OutputWriter
|
||||||
{
|
{
|
||||||
FSTWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) {
|
FSTWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) {
|
||||||
fstfile = (struct fstContext *)fstWriterCreate(filename.c_str(),1);
|
fstfile = fstWriterCreate(filename.c_str(),1);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~FSTWriter()
|
virtual ~FSTWriter()
|
||||||
|
|
@ -2412,7 +2394,7 @@ struct FSTWriter : public OutputWriter
|
||||||
{
|
{
|
||||||
if (!fstfile) return;
|
if (!fstfile) return;
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(nullptr);
|
||||||
fstWriterSetVersion(fstfile, worker->date ? yosys_version_str : "Yosys");
|
fstWriterSetVersion(fstfile, worker->date ? yosys_maybe_version() : "Yosys");
|
||||||
if (worker->date)
|
if (worker->date)
|
||||||
fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
|
fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
|
||||||
else
|
else
|
||||||
|
|
@ -2456,7 +2438,7 @@ struct FSTWriter : public OutputWriter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fstContext *fstfile = nullptr;
|
struct fstWriterContext *fstfile = nullptr;
|
||||||
std::map<int,fstHandle> mapping;
|
std::map<int,fstHandle> mapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
|
||||||
vector<int> lut_costs, bool dff_mode, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
|
vector<int> lut_costs, bool dff_mode, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
|
||||||
bool show_tempdir, std::string box_file, std::string lut_file,
|
bool show_tempdir, std::string box_file, std::string lut_file,
|
||||||
std::vector<std::string> liberty_files, std::string wire_delay, std::string tempdir_name,
|
std::vector<std::string> liberty_files, std::string wire_delay, std::string tempdir_name,
|
||||||
std::string constr_file, std::vector<std::string> dont_use_cells)
|
std::string constr_file, std::vector<std::string> dont_use_cells, std::vector<std::string> genlib_files)
|
||||||
{
|
{
|
||||||
std::string abc9_script;
|
std::string abc9_script;
|
||||||
|
|
||||||
|
|
@ -186,6 +186,10 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
|
||||||
}
|
}
|
||||||
if (!constr_file.empty())
|
if (!constr_file.empty())
|
||||||
abc9_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str());
|
abc9_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str());
|
||||||
|
} else if (!genlib_files.empty()) {
|
||||||
|
for (std::string genlib_file : genlib_files) {
|
||||||
|
abc9_script += stringf("read_genlib \"%s\"; ", genlib_file.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_assert(!box_file.empty());
|
log_assert(!box_file.empty());
|
||||||
|
|
@ -384,9 +388,14 @@ struct Abc9ExePass : public Pass {
|
||||||
log(" read the given Liberty file as a description of the target cell library.\n");
|
log(" read the given Liberty file as a description of the target cell library.\n");
|
||||||
log(" this option can be used multiple times.\n");
|
log(" this option can be used multiple times.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -genlib <file>\n");
|
||||||
|
log(" read the given genlib file as a description of the target cell library.\n");
|
||||||
|
log(" this option can be used multiple times.\n");
|
||||||
|
log("\n");
|
||||||
log(" -dont_use <cell_name>\n");
|
log(" -dont_use <cell_name>\n");
|
||||||
log(" avoid usage of the technology cell <cell_name> when mapping the design.\n");
|
log(" avoid usage of the technology cell <cell_name> when mapping the design.\n");
|
||||||
log(" this option can be used multiple times.\n");
|
log(" this option can be used multiple times. only supported with Liberty\n");
|
||||||
|
log(" cell libraries.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -D <picoseconds>\n");
|
log(" -D <picoseconds>\n");
|
||||||
log(" set delay target. the string {D} in the default scripts above is\n");
|
log(" set delay target. the string {D} in the default scripts above is\n");
|
||||||
|
|
@ -441,7 +450,7 @@ struct Abc9ExePass : public Pass {
|
||||||
|
|
||||||
std::string exe_file = yosys_abc_executable;
|
std::string exe_file = yosys_abc_executable;
|
||||||
std::string script_file, clk_str, box_file, lut_file, constr_file;
|
std::string script_file, clk_str, box_file, lut_file, constr_file;
|
||||||
std::vector<std::string> liberty_files, dont_use_cells;
|
std::vector<std::string> liberty_files, genlib_files, dont_use_cells;
|
||||||
std::string delay_target, lutin_shared = "-S 1", wire_delay;
|
std::string delay_target, lutin_shared = "-S 1", wire_delay;
|
||||||
std::string tempdir_name;
|
std::string tempdir_name;
|
||||||
bool fast_mode = false, dff_mode = false;
|
bool fast_mode = false, dff_mode = false;
|
||||||
|
|
@ -530,9 +539,15 @@ struct Abc9ExePass : public Pass {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (arg == "-liberty" && argidx+1 < args.size()) {
|
if (arg == "-liberty" && argidx+1 < args.size()) {
|
||||||
|
rewrite_filename(args[argidx+1]);
|
||||||
liberty_files.push_back(args[++argidx]);
|
liberty_files.push_back(args[++argidx]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-genlib" && argidx+1 < args.size()) {
|
||||||
|
rewrite_filename(args[argidx+1]);
|
||||||
|
genlib_files.push_back(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-dont_use" && argidx+1 < args.size()) {
|
if (arg == "-dont_use" && argidx+1 < args.size()) {
|
||||||
dont_use_cells.push_back(args[++argidx]);
|
dont_use_cells.push_back(args[++argidx]);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -601,11 +616,13 @@ struct Abc9ExePass : public Pass {
|
||||||
if (tempdir_name.empty())
|
if (tempdir_name.empty())
|
||||||
log_cmd_error("abc9_exe '-cwd' option is mandatory.\n");
|
log_cmd_error("abc9_exe '-cwd' option is mandatory.\n");
|
||||||
|
|
||||||
|
if (!genlib_files.empty() && !dont_use_cells.empty())
|
||||||
|
log_cmd_error("abc9_exe '-genlib' is incompatible with '-dont_use'.\n");
|
||||||
|
|
||||||
abc9_module(design, script_file, exe_file, lut_costs, dff_mode,
|
abc9_module(design, script_file, exe_file, lut_costs, dff_mode,
|
||||||
delay_target, lutin_shared, fast_mode, show_tempdir,
|
delay_target, lutin_shared, fast_mode, show_tempdir,
|
||||||
box_file, lut_file, liberty_files, wire_delay, tempdir_name,
|
box_file, lut_file, liberty_files, wire_delay, tempdir_name,
|
||||||
constr_file, dont_use_cells);
|
constr_file, dont_use_cells, genlib_files);
|
||||||
}
|
}
|
||||||
} Abc9ExePass;
|
} Abc9ExePass;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ void check(RTLIL::Design *design, bool dff_mode)
|
||||||
log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type));
|
log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type));
|
||||||
|
|
||||||
if (derived_module->has_processes())
|
if (derived_module->has_processes())
|
||||||
Pass::call_on_module(design, derived_module, "proc");
|
Pass::call_on_module(design, derived_module, "proc -noopt");
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto derived_cell : derived_module->cells()) {
|
for (auto derived_cell : derived_module->cells()) {
|
||||||
|
|
@ -204,7 +204,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
|
||||||
|
|
||||||
if (!unmap_design->module(derived_type)) {
|
if (!unmap_design->module(derived_type)) {
|
||||||
if (derived_module->has_processes())
|
if (derived_module->has_processes())
|
||||||
Pass::call_on_module(design, derived_module, "proc");
|
Pass::call_on_module(design, derived_module, "proc -noopt");
|
||||||
|
|
||||||
if (derived_module->get_bool_attribute(ID::abc9_flop)) {
|
if (derived_module->get_bool_attribute(ID::abc9_flop)) {
|
||||||
for (auto derived_cell : derived_module->cells())
|
for (auto derived_cell : derived_module->cells())
|
||||||
|
|
@ -834,7 +834,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
|
||||||
holes_cell = holes_module->addCell(NEW_ID, cell->type);
|
holes_cell = holes_module->addCell(NEW_ID, cell->type);
|
||||||
|
|
||||||
if (box_module->has_processes())
|
if (box_module->has_processes())
|
||||||
Pass::call_on_module(design, box_module, "proc");
|
Pass::call_on_module(design, box_module, "proc -noopt");
|
||||||
|
|
||||||
int box_inputs = 0;
|
int box_inputs = 0;
|
||||||
for (auto port_name : box_ports.at(cell->type)) {
|
for (auto port_name : box_ports.at(cell->type)) {
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ struct AbcNewPass : public ScriptPass {
|
||||||
log(" -constr <file>\n");
|
log(" -constr <file>\n");
|
||||||
log(" -dont_use <cell_name>\n");
|
log(" -dont_use <cell_name>\n");
|
||||||
log(" -liberty <file>\n");
|
log(" -liberty <file>\n");
|
||||||
|
log(" -genlib <file>\n");
|
||||||
log(" these options are passed on to the 'abc9_exe' command which invokes\n");
|
log(" these options are passed on to the 'abc9_exe' command which invokes\n");
|
||||||
log(" the ABC tool on individual modules of the design. please see\n");
|
log(" the ABC tool on individual modules of the design. please see\n");
|
||||||
log(" 'help abc9_exe' for more details\n");
|
log(" 'help abc9_exe' for more details\n");
|
||||||
|
|
@ -90,7 +91,7 @@ struct AbcNewPass : public ScriptPass {
|
||||||
if (args[argidx] == "-exe" || args[argidx] == "-script" ||
|
if (args[argidx] == "-exe" || args[argidx] == "-script" ||
|
||||||
args[argidx] == "-D" ||
|
args[argidx] == "-D" ||
|
||||||
args[argidx] == "-constr" || args[argidx] == "-dont_use" ||
|
args[argidx] == "-constr" || args[argidx] == "-dont_use" ||
|
||||||
args[argidx] == "-liberty") {
|
args[argidx] == "-liberty" || args[argidx] == "-genlib") {
|
||||||
abc_exe_options += " " + args[argidx] + " " + args[argidx + 1];
|
abc_exe_options += " " + args[argidx] + " " + args[argidx + 1];
|
||||||
argidx++;
|
argidx++;
|
||||||
} else if (args[argidx] == "-run" && argidx + 1 < args.size()) {
|
} else if (args[argidx] == "-run" && argidx + 1 < args.size()) {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,13 @@
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Displays the current cache settings and cached paths.\n");
|
log("Displays the current cache settings and cached paths.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" libcache {-verbose|-quiet}\n");
|
||||||
|
log("\n");
|
||||||
|
log("Controls cache use logging.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -verbose Enable printing info when cache is used\n");
|
||||||
|
log(" -quiet Disable printing info when cache is used (default)\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *) override
|
void execute(std::vector<std::string> args, RTLIL::Design *) override
|
||||||
{
|
{
|
||||||
|
|
@ -55,6 +62,8 @@
|
||||||
bool purge = false;
|
bool purge = false;
|
||||||
bool all = false;
|
bool all = false;
|
||||||
bool list = false;
|
bool list = false;
|
||||||
|
bool verbose = false;
|
||||||
|
bool quiet = false;
|
||||||
std::vector<std::string> paths;
|
std::vector<std::string> paths;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
|
|
@ -79,16 +88,24 @@
|
||||||
list = true;
|
list = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-verbose") {
|
||||||
|
verbose = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-quiet") {
|
||||||
|
quiet = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
std::string fname = args[argidx];
|
std::string fname = args[argidx];
|
||||||
rewrite_filename(fname);
|
rewrite_filename(fname);
|
||||||
paths.push_back(fname);
|
paths.push_back(fname);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int modes = enable + disable + purge + list;
|
int modes = enable + disable + purge + list + verbose + quiet;
|
||||||
if (modes == 0)
|
if (modes == 0)
|
||||||
log_cmd_error("At least one of -enable, -disable, -purge or -list is required.\n");
|
log_cmd_error("At least one of -enable, -disable, -purge, -list,\n-verbose, or -quiet is required.\n");
|
||||||
if (modes > 1)
|
if (modes > 1)
|
||||||
log_cmd_error("Only one of -enable, -disable, -purge or -list may be present.\n");
|
log_cmd_error("Only one of -enable, -disable, -purge, -list,\n-verbose, or -quiet may be present.\n");
|
||||||
|
|
||||||
if (all && !paths.empty())
|
if (all && !paths.empty())
|
||||||
log_cmd_error("The -all option cannot be combined with a list of paths.\n");
|
log_cmd_error("The -all option cannot be combined with a list of paths.\n");
|
||||||
|
|
@ -121,6 +138,10 @@
|
||||||
LibertyAstCache::instance.cache_path.erase(path);
|
LibertyAstCache::instance.cache_path.erase(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (verbose) {
|
||||||
|
LibertyAstCache::instance.verbose = true;
|
||||||
|
} else if (quiet) {
|
||||||
|
LibertyAstCache::instance.verbose = false;
|
||||||
} else {
|
} else {
|
||||||
log_assert(false);
|
log_assert(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ std::shared_ptr<const LibertyAst> LibertyAstCache::cached_ast(const std::string
|
||||||
auto it = cached.find(fname);
|
auto it = cached.find(fname);
|
||||||
if (it == cached.end())
|
if (it == cached.end())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
log("Using cached data for liberty file `%s'\n", fname.c_str());
|
if (verbose)
|
||||||
|
log("Using cached data for liberty file `%s'\n", fname.c_str());
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,7 +52,8 @@ void LibertyAstCache::parsed_ast(const std::string &fname, const std::shared_ptr
|
||||||
bool should_cache = it == cache_path.end() ? cache_by_default : it->second;
|
bool should_cache = it == cache_path.end() ? cache_by_default : it->second;
|
||||||
if (!should_cache)
|
if (!should_cache)
|
||||||
return;
|
return;
|
||||||
log("Caching data for liberty file `%s'\n", fname.c_str());
|
if (verbose)
|
||||||
|
log("Caching data for liberty file `%s'\n", fname.c_str());
|
||||||
cached.emplace(fname, ast);
|
cached.emplace(fname, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,7 @@ namespace Yosys
|
||||||
dict<std::string, std::shared_ptr<const LibertyAst>> cached;
|
dict<std::string, std::shared_ptr<const LibertyAst>> cached;
|
||||||
|
|
||||||
bool cache_by_default = false;
|
bool cache_by_default = false;
|
||||||
|
bool verbose = false;
|
||||||
dict<std::string, bool> cache_path;
|
dict<std::string, bool> cache_path;
|
||||||
|
|
||||||
std::shared_ptr<const LibertyAst> cached_ast(const std::string &fname);
|
std::shared_ptr<const LibertyAst> cached_ast(const std::string &fname);
|
||||||
|
|
|
||||||
|
|
@ -35,3 +35,25 @@ ram huge $__XILINX_URAM_ {
|
||||||
wrbe_separate;
|
wrbe_separate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ram huge $__XILINX_URAM_SP_ {
|
||||||
|
abits 11;
|
||||||
|
width 144;
|
||||||
|
cost 1024;
|
||||||
|
option "BYTEWIDTH" 8 byte 8;
|
||||||
|
option "BYTEWIDTH" 9 byte 9;
|
||||||
|
init zero;
|
||||||
|
port srsw "A" {
|
||||||
|
clock anyedge "C";
|
||||||
|
clken;
|
||||||
|
rdwr no_change;
|
||||||
|
rdinit zero;
|
||||||
|
portoption "RST_MODE" "SYNC" {
|
||||||
|
rdsrst zero ungated;
|
||||||
|
}
|
||||||
|
portoption "RST_MODE" "ASYNC" {
|
||||||
|
rdarst zero;
|
||||||
|
}
|
||||||
|
wrbe_separate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,3 +150,141 @@ module $__XILINX_URAM_ (...);
|
||||||
.SLEEP(1'b0)
|
.SLEEP(1'b0)
|
||||||
);
|
);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module $__XILINX_URAM_SP_ (...);
|
||||||
|
parameter OPTION_BYTEWIDTH = 8;
|
||||||
|
localparam WR_BE_WIDTH = 144 / OPTION_BYTEWIDTH;
|
||||||
|
|
||||||
|
parameter CLK_C_POL = 1;
|
||||||
|
parameter PORT_A_CLK_POL = 1;
|
||||||
|
parameter PORT_A_OPTION_RST_MODE = "SYNC";
|
||||||
|
|
||||||
|
input CLK_C;
|
||||||
|
|
||||||
|
input PORT_A_CLK;
|
||||||
|
input PORT_A_CLK_EN;
|
||||||
|
input PORT_A_RD_SRST;
|
||||||
|
input PORT_A_RD_ARST;
|
||||||
|
input PORT_A_WR_EN;
|
||||||
|
input [WR_BE_WIDTH-1:0] PORT_A_WR_BE;
|
||||||
|
input [10:0] PORT_A_ADDR;
|
||||||
|
input [143:0] PORT_A_WR_DATA;
|
||||||
|
output [143:0] PORT_A_RD_DATA;
|
||||||
|
|
||||||
|
wire [71:0] DIN_A, DIN_B, DOUT_A, DOUT_B;
|
||||||
|
|
||||||
|
generate
|
||||||
|
if (OPTION_BYTEWIDTH == 8) begin
|
||||||
|
assign DIN_A = PORT_A_WR_DATA[71:0];
|
||||||
|
assign DIN_B = PORT_A_WR_DATA[143:72];
|
||||||
|
assign PORT_A_RD_DATA = {DOUT_B, DOUT_A};
|
||||||
|
end else begin
|
||||||
|
assign DIN_A = {
|
||||||
|
PORT_A_WR_DATA[71],
|
||||||
|
PORT_A_WR_DATA[62],
|
||||||
|
PORT_A_WR_DATA[53],
|
||||||
|
PORT_A_WR_DATA[44],
|
||||||
|
PORT_A_WR_DATA[35],
|
||||||
|
PORT_A_WR_DATA[26],
|
||||||
|
PORT_A_WR_DATA[17],
|
||||||
|
PORT_A_WR_DATA[8],
|
||||||
|
PORT_A_WR_DATA[70:63],
|
||||||
|
PORT_A_WR_DATA[61:54],
|
||||||
|
PORT_A_WR_DATA[52:45],
|
||||||
|
PORT_A_WR_DATA[43:36],
|
||||||
|
PORT_A_WR_DATA[34:27],
|
||||||
|
PORT_A_WR_DATA[25:18],
|
||||||
|
PORT_A_WR_DATA[16:9],
|
||||||
|
PORT_A_WR_DATA[7:0]
|
||||||
|
};
|
||||||
|
assign DIN_B = {
|
||||||
|
PORT_A_WR_DATA[72+71],
|
||||||
|
PORT_A_WR_DATA[72+62],
|
||||||
|
PORT_A_WR_DATA[72+53],
|
||||||
|
PORT_A_WR_DATA[72+44],
|
||||||
|
PORT_A_WR_DATA[72+35],
|
||||||
|
PORT_A_WR_DATA[72+26],
|
||||||
|
PORT_A_WR_DATA[72+17],
|
||||||
|
PORT_A_WR_DATA[72+8],
|
||||||
|
PORT_A_WR_DATA[72+70:72+63],
|
||||||
|
PORT_A_WR_DATA[72+61:72+54],
|
||||||
|
PORT_A_WR_DATA[72+52:72+45],
|
||||||
|
PORT_A_WR_DATA[72+43:72+36],
|
||||||
|
PORT_A_WR_DATA[72+34:72+27],
|
||||||
|
PORT_A_WR_DATA[72+25:72+18],
|
||||||
|
PORT_A_WR_DATA[72+16:72+ 9],
|
||||||
|
PORT_A_WR_DATA[72+ 7:72+ 0]
|
||||||
|
};
|
||||||
|
assign PORT_A_RD_DATA = {
|
||||||
|
DOUT_B[71],
|
||||||
|
DOUT_B[63:56],
|
||||||
|
DOUT_B[70],
|
||||||
|
DOUT_B[55:48],
|
||||||
|
DOUT_B[69],
|
||||||
|
DOUT_B[47:40],
|
||||||
|
DOUT_B[68],
|
||||||
|
DOUT_B[39:32],
|
||||||
|
DOUT_B[67],
|
||||||
|
DOUT_B[31:24],
|
||||||
|
DOUT_B[66],
|
||||||
|
DOUT_B[23:16],
|
||||||
|
DOUT_B[65],
|
||||||
|
DOUT_B[15:8],
|
||||||
|
DOUT_B[64],
|
||||||
|
DOUT_B[7:0],
|
||||||
|
DOUT_A[71],
|
||||||
|
DOUT_A[63:56],
|
||||||
|
DOUT_A[70],
|
||||||
|
DOUT_A[55:48],
|
||||||
|
DOUT_A[69],
|
||||||
|
DOUT_A[47:40],
|
||||||
|
DOUT_A[68],
|
||||||
|
DOUT_A[39:32],
|
||||||
|
DOUT_A[67],
|
||||||
|
DOUT_A[31:24],
|
||||||
|
DOUT_A[66],
|
||||||
|
DOUT_A[23:16],
|
||||||
|
DOUT_A[65],
|
||||||
|
DOUT_A[15:8],
|
||||||
|
DOUT_A[64],
|
||||||
|
DOUT_A[7:0]
|
||||||
|
};
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
URAM288 #(
|
||||||
|
.BWE_MODE_A(OPTION_BYTEWIDTH == 8 ? "PARITY_INDEPENDENT" : "PARITY_INTERLEAVED"),
|
||||||
|
.BWE_MODE_B(OPTION_BYTEWIDTH == 8 ? "PARITY_INDEPENDENT" : "PARITY_INTERLEAVED"),
|
||||||
|
.EN_AUTO_SLEEP_MODE("FALSE"),
|
||||||
|
.IREG_PRE_A("FALSE"),
|
||||||
|
.IREG_PRE_B("FALSE"),
|
||||||
|
.IS_CLK_INVERTED(!CLK_C_POL),
|
||||||
|
.OREG_A("FALSE"),
|
||||||
|
.OREG_B("FALSE"),
|
||||||
|
.RST_MODE_A(PORT_A_OPTION_RST_MODE),
|
||||||
|
.RST_MODE_B(PORT_A_OPTION_RST_MODE),
|
||||||
|
) _TECHMAP_REPLACE_ (
|
||||||
|
.ADDR_A({11'b0, PORT_A_ADDR, 1'b0}),
|
||||||
|
.BWE_A(PORT_A_WR_BE[WR_BE_WIDTH/2-1:0]),
|
||||||
|
.EN_A(PORT_A_CLK_EN),
|
||||||
|
.RDB_WR_A(PORT_A_WR_EN),
|
||||||
|
.INJECT_DBITERR_A(1'b0),
|
||||||
|
.INJECT_SBITERR_A(1'b0),
|
||||||
|
.RST_A(PORT_A_OPTION_RST_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
|
||||||
|
.DIN_A(DIN_A),
|
||||||
|
.DOUT_A(DOUT_A),
|
||||||
|
|
||||||
|
.ADDR_B({11'b0, PORT_A_ADDR, 1'b1}),
|
||||||
|
.BWE_B(PORT_A_WR_BE[WR_BE_WIDTH-1:WR_BE_WIDTH/2]),
|
||||||
|
.EN_B(PORT_A_CLK_EN),
|
||||||
|
.RDB_WR_B(PORT_A_WR_EN),
|
||||||
|
.INJECT_DBITERR_B(1'b0),
|
||||||
|
.INJECT_SBITERR_B(1'b0),
|
||||||
|
.RST_B(PORT_A_OPTION_RST_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
|
||||||
|
.DIN_B(DIN_B),
|
||||||
|
.DOUT_B(DOUT_B),
|
||||||
|
|
||||||
|
.CLK(CLK_C),
|
||||||
|
.SLEEP(1'b0)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
|
|
|
||||||
10
tests/aiger/io.ys
Normal file
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
|
||||||
|
|
@ -79,7 +79,6 @@ module sp_write_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
|
||||||
rdata_a <= 'h0;
|
rdata_a <= 'h0;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
// A port
|
// A port
|
||||||
if (wren_a)
|
if (wren_a)
|
||||||
|
|
@ -111,7 +110,6 @@ module sp_read_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
|
||||||
rdata_a <= 'h0;
|
rdata_a <= 'h0;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
// A port
|
// A port
|
||||||
if (wren_a)
|
if (wren_a)
|
||||||
|
|
@ -120,3 +118,31 @@ module sp_read_first (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
|
||||||
rdata_a <= mem[addr_a];
|
rdata_a <= mem[addr_a];
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module sp_read_or_write (clk, wren_a, rden_a, addr_a, wdata_a, rdata_a);
|
||||||
|
|
||||||
|
parameter ABITS = 11;
|
||||||
|
parameter WIDTH = 144;
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
input wren_a, rden_a;
|
||||||
|
input [ABITS-1:0] addr_a;
|
||||||
|
input [WIDTH-1:0] wdata_a;
|
||||||
|
output reg [WIDTH-1:0] rdata_a;
|
||||||
|
|
||||||
|
(* ram_style = "huge" *)
|
||||||
|
reg [WIDTH-1:0] mem [0:2**ABITS-1];
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
initial begin
|
||||||
|
rdata_a <= 'h0;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (wren_a)
|
||||||
|
mem[addr_a] <= wdata_a;
|
||||||
|
else if (rden_a)
|
||||||
|
rdata_a <= mem[addr_a];
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -58,3 +58,13 @@ select -assert-count 1 t:URAM288
|
||||||
# see above for details
|
# see above for details
|
||||||
select -assert-count 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i
|
select -assert-count 1 t:URAM288 %co:+[DOUT_A] w:rdata_a %i
|
||||||
select -assert-none 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i
|
select -assert-none 1 t:URAM288 %co:+[DOUT_B] w:rdata_a %i
|
||||||
|
|
||||||
|
# sp read or write for size 2048 x 144b
|
||||||
|
# the two URAM ports A and B are concatenated, with port A serving LSBs and port B serving MSBs
|
||||||
|
design -reset
|
||||||
|
read_verilog priority_memory.v
|
||||||
|
synth_xilinx -family xcup -top sp_read_or_write -noiopad
|
||||||
|
select -assert-count 1 t:URAM288
|
||||||
|
# we expect no more than 1 LUT2 to control the hardware enable ports
|
||||||
|
# see above for details about this command
|
||||||
|
select -assert-max 1 t:LUT* n:*blif* %d
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
libcache -verbose
|
||||||
libcache -enable busdef.lib
|
libcache -enable busdef.lib
|
||||||
|
|
||||||
logger -expect log "Caching is disabled by default." 1
|
logger -expect log "Caching is disabled by default." 1
|
||||||
|
|
@ -14,8 +15,8 @@ logger -expect log "Caching data" 1
|
||||||
read_liberty -lib busdef.lib; design -reset
|
read_liberty -lib busdef.lib; design -reset
|
||||||
logger -check-expected
|
logger -check-expected
|
||||||
|
|
||||||
logger -expect log "Using caching data" 1
|
logger -expect log "Using cached data" 1
|
||||||
log Using caching data
|
log Using cached data
|
||||||
read_liberty normal.lib; design -reset
|
read_liberty normal.lib; design -reset
|
||||||
logger -check-expected
|
logger -check-expected
|
||||||
|
|
||||||
|
|
@ -23,6 +24,13 @@ logger -expect log "Using cached data" 1
|
||||||
read_liberty -lib busdef.lib; design -reset
|
read_liberty -lib busdef.lib; design -reset
|
||||||
logger -check-expected
|
logger -check-expected
|
||||||
|
|
||||||
|
libcache -quiet
|
||||||
|
logger -expect log "Using cached data" 1
|
||||||
|
log Using cached data
|
||||||
|
read_liberty -lib busdef.lib; design -reset
|
||||||
|
logger -check-expected
|
||||||
|
libcache -verbose
|
||||||
|
|
||||||
libcache -purge busdef.lib
|
libcache -purge busdef.lib
|
||||||
|
|
||||||
logger -expect log "Caching is disabled by default." 1
|
logger -expect log "Caching is disabled by default." 1
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,11 @@ module top (
|
||||||
output wire [7:0] sshr_uu,
|
output wire [7:0] sshr_uu,
|
||||||
output wire signed [7:0] sshr_us,
|
output wire signed [7:0] sshr_us,
|
||||||
output wire [7:0] sshr_su,
|
output wire [7:0] sshr_su,
|
||||||
output wire signed [7:0] sshr_ss
|
output wire signed [7:0] sshr_ss,
|
||||||
|
output wire [7:0] shiftx_uu,
|
||||||
|
output wire signed [7:0] shiftx_us,
|
||||||
|
output wire [7:0] shiftx_su,
|
||||||
|
output wire signed [7:0] shiftx_ss
|
||||||
);
|
);
|
||||||
assign shl_uu = in_u << 20;
|
assign shl_uu = in_u << 20;
|
||||||
assign shl_us = in_u << 20;
|
assign shl_us = in_u << 20;
|
||||||
|
|
@ -38,9 +42,20 @@ module top (
|
||||||
assign sshr_us = in_u >>> 20;
|
assign sshr_us = in_u >>> 20;
|
||||||
assign sshr_su = in_s >>> 20;
|
assign sshr_su = in_s >>> 20;
|
||||||
assign sshr_ss = in_s >>> 20;
|
assign sshr_ss = in_s >>> 20;
|
||||||
|
wire [7:0] shamt = 20;
|
||||||
|
assign shiftx_uu = in_u[shamt +: 8];
|
||||||
|
assign shiftx_us = in_u[shamt +: 8];
|
||||||
|
assign shiftx_su = in_s[shamt +: 8];
|
||||||
|
assign shiftx_ss = in_s[shamt +: 8];
|
||||||
endmodule
|
endmodule
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
|
select -assert-count 4 t:$shl
|
||||||
|
select -assert-count 4 t:$shr
|
||||||
|
select -assert-count 4 t:$sshl
|
||||||
|
select -assert-count 4 t:$sshr
|
||||||
|
select -assert-count 4 t:$shiftx
|
||||||
|
|
||||||
equiv_opt opt_expr
|
equiv_opt opt_expr
|
||||||
|
|
||||||
design -load postopt
|
design -load postopt
|
||||||
|
|
@ -48,3 +63,98 @@ select -assert-none t:$shl
|
||||||
select -assert-none t:$shr
|
select -assert-none t:$shr
|
||||||
select -assert-none t:$sshl
|
select -assert-none t:$sshl
|
||||||
select -assert-none t:$sshr
|
select -assert-none t:$sshr
|
||||||
|
select -assert-none t:$shiftx
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module top (
|
||||||
|
input wire [3:0] in,
|
||||||
|
output wire [7:0] shl,
|
||||||
|
output wire [7:0] shr,
|
||||||
|
output wire [7:0] sshl,
|
||||||
|
output wire [7:0] sshr,
|
||||||
|
output wire [7:0] shiftx,
|
||||||
|
|
||||||
|
output wire [7:0] shl_s,
|
||||||
|
output wire [7:0] shr_s,
|
||||||
|
output wire [7:0] sshl_s,
|
||||||
|
output wire [7:0] sshr_s,
|
||||||
|
output wire [7:0] shiftx_s,
|
||||||
|
);
|
||||||
|
assign shl = in << 36'hfffffffff;
|
||||||
|
assign shr = in >> 36'hfffffffff;
|
||||||
|
assign sshl = in <<< 36'hfffffffff;
|
||||||
|
assign sshr = in >>> 36'hfffffffff;
|
||||||
|
assign shiftx = in[36'hfffffffff +: 8];
|
||||||
|
|
||||||
|
wire signed [35:0] shamt = 36'hfffffffff;
|
||||||
|
assign shl_s = in << shamt;
|
||||||
|
assign shr_s = in >> shamt;
|
||||||
|
assign sshl_s = in <<< shamt;
|
||||||
|
assign sshr_s = in >>> shamt;
|
||||||
|
assign shiftx_s = in[shamt +: 8];
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
select -assert-count 2 t:$shl
|
||||||
|
select -assert-count 2 t:$shr
|
||||||
|
select -assert-count 2 t:$sshl
|
||||||
|
select -assert-count 2 t:$sshr
|
||||||
|
select -assert-count 1 t:$shiftx
|
||||||
|
|
||||||
|
equiv_opt opt_expr
|
||||||
|
|
||||||
|
design -load postopt
|
||||||
|
select -assert-none t:$shl
|
||||||
|
select -assert-none t:$shr
|
||||||
|
select -assert-none t:$sshl
|
||||||
|
select -assert-none t:$sshr
|
||||||
|
select -assert-none t:$shiftx
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
|
||||||
|
read_verilog <<EOT
|
||||||
|
module top (
|
||||||
|
input wire [3:0] in,
|
||||||
|
output wire [7:0] shl,
|
||||||
|
output wire [7:0] shr,
|
||||||
|
output wire [7:0] sshl,
|
||||||
|
output wire [7:0] sshr,
|
||||||
|
output wire [7:0] shiftx,
|
||||||
|
|
||||||
|
output wire [7:0] shl_s,
|
||||||
|
output wire [7:0] shr_s,
|
||||||
|
output wire [7:0] sshl_s,
|
||||||
|
output wire [7:0] sshr_s,
|
||||||
|
output wire [7:0] shiftx_s,
|
||||||
|
);
|
||||||
|
assign shl = in << 32'hffffffff;
|
||||||
|
assign shr = in >> 32'hffffffff;
|
||||||
|
assign sshl = in <<< 32'hffffffff;
|
||||||
|
assign sshr = in >>> 32'hffffffff;
|
||||||
|
assign shiftx = in[32'hffffffff +: 8];
|
||||||
|
|
||||||
|
wire signed [31:0] shamt = 32'hffffffff;
|
||||||
|
assign shl_s = in << shamt;
|
||||||
|
assign shr_s = in >> shamt;
|
||||||
|
assign sshl_s = in <<< shamt;
|
||||||
|
assign sshr_s = in >>> shamt;
|
||||||
|
assign shiftx_s = in[shamt +: 8];
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
select -assert-count 2 t:$shl
|
||||||
|
select -assert-count 2 t:$shr
|
||||||
|
select -assert-count 2 t:$sshl
|
||||||
|
select -assert-count 2 t:$sshr
|
||||||
|
select -assert-count 1 t:$shiftx
|
||||||
|
|
||||||
|
equiv_opt opt_expr
|
||||||
|
|
||||||
|
design -load postopt
|
||||||
|
select -assert-none t:$shl
|
||||||
|
select -assert-none t:$shr
|
||||||
|
select -assert-none t:$sshl
|
||||||
|
select -assert-none t:$sshr
|
||||||
|
select -assert-none t:$shiftx
|
||||||
|
|
|
||||||
1
tests/peepopt/.gitignore
vendored
Normal file
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