3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-09-12 20:51:27 +00:00
This commit is contained in:
Emil J 2025-09-07 17:44:32 +10:00 committed by GitHub
commit 023f867044
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 1730 additions and 107 deletions

View file

@ -874,6 +874,7 @@ MK_TEST_DIRS += tests/sim
MK_TEST_DIRS += tests/svtypes
MK_TEST_DIRS += tests/techmap
MK_TEST_DIRS += tests/various
MK_TEST_DIRS += tests/rtlil
ifeq ($(ENABLE_VERIFIC),1)
ifneq ($(YOSYS_NOVERIFIC),1)
MK_TEST_DIRS += tests/verific

View file

@ -24,12 +24,23 @@
#include "rtlil_backend.h"
#include "kernel/yosys.h"
#include "kernel/utils.h"
#include <errno.h>
#include <iterator>
USING_YOSYS_NAMESPACE
using namespace RTLIL_BACKEND;
YOSYS_NAMESPACE_BEGIN
void RTLIL_BACKEND::dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj)
{
for (const auto& [name, value] : reversed(obj->attributes)) {
f << stringf("%s" "attribute %s ", indent.c_str(), name.c_str());
dump_const(f, value);
f << stringf("\n");
}
}
void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
{
if (width < 0)
@ -110,8 +121,8 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
dump_sigchunk(f, sig.as_chunk(), autoint);
} else {
f << stringf("{ ");
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
dump_sigchunk(f, *it, false);
for (const auto& chunk : reversed(sig.chunks())) {
dump_sigchunk(f, chunk, false);
f << stringf(" ");
}
f << stringf("}");
@ -120,11 +131,7 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
{
for (auto &it : wire->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
dump_attributes(f, indent, wire);
if (wire->driverCell_) {
f << stringf("%s" "# driver %s %s\n", indent.c_str(),
wire->driverCell()->name.c_str(), wire->driverPort().c_str());
@ -149,11 +156,7 @@ void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::
void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
{
for (auto &it : memory->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
dump_attributes(f, indent, memory);
f << stringf("%s" "memory ", indent.c_str());
if (memory->width != 1)
f << stringf("width %d ", memory->width);
@ -166,23 +169,19 @@ void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL
void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
{
for (auto &it : cell->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
dump_attributes(f, indent, cell);
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto &it : cell->parameters) {
for (const auto& [name, param] : reversed(cell->parameters)) {
f << stringf("%s parameter%s%s %s ", indent.c_str(),
(it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
(it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
it.first.c_str());
dump_const(f, it.second);
(param.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
(param.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
name.c_str());
dump_const(f, param);
f << stringf("\n");
}
for (auto &it : cell->connections()) {
f << stringf("%s connect %s ", indent.c_str(), it.first.c_str());
dump_sigspec(f, it.second);
for (const auto& [port, sig] : reversed(cell->connections_)) {
f << stringf("%s connect %s ", indent.c_str(), port.c_str());
dump_sigspec(f, sig);
f << stringf("\n");
}
f << stringf("%s" "end\n", indent.c_str());
@ -190,47 +189,38 @@ void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it)
{
for (const auto& [lhs, rhs] : cs->actions) {
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, it->first);
dump_sigspec(f, lhs);
f << stringf(" ");
dump_sigspec(f, it->second);
dump_sigspec(f, rhs);
f << stringf("\n");
}
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
dump_proc_switch(f, indent, *it);
for (const auto& sw : cs->switches)
dump_proc_switch(f, indent, sw);
}
void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw)
{
for (auto it = sw->attributes.begin(); it != sw->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
dump_attributes(f, indent, sw);
f << stringf("%s" "switch ", indent.c_str());
dump_sigspec(f, sw->signal);
f << stringf("\n");
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it)
for (const auto case_ : sw->cases)
{
for (auto ait = (*it)->attributes.begin(); ait != (*it)->attributes.end(); ++ait) {
f << stringf("%s attribute %s ", indent.c_str(), ait->first.c_str());
dump_const(f, ait->second);
f << stringf("\n");
}
dump_attributes(f, indent, case_);
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
for (size_t i = 0; i < case_->compare.size(); i++) {
if (i > 0)
f << stringf(" , ");
dump_sigspec(f, (*it)->compare[i]);
dump_sigspec(f, case_->compare[i]);
}
f << stringf("\n");
dump_proc_case_body(f, indent + " ", *it);
dump_proc_case_body(f, indent + " ", case_);
}
f << stringf("%s" "end\n", indent.c_str());
@ -253,20 +243,16 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
case RTLIL::STi: f << stringf("init\n"); break;
}
for (auto &it: sy->actions) {
for (const auto& [lhs, rhs] : sy->actions) {
f << stringf("%s update ", indent.c_str());
dump_sigspec(f, it.first);
dump_sigspec(f, lhs);
f << stringf(" ");
dump_sigspec(f, it.second);
dump_sigspec(f, rhs);
f << stringf("\n");
}
for (auto &it: sy->mem_write_actions) {
for (auto it2 = it.attributes.begin(); it2 != it.attributes.end(); ++it2) {
f << stringf("%s attribute %s ", indent.c_str(), it2->first.c_str());
dump_const(f, it2->second);
f << stringf("\n");
}
dump_attributes(f, indent, &it);
f << stringf("%s memwr %s ", indent.c_str(), it.memid.c_str());
dump_sigspec(f, it.address);
f << stringf(" ");
@ -281,15 +267,11 @@ void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
void RTLIL_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc)
{
for (auto it = proc->attributes.begin(); it != proc->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
dump_attributes(f, indent, proc);
f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str());
dump_proc_case_body(f, indent + " ", &proc->root_case);
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
dump_proc_sync(f, indent + " ", *it);
for (auto* sync : proc->syncs)
dump_proc_sync(f, indent + " ", sync);
f << stringf("%s" "end\n", indent.c_str());
}
@ -309,11 +291,7 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (print_header)
{
for (auto it = module->attributes.begin(); it != module->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
dump_attributes(f, indent, module);
f << stringf("%s" "module %s\n", indent.c_str(), module->name.c_str());
@ -335,40 +313,40 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (print_body)
{
for (auto it : module->wires())
if (!only_selected || design->selected(module, it)) {
for (const auto& [_, wire] : reversed(module->wires_))
if (!only_selected || design->selected(module, wire)) {
if (only_selected)
f << stringf("\n");
dump_wire(f, indent + " ", it);
dump_wire(f, indent + " ", wire);
}
for (auto it : module->memories)
if (!only_selected || design->selected(module, it.second)) {
for (const auto& [_, mem] : reversed(module->memories))
if (!only_selected || design->selected(module, mem)) {
if (only_selected)
f << stringf("\n");
dump_memory(f, indent + " ", it.second);
dump_memory(f, indent + " ", mem);
}
for (auto it : module->cells())
if (!only_selected || design->selected(module, it)) {
for (const auto& [_, cell] : reversed(module->cells_))
if (!only_selected || design->selected(module, cell)) {
if (only_selected)
f << stringf("\n");
dump_cell(f, indent + " ", it);
dump_cell(f, indent + " ", cell);
}
for (auto it : module->processes)
if (!only_selected || design->selected(module, it.second)) {
for (const auto& [_, process] : reversed(module->processes))
if (!only_selected || design->selected(module, process)) {
if (only_selected)
f << stringf("\n");
dump_proc(f, indent + " ", it.second);
dump_proc(f, indent + " ", process);
}
bool first_conn_line = true;
for (auto it = module->connections().begin(); it != module->connections().end(); ++it) {
for (const auto& [lhs, rhs] : module->connections()) {
bool show_conn = !only_selected || design->selected_whole_module(module->name);
if (!show_conn) {
RTLIL::SigSpec sigs = it->first;
sigs.append(it->second);
RTLIL::SigSpec sigs = lhs;
sigs.append(rhs);
for (auto &c : sigs.chunks()) {
if (c.wire == NULL || !design->selected(module, c.wire))
continue;
@ -378,7 +356,7 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (show_conn) {
if (only_selected && first_conn_line)
f << stringf("\n");
dump_conn(f, indent + " ", it->first, it->second);
dump_conn(f, indent + " ", lhs, rhs);
first_conn_line = false;
}
}
@ -394,7 +372,7 @@ void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
if (!flag_m) {
int count_selected_mods = 0;
for (auto module : design->modules()) {
for (auto* module : design->modules()) {
if (design->selected_whole_module(module->name))
flag_m = true;
if (design->selected(module))
@ -410,7 +388,7 @@ void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
f << stringf("autoidx %d\n", autoidx);
}
for (auto module : design->modules()) {
for (const auto& [_, module] : reversed(design->modules_)) {
if (!only_selected || design->selected(module)) {
if (only_selected)
f << stringf("\n");
@ -438,10 +416,14 @@ struct RTLILBackend : public Backend {
log(" -selected\n");
log(" only write selected parts of the design.\n");
log("\n");
log(" -sort\n");
log(" sort design in-place (used to be default).\n");
log("\n");
}
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
{
bool selected = false;
bool do_sort = false;
log_header(design, "Executing RTLIL backend.\n");
@ -452,14 +434,19 @@ struct RTLILBackend : public Backend {
selected = true;
continue;
}
if (arg == "-sort") {
do_sort = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
design->sort();
log("Output filename: %s\n", filename.c_str());
if (do_sort)
design->sort();
*f << stringf("# Generated by %s\n", yosys_maybe_version());
RTLIL_BACKEND::dump_design(*f, design, selected, true, false);
}

View file

@ -31,6 +31,7 @@
YOSYS_NAMESPACE_BEGIN
namespace RTLIL_BACKEND {
void dump_attributes(std::ostream &f, std::string indent, const RTLIL::AttrObject *obj);
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true);
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true);
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true);

View file

@ -229,6 +229,10 @@ struct VerilogFrontend : public Frontend {
log(" add 'dir' to the directories which are used when searching include\n");
log(" files\n");
log("\n");
log(" -relativeshare\n");
log(" use paths relative to share directory for source locations\n");
log(" where possible (experimental).\n");
log("\n");
log("The command 'verilog_defaults' can be used to register default options for\n");
log("subsequent calls to 'read_verilog'.\n");
log("\n");
@ -273,6 +277,7 @@ struct VerilogFrontend : public Frontend {
bool flag_nowb = false;
bool flag_nosynthesis = false;
bool flag_yydebug = false;
bool flag_relative_share = false;
define_map_t defines_map;
std::list<std::string> include_dirs;
@ -450,6 +455,11 @@ struct VerilogFrontend : public Frontend {
attributes.push_back(RTLIL::escape_id(args[++argidx]));
continue;
}
if (arg == "-relativeshare") {
flag_relative_share = true;
log_experimental("read_verilog -relativeshare");
continue;
}
if (arg == "-D" && argidx+1 < args.size()) {
std::string name = args[++argidx], value;
size_t equal = name.find('=');
@ -490,6 +500,13 @@ struct VerilogFrontend : public Frontend {
log("Parsing %s%s input from `%s' to AST representation.\n",
parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str());
log("verilog frontend filename %s\n", filename.c_str());
if (flag_relative_share) {
auto share_path = proc_share_dirname();
if (filename.substr(0, share_path.length()) == share_path)
filename = std::string("+/") + filename.substr(share_path.length());
log("new filename %s\n", filename.c_str());
}
AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv;
std::string code_after_preproc;

View file

@ -558,13 +558,16 @@ public:
int index;
const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { }
public:
typedef std::forward_iterator_tag iterator_category;
typedef std::bidirectional_iterator_tag iterator_category;
typedef std::pair<K, T> value_type;
typedef ptrdiff_t difference_type;
typedef std::pair<K, T>* pointer;
typedef std::pair<K, T>& reference;
typedef const std::pair<K, T>* pointer;
typedef const std::pair<K, T>& reference;
const_iterator() { }
const_iterator operator++() { index--; return *this; }
const_iterator operator++(int) { const_iterator tmp = *this; index--; return tmp; }
const_iterator operator--() { index++; return *this; }
const_iterator operator--(int) { const_iterator tmp = *this; index++; return tmp; }
const_iterator operator+=(int amt) { index -= amt; return *this; }
bool operator<(const const_iterator &other) const { return index > other.index; }
bool operator==(const const_iterator &other) const { return index == other.index; }
@ -598,6 +601,13 @@ public:
const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
operator const_iterator() const { return const_iterator(ptr, index); }
};
using reverse_iterator = std::reverse_iterator<const_iterator>;
reverse_iterator rbegin() const {
return std::make_reverse_iterator(end());
}
reverse_iterator rend() const {
return std::make_reverse_iterator(begin());
}
constexpr dict()
{
@ -847,7 +857,7 @@ public:
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); }
const_iterator end() const { return const_iterator(this, -1); }
};
template<typename K, typename OPS>

View file

@ -5855,6 +5855,7 @@ RTLIL::CaseRule *RTLIL::CaseRule::clone() const
RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule;
new_caserule->compare = compare;
new_caserule->actions = actions;
new_caserule->attributes = attributes;
for (auto &it : switches)
new_caserule->switches.push_back(it->clone());
return new_caserule;

View file

@ -21,6 +21,7 @@
// do not depend on any other components of yosys (except stuff like log_*).
#include "kernel/yosys.h"
#include <iterator>
#ifndef UTILS_H
#define UTILS_H
@ -276,6 +277,16 @@ inline int ceil_log2(int x)
#endif
}
template <typename T>
auto reversed(const T& container) {
struct reverse_view {
const T& cont;
auto begin() const { return cont.rbegin(); }
auto end() const { return cont.rend(); }
};
return reverse_view{container};
}
YOSYS_NAMESPACE_END
#endif

View file

@ -122,8 +122,6 @@ struct BugpointPass : public Pass {
int run_yosys(RTLIL::Design *design, string runner, string yosys_cmd, string yosys_arg, string suffix, bool catch_err)
{
design->sort();
string bugpoint_file = "bugpoint-case";
if (suffix.size())
bugpoint_file += stringf(".%.8s", suffix.c_str());

View file

@ -1031,6 +1031,10 @@ struct TechmapPass : public Pass {
log(" -dont_map <celltype>\n");
log(" leave the given cell type unmapped by ignoring any mapping rules for it\n");
log("\n");
log(" -relativeshare\n");
log(" use paths relative to share directory for source locations\n");
log(" where possible (experimental).\n");
log("\n");
log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
log("match cells with a type that match the text value of this attribute. Otherwise\n");
log("the module name will be used to match the cell. Multiple space-separated cell\n");
@ -1184,6 +1188,11 @@ struct TechmapPass : public Pass {
verilog_frontend += " -I " + args[++argidx];
continue;
}
if (args[argidx] == "-relativeshare") {
verilog_frontend += " -relativeshare";
log_experimental("techmap -relativeshare");
continue;
}
if (args[argidx] == "-assert") {
worker.assert_mode = true;
continue;

View file

@ -47,7 +47,7 @@ struct RaiseErrorPass : public Pass {
extra_args(args, argidx, design, true);
RTLIL::NamedObject *err_obj = nullptr;
for (auto mod : design->all_selected_modules()) {
if (mod->has_attribute(ID::raise_error)) {
err_obj = mod->clone();

View file

@ -98,13 +98,17 @@ struct SynthPass : public ScriptPass {
log(" mapping library in the `techmap` step. this option can be\n");
log(" repeated.\n");
log("\n");
log(" -relativeshare\n");
log(" use paths relative to share directory for source locations\n");
log(" where possible (experimental).\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
string top_module, fsm_opts, memory_opts, abc;
bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, booth, hieropt;
bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, booth, hieropt, relative_share;
int lut;
std::vector<std::string> techmap_maps;
@ -124,6 +128,7 @@ struct SynthPass : public ScriptPass {
flowmap = false;
booth = false;
hieropt = false;
relative_share = false;
abc = "abc";
techmap_maps.clear();
}
@ -211,6 +216,11 @@ struct SynthPass : public ScriptPass {
hieropt = true;
continue;
}
if (args[argidx] == "-relativeshare") {
relative_share = true;
log_experimental("synth -relativeshare");
continue;
}
break;
}
extra_args(args, argidx, design);
@ -239,6 +249,10 @@ struct SynthPass : public ScriptPass {
else
hieropt_flag = hieropt ? " -hier" : "";
std::string techmap_cmd = "techmap";
if (relative_share)
techmap_cmd += " -relativeshare";
if (check_label("begin")) {
if (help_mode) {
run("hierarchy -check [-top <top> | -auto-top]");
@ -268,9 +282,9 @@ struct SynthPass : public ScriptPass {
run("peepopt");
run("opt_clean");
if (help_mode)
run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v", " (if -lut)");
run(techmap_cmd + " -map +/cmp2lut.v -map +/cmp2lcu.v", " (if -lut)");
else if (lut)
run(stringf("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=%d", lut));
run(stringf("%s -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=%d", techmap_cmd, lut));
if (booth || help_mode)
run("booth", " (if -booth)");
if (!noalumacc)
@ -287,22 +301,22 @@ struct SynthPass : public ScriptPass {
run("memory_map");
run("opt -full");
if (help_mode) {
run("techmap", " (unless -extra-map)");
run("techmap -map +/techmap.v -map <inject>", " (if -extra-map)");
run(techmap_cmd, " (unless -extra-map)");
run(techmap_cmd + " -map +/techmap.v -map <inject>", " (if -extra-map)");
} else {
std::string techmap_opts;
if (!techmap_maps.empty())
techmap_opts += " -map +/techmap.v";
for (auto fn : techmap_maps)
techmap_opts += stringf(" -map %s", fn.c_str());
run("techmap" + techmap_opts);
run(techmap_cmd + techmap_opts);
}
if (help_mode) {
run("techmap -map +/gate2lut.v", "(if -noabc and -lut)");
run(techmap_cmd + " -map +/gate2lut.v", "(if -noabc and -lut)");
run("clean; opt_lut", " (if -noabc and -lut)");
run("flowmap -maxlut K", " (if -flowmap and -lut)");
} else if (noabc && lut) {
run(stringf("techmap -map +/gate2lut.v -D LUT_WIDTH=%d", lut));
run(stringf("%s -map +/gate2lut.v -D LUT_WIDTH=%d", techmap_cmd, lut));
run("clean; opt_lut");
} else if (flowmap) {
run(stringf("flowmap -maxlut %d", lut));

View file

@ -69,7 +69,7 @@ struct SynthPass : public ScriptPass
log(" use the specified Verilog file for extra primitives (can be specified multiple\n");
log(" times).\n");
log("\n");
log(" -extra-map <techamp.v>\n");
log(" -extra-map <techmap.v>\n");
log(" use the specified Verilog file for extra techmap rules (can be specified multiple\n");
log(" times).\n");
log("\n");

View file

@ -22,34 +22,37 @@ logger -check-expected
# raise_error with int exits with status
design -load read
setattr -mod -unset raise_error def other
dump
bugpoint -suffix error -yosys ../../yosys -command raise_error -expect-return 7
select -assert-mod-count 1 =*
select -assert-mod-count 1 top
# raise_error -always still uses 'raise_error' attribute if possible
design -load read
setattr -mod -unset raise_error def other
bugpoint -suffix error -yosys ../../yosys -command "raise_error -always" -expect-return 7
select -assert-mod-count 1 =*
select -assert-mod-count 1 top
# raise_error with string prints message and exits with 1
design -load read
rename top abc
setattr -mod -unset raise_error top def
bugpoint -suffix error -yosys ../../yosys -command raise_error -grep "help me" -expect-return 1
select -assert-mod-count 1 =*
select -assert-mod-count 1 other
# raise_error with no value exits with 1
design -load read
rename def zzy
setattr -mod -unset raise_error top
delete other
bugpoint -suffix error -yosys ../../yosys -command raise_error -expect-return 1
select -assert-mod-count 1 =*
select -assert-mod-count 1 zzy
select -assert-mod-count 1 def
# raise_error -stderr prints to stderr and exits with 1
design -load read
rename top abc
setattr -mod -unset raise_error top def
bugpoint -suffix error -yosys ../../yosys -command "raise_error -stderr" -err-grep "help me" -expect-return 1
select -assert-mod-count 1 =*
select -assert-mod-count 1 other

View file

@ -24,7 +24,7 @@ def compile_cpp(in_path, out_path, args):
run(['g++', '-g', '-std=c++17'] + args + [str(in_path), '-o', str(out_path)])
def yosys_synth(verilog_file, rtlil_file):
yosys(f"read_verilog {quote(verilog_file)} ; prep ; write_rtlil {quote(rtlil_file)}")
yosys(f"read_verilog {quote(verilog_file)} ; prep ; setundef -undriven -undef ; write_rtlil {quote(rtlil_file)}")
# simulate an rtlil file with yosys, comparing with a given vcd file, and writing out the yosys simulation results into a second vcd file
def yosys_sim(rtlil_file, vcd_reference_file, vcd_out_file, preprocessing = ""):
@ -91,4 +91,4 @@ def test_print_graph(tmp_path):
tb_file = base_path / 'tests/functional/picorv32_tb.v'
cpu_file = base_path / 'tests/functional/picorv32.v'
# currently we only check that we can print the graph without getting an error, not that it prints anything sensibl
yosys(f"read_verilog {quote(tb_file)} {quote(cpu_file)}; prep -top gold; flatten; clk2fflogic; test_generic")
yosys(f"read_verilog {quote(tb_file)} {quote(cpu_file)}; prep -top gold; setundef -undriven -undef ; flatten; clk2fflogic; test_generic")

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

@ -0,0 +1 @@
/temp

40
tests/rtlil/everything.v Normal file
View file

@ -0,0 +1,40 @@
module alu(
input clk,
input [7:0] A,
input [7:0] B,
input [3:0] operation,
output reg [7:0] result,
output reg CF,
output reg ZF,
output reg SF
);
localparam ALU_OP_ADD = 4'b0000;
localparam ALU_OP_SUB = 4'b0001;
reg [8:0] tmp;
always @(posedge clk)
begin
case (operation)
ALU_OP_ADD :
tmp = A + B;
ALU_OP_SUB :
tmp = A - B;
endcase
CF <= tmp[8];
ZF <= tmp[7:0] == 0;
SF <= tmp[7];
result <= tmp[7:0];
end
endmodule
module foo(
input [7:0] a, input [7:0] b, output [7:0] y
);
wire [7:0] bb;
assign b = bb;
assign y = a + bb;
endmodule

View file

@ -0,0 +1,10 @@
set -euo pipefail
YS=../../yosys
mkdir -p temp
$YS -p "read_verilog -sv everything.v; write_rtlil temp/roundtrip-design-push.il; design -push; design -pop; write_rtlil temp/roundtrip-design-pop.il"
diff temp/roundtrip-design-push.il temp/roundtrip-design-pop.il
$YS -p "read_verilog -sv everything.v; write_rtlil temp/roundtrip-design-save.il; design -save foo; design -load foo; write_rtlil temp/roundtrip-design-load.il"
diff temp/roundtrip-design-save.il temp/roundtrip-design-load.il

View file

@ -0,0 +1,283 @@
autoidx 15
attribute \src "everything.v:1.1-32.10"
attribute \cells_not_processed 1
module \alu
attribute \src "everything.v:2.8-2.11"
wire input 1 \clk
attribute \src "everything.v:3.14-3.15"
wire width 8 input 2 \A
attribute \src "everything.v:4.14-4.15"
wire width 8 input 3 \B
attribute \src "everything.v:5.14-5.23"
wire width 4 input 4 \operation
attribute \src "everything.v:6.19-6.25"
wire width 8 output 5 \result
attribute \src "everything.v:7.13-7.15"
wire output 6 \CF
attribute \src "everything.v:8.13-8.15"
wire output 7 \ZF
attribute \src "everything.v:9.13-9.15"
wire output 8 \SF
attribute \src "everything.v:15.12-15.15"
wire width 9 \tmp
attribute \src "everything.v:17.2-31.5"
wire width 8 $0\result[7:0]
attribute \src "everything.v:17.2-31.5"
wire $0\CF[0:0]
attribute \src "everything.v:17.2-31.5"
wire $0\ZF[0:0]
attribute \src "everything.v:17.2-31.5"
wire $0\SF[0:0]
attribute \src "everything.v:17.2-31.5"
wire width 9 $0\tmp[8:0]
attribute \src "everything.v:17.2-31.5"
wire width 9 $1\tmp[8:0]
attribute \src "everything.v:21.11-21.16"
wire width 9 $add$everything.v:21$2_Y
attribute \src "everything.v:23.11-23.16"
wire width 9 $sub$everything.v:23$3_Y
attribute \src "everything.v:27.9-27.22"
wire $eq$everything.v:27$4_Y
attribute \src "everything.v:21.11-21.16"
cell $add $add$everything.v:21$2
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 8
parameter \Y_WIDTH 9
connect \A \A
connect \B \B
connect \Y $add$everything.v:21$2_Y
end
attribute \src "everything.v:23.11-23.16"
cell $sub $sub$everything.v:23$3
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 8
parameter \Y_WIDTH 9
connect \A \A
connect \B \B
connect \Y $sub$everything.v:23$3_Y
end
attribute \src "everything.v:27.9-27.22"
cell $eq $eq$everything.v:27$4
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 32
parameter \Y_WIDTH 1
connect \A $1\tmp[8:0] [7:0]
connect \B 0
connect \Y $eq$everything.v:27$4_Y
end
attribute \src "everything.v:17.2-31.5"
process $proc$everything.v:17$1
assign { } { }
assign { } { }
assign { } { }
assign { } { }
assign { } { }
assign $0\tmp[8:0] $1\tmp[8:0]
assign $0\CF[0:0] $1\tmp[8:0] [8]
assign $0\ZF[0:0] $eq$everything.v:27$4_Y
assign $0\SF[0:0] $1\tmp[8:0] [7]
assign $0\result[7:0] $1\tmp[8:0] [7:0]
attribute \src "everything.v:19.3-24.10"
switch \operation
attribute \src "everything.v:19.19-19.19"
case 4'0000
assign { } { }
assign $1\tmp[8:0] $add$everything.v:21$2_Y
attribute \src "everything.v:21.17-21.17"
case 4'0001
assign { } { }
assign $1\tmp[8:0] $sub$everything.v:23$3_Y
case
assign $1\tmp[8:0] \tmp
end
sync posedge \clk
update \result $0\result[7:0]
update \CF $0\CF[0:0]
update \ZF $0\ZF[0:0]
update \SF $0\SF[0:0]
update \tmp $0\tmp[8:0]
end
end
attribute \src "everything.v:34.1-40.10"
attribute \cells_not_processed 1
module \foo
attribute \src "everything.v:35.17-35.18"
wire width 8 input 1 \a
attribute \src "everything.v:35.32-35.33"
wire width 8 input 2 \b
attribute \src "everything.v:35.48-35.49"
wire width 8 output 3 \y
attribute \src "everything.v:37.16-37.18"
wire width 8 \bb
attribute \src "everything.v:39.16-39.22"
wire width 8 $add$everything.v:39$5_Y
attribute \src "everything.v:39.16-39.22"
cell $add $add$everything.v:39$5
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 8
parameter \Y_WIDTH 8
connect \A \a
connect \B \bb
connect \Y $add$everything.v:39$5_Y
end
connect \b \bb
connect \y $add$everything.v:39$5_Y
end
attribute \cells_not_processed 1
attribute \src "everything.v:1.1-32.10"
module \zzz
attribute \src "everything.v:27.9-27.22"
wire $eq$everything.v:27$4_Y
attribute \src "everything.v:23.11-23.16"
wire width 9 $sub$everything.v:23$3_Y
attribute \src "everything.v:21.11-21.16"
wire width 9 $add$everything.v:21$2_Y
attribute \src "everything.v:17.2-31.5"
wire width 9 $1\tmp[8:0]
attribute \src "everything.v:17.2-31.5"
wire width 9 $0\tmp[8:0]
attribute \src "everything.v:17.2-31.5"
wire $0\SF[0:0]
attribute \src "everything.v:17.2-31.5"
wire $0\ZF[0:0]
attribute \src "everything.v:17.2-31.5"
wire $0\CF[0:0]
attribute \src "everything.v:17.2-31.5"
wire width 8 $0\result[7:0]
attribute \src "everything.v:15.12-15.15"
wire width 9 \tmp
attribute \src "everything.v:9.13-9.15"
wire output 8 \SF
attribute \src "everything.v:8.13-8.15"
wire output 7 \ZF
attribute \src "everything.v:7.13-7.15"
wire output 6 \CF
attribute \src "everything.v:6.19-6.25"
wire width 8 output 5 \result
attribute \src "everything.v:5.14-5.23"
wire width 4 input 4 \operation
attribute \src "everything.v:4.14-4.15"
wire width 8 input 3 \B
attribute \src "everything.v:3.14-3.15"
wire width 8 input 2 \A
attribute \src "everything.v:2.8-2.11"
wire input 1 \clk
wire $procmux$8_CMP
wire width 9 $procmux$7_Y
wire $procmux$9_CMP
attribute \src "everything.v:27.9-27.22"
cell $logic_not $eq$everything.v:27$4
parameter \A_SIGNED 0
parameter \Y_WIDTH 1
parameter \A_WIDTH 8
connect \A $1\tmp[8:0] [7:0]
connect \Y $eq$everything.v:27$4_Y
end
attribute \src "everything.v:23.11-23.16"
cell $sub $sub$everything.v:23$3
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 8
parameter \Y_WIDTH 9
connect \A \A
connect \B \B
connect \Y $sub$everything.v:23$3_Y
end
attribute \src "everything.v:21.11-21.16"
cell $add $add$everything.v:21$2
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 8
parameter \B_WIDTH 8
parameter \Y_WIDTH 9
connect \A \A
connect \B \B
connect \Y $add$everything.v:21$2_Y
end
attribute \src "everything.v:21.17-21.17|everything.v:19.3-24.10"
attribute \full_case 1
cell $eq $procmux$8_CMP0
parameter \A_SIGNED 0
parameter \B_SIGNED 0
parameter \A_WIDTH 4
parameter \B_WIDTH 4
parameter \Y_WIDTH 1
connect \A \operation
connect \B 4'0001
connect \Y $procmux$8_CMP
end
attribute \src "everything.v:21.17-21.17|everything.v:19.3-24.10"
attribute \full_case 1
cell $pmux $procmux$7
parameter \WIDTH 9
parameter \S_WIDTH 2
connect \A \tmp
connect \B { $add$everything.v:21$2_Y $sub$everything.v:23$3_Y }
connect \S { $procmux$9_CMP $procmux$8_CMP }
connect \Y $procmux$7_Y
end
attribute \src "everything.v:19.19-19.19|everything.v:19.3-24.10"
attribute \full_case 1
cell $logic_not $procmux$9_CMP0
parameter \A_SIGNED 0
parameter \Y_WIDTH 1
parameter \A_WIDTH 4
connect \A \operation
connect \Y $procmux$9_CMP
end
attribute \src "everything.v:17.2-31.5"
cell $dff $procdff$10
parameter \WIDTH 8
parameter \CLK_POLARITY 1'1
connect \D $procmux$7_Y [7:0]
connect \Q \result
connect \CLK \clk
end
attribute \src "everything.v:17.2-31.5"
cell $dff $procdff$11
parameter \WIDTH 1
parameter \CLK_POLARITY 1'1
connect \D $procmux$7_Y [8]
connect \Q \CF
connect \CLK \clk
end
attribute \src "everything.v:17.2-31.5"
cell $dff $procdff$12
parameter \WIDTH 1
parameter \CLK_POLARITY 1'1
connect \D $eq$everything.v:27$4_Y
connect \Q \ZF
connect \CLK \clk
end
attribute \src "everything.v:17.2-31.5"
cell $dff $procdff$13
parameter \WIDTH 1
parameter \CLK_POLARITY 1'1
connect \D $procmux$7_Y [7]
connect \Q \SF
connect \CLK \clk
end
attribute \src "everything.v:17.2-31.5"
cell $dff $procdff$14
parameter \WIDTH 9
parameter \CLK_POLARITY 1'1
connect \D $procmux$7_Y
connect \Q \tmp
connect \CLK \clk
end
connect $0\result[7:0] $1\tmp[8:0] [7:0]
connect $0\SF[0:0] $1\tmp[8:0] [7]
connect $0\ZF[0:0] $eq$everything.v:27$4_Y
connect $0\CF[0:0] $1\tmp[8:0] [8]
connect $0\tmp[8:0] $1\tmp[8:0]
connect $1\tmp[8:0] $procmux$7_Y
end

View file

@ -0,0 +1,39 @@
set -euo pipefail
YS=../../yosys
mkdir -p temp
# non-POSIX sed -i inconsistency workaround
remove_empty_lines() {
local file="$1"
sed '/^$/d' "$file" > temp/tmp
mv temp/tmp "$file"
}
# write_rtlil and dump are equivalent
$YS -p "read_verilog -sv everything.v; copy alu zzz; proc zzz; dump -o temp/roundtrip-text.dump.il; write_rtlil temp/roundtrip-text.write.il"
remove_empty_lines temp/roundtrip-text.dump.il
remove_empty_lines temp/roundtrip-text.write.il
# Trim first line ("Generated by Yosys ...")
tail -n +2 temp/roundtrip-text.write.il > temp/roundtrip-text.write-nogen.il
diff temp/roundtrip-text.dump.il temp/roundtrip-text.write-nogen.il
diff temp/roundtrip-text.dump.il roundtrip-text.ref.il
# Loading and writing it out again doesn't change the RTLIL
$YS -p "read_rtlil temp/roundtrip-text.dump.il; write_rtlil temp/roundtrip-text.reload.il"
remove_empty_lines temp/roundtrip-text.reload.il
tail -n +2 temp/roundtrip-text.reload.il > temp/roundtrip-text.reload-nogen.il
diff temp/roundtrip-text.dump.il temp/roundtrip-text.reload-nogen.il
# Hashing differences don't change the RTLIL
$YS --hash-seed=2345678 -p "read_rtlil temp/roundtrip-text.dump.il; write_rtlil temp/roundtrip-text.reload-hash.il"
remove_empty_lines temp/roundtrip-text.reload-hash.il
tail -n +2 temp/roundtrip-text.reload-hash.il > temp/roundtrip-text.reload-hash-nogen.il
diff temp/roundtrip-text.dump.il temp/roundtrip-text.reload-hash-nogen.il
echo "Without ABC, we don't get any irreproducibility and can pin that"
echo "Has this test case started failing for you? Consider updating the reference"
$YS -p "read_verilog -sv everything.v; synth -relativeshare -noabc; write_rtlil temp/roundtrip-text.synth.il"
remove_empty_lines temp/roundtrip-text.synth.il
tail -n +2 temp/roundtrip-text.synth.il > temp/roundtrip-text.synth-nogen.il
diff temp/roundtrip-text.synth-nogen.il roundtrip-text.synth.ref.il

File diff suppressed because it is too large Load diff

4
tests/rtlil/run-test.sh Executable file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -eu
source ../gen-tests-makefile.sh
generate_mk --bash