3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-06-25 02:00:33 +00:00

Merge branch 'YosysHQ:main' into master

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -148,7 +148,7 @@ static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_d
#else
static inline bool ys_debug(int = 0) { return false; }
#endif
static inline void log_debug(const char *format, ...) { if (ys_debug(1)) { va_list args; va_start(args, format); logv(format, args); va_end(args); } }
# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
static inline void log_suppressed() {
if (log_debug_suppressed && !log_make_debug) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

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

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

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

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

View file

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

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

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

View file

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

View file

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

View file

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

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

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

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