aboutsummaryrefslogtreecommitdiffstats
path: root/backends/smt2/smt2.cc
diff options
context:
space:
mode:
authorArchie <ac11018@ic.ac.uk>2022-08-21 17:18:20 -0500
committerArchie <ac11018@ic.ac.uk>2022-08-21 17:18:20 -0500
commitdb73f3c26b2768f93c7573b7c7d74b1cc7a0756d (patch)
tree81696fd98770e519aea96fe3a6e40bcc3b3a4360 /backends/smt2/smt2.cc
parente7e8e3b0f65ea1ebfcf04bffd0d9ba90f8e0d7fe (diff)
parent029c2785e810fda0ccc5abbb6057af760f2fc6f3 (diff)
downloadyosys-db73f3c26b2768f93c7573b7c7d74b1cc7a0756d.tar.gz
yosys-db73f3c26b2768f93c7573b7c7d74b1cc7a0756d.tar.bz2
yosys-db73f3c26b2768f93c7573b7c7d74b1cc7a0756d.zip
Merge branch 'master' of https://github.com/ALGCDG/yosys
Diffstat (limited to 'backends/smt2/smt2.cc')
-rw-r--r--backends/smt2/smt2.cc160
1 files changed, 143 insertions, 17 deletions
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index 7481e0510..54783cf1b 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -23,6 +23,7 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include "kernel/mem.h"
+#include "libs/json11/json11.hpp"
#include <string>
USING_YOSYS_NAMESPACE
@@ -241,6 +242,17 @@ struct Smt2Worker
for (auto wire : module->wires())
{
+ auto gclk_attr = wire->attributes.find(ID::replaced_by_gclk);
+ if (gclk_attr != wire->attributes.end()) {
+ if (gclk_attr->second == State::S1)
+ clock_posedge.insert(sigmap(wire));
+ else if (gclk_attr->second == State::S0)
+ clock_negedge.insert(sigmap(wire));
+ }
+ }
+
+ for (auto wire : module->wires())
+ {
if (!wire->port_input || GetSize(wire) != 1)
continue;
SigBit bit = sigmap(wire);
@@ -449,7 +461,7 @@ struct Smt2Worker
bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
int width = GetSize(sig_y);
- if (type == 's' || type == 'd' || type == 'b') {
+ if (type == 's' || type == 'S' || type == 'd' || type == 'b') {
width = max(width, GetSize(cell->getPort(ID::A)));
if (cell->hasPort(ID::B))
width = max(width, GetSize(cell->getPort(ID::B)));
@@ -462,7 +474,7 @@ struct Smt2Worker
if (cell->hasPort(ID::B)) {
sig_b = cell->getPort(ID::B);
- sig_b.extend_u0(width, is_signed && !(type == 's'));
+ sig_b.extend_u0(width, (type == 'S') || (is_signed && !(type == 's')));
}
std::string processed_expr;
@@ -577,31 +589,41 @@ struct Smt2Worker
if (cell->type.in(ID($ff), ID($dff)))
{
registers.insert(cell);
+ for (auto chunk : cell->getPort(ID::Q).chunks())
+ if (chunk.is_wire())
+ decls.push_back(witness_signal("reg", chunk.width, chunk.offset, "", idcounter, chunk.wire));
makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(ID::Q)), log_signal(cell->getPort(ID::Q)));
register_bv(cell->getPort(ID::Q), idcounter++);
recursive_cells.erase(cell);
return;
}
- if (cell->type.in(ID($anyconst), ID($anyseq), ID($allconst), ID($allseq)))
+ if (cell->type.in(ID($anyconst), ID($anyseq), ID($anyinit), ID($allconst), ID($allseq)))
{
+ auto QY = cell->type == ID($anyinit) ? ID::Q : ID::Y;
registers.insert(cell);
string infostr = cell->attributes.count(ID::src) ? cell->attributes.at(ID::src).decode_string().c_str() : get_id(cell);
if (cell->attributes.count(ID::reg))
infostr += " " + cell->attributes.at(ID::reg).decode_string();
- decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(ID::Y)), infostr.c_str()));
- if (cell->getPort(ID::Y).is_wire() && cell->getPort(ID::Y).as_wire()->get_bool_attribute(ID::maximize)){
+ decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort(QY)), infostr.c_str()));
+ if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::maximize)){
decls.push_back(stringf("; yosys-smt2-maximize %s#%d\n", get_id(module), idcounter));
- log("Wire %s is maximized\n", cell->getPort(ID::Y).as_wire()->name.str().c_str());
+ log("Wire %s is maximized\n", cell->getPort(QY).as_wire()->name.str().c_str());
}
- else if (cell->getPort(ID::Y).is_wire() && cell->getPort(ID::Y).as_wire()->get_bool_attribute(ID::minimize)){
+ else if (cell->getPort(QY).is_wire() && cell->getPort(QY).as_wire()->get_bool_attribute(ID::minimize)){
decls.push_back(stringf("; yosys-smt2-minimize %s#%d\n", get_id(module), idcounter));
- log("Wire %s is minimized\n", cell->getPort(ID::Y).as_wire()->name.str().c_str());
+ log("Wire %s is minimized\n", cell->getPort(QY).as_wire()->name.str().c_str());
}
- makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(ID::Y)), log_signal(cell->getPort(ID::Y)));
+
+ bool init_only = cell->type.in(ID($anyconst), ID($anyinit), ID($allconst));
+ for (auto chunk : cell->getPort(QY).chunks())
+ if (chunk.is_wire())
+ decls.push_back(witness_signal(init_only ? "init" : "seq", chunk.width, chunk.offset, "", idcounter, chunk.wire));
+
+ makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort(QY)), log_signal(cell->getPort(QY)));
if (cell->type == ID($anyseq))
ex_input_eq.push_back(stringf(" (= (|%s#%d| state) (|%s#%d| other_state))", get_id(module), idcounter, get_id(module), idcounter));
- register_bv(cell->getPort(ID::Y), idcounter++);
+ register_bv(cell->getPort(QY), idcounter++);
recursive_cells.erase(cell);
return;
}
@@ -619,8 +641,8 @@ struct Smt2Worker
if (cell->type.in(ID($shift), ID($shiftx))) {
if (cell->getParam(ID::B_SIGNED).as_bool()) {
return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
- "(bvlshr A B) (bvlshr A (bvneg B)))",
- GetSize(cell->getPort(ID::B)), 0), 's');
+ "(bvlshr A B) (bvshl A (bvneg B)))",
+ GetSize(cell->getPort(ID::B)), 0), 'S'); // type 'S' sign extends B
} else {
return export_bvop(cell, "(bvlshr A B)", 's');
}
@@ -748,6 +770,7 @@ struct Smt2Worker
log_error("Memory %s.%s has mixed clocked/nonclocked write ports. This is not supported by \"write_smt2\".\n", log_id(cell), log_id(module));
decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d %d %s\n", get_id(mem->memid), abits, mem->width, GetSize(mem->rd_ports), GetSize(mem->wr_ports), has_async_wr ? "async" : "sync"));
+ decls.push_back(witness_memory(get_id(mem->memid), cell, mem));
string memstate;
if (has_async_wr) {
@@ -840,6 +863,7 @@ struct Smt2Worker
if (m != nullptr)
{
decls.push_back(stringf("; yosys-smt2-cell %s %s\n", get_id(cell->type), get_id(cell->name)));
+ decls.push_back(witness_cell(get_id(cell->name), cell));
string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name));
for (auto &conn : cell->connections())
@@ -920,7 +944,7 @@ struct Smt2Worker
pool<SigBit> reg_bits;
for (auto cell : module->cells())
- if (cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_P_), ID($_DFF_N_))) {
+ if (cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_P_), ID($_DFF_N_), ID($anyinit))) {
// not using sigmap -- we want the net directly at the dff output
for (auto bit : cell->getPort(ID::Q))
reg_bits.insert(bit);
@@ -938,14 +962,19 @@ struct Smt2Worker
for (auto wire : module->wires()) {
bool is_register = false;
- for (auto bit : SigSpec(wire))
+ bool contains_clock = false;
+ for (auto bit : SigSpec(wire)) {
if (reg_bits.count(bit))
is_register = true;
+ auto sig_bit = sigmap(bit);
+ if (clock_posedge.count(sig_bit) || clock_negedge.count(sig_bit))
+ contains_clock = true;
+ }
bool is_smtlib2_comb_expr = wire->has_attribute(ID::smtlib2_comb_expr);
if (is_smtlib2_comb_expr && !is_smtlib2_module)
log_error("smtlib2_comb_expr is only valid in a module with the smtlib2_module attribute: wire %s.%s", log_id(module),
log_id(wire));
- if (wire->port_id || is_register || wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) {
+ if (wire->port_id || is_register || contains_clock || wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic())) {
RTLIL::SigSpec sig = sigmap(wire);
std::vector<std::string> comments;
if (wire->port_input)
@@ -956,9 +985,20 @@ struct Smt2Worker
comments.push_back(stringf("; yosys-smt2-register %s %d\n", get_id(wire), wire->width));
if (wire->get_bool_attribute(ID::keep) || (wiresmode && wire->name.isPublic()))
comments.push_back(stringf("; yosys-smt2-wire %s %d\n", get_id(wire), wire->width));
- if (GetSize(wire) == 1 && (clock_posedge.count(sig) || clock_negedge.count(sig)))
+ if (contains_clock && GetSize(wire) == 1 && (clock_posedge.count(sig) || clock_negedge.count(sig)))
comments.push_back(stringf("; yosys-smt2-clock %s%s%s\n", get_id(wire),
clock_posedge.count(sig) ? " posedge" : "", clock_negedge.count(sig) ? " negedge" : ""));
+ if (contains_clock) {
+ for (int i = 0; i < GetSize(sig); i++) {
+ bool is_posedge = clock_posedge.count(sig[i]);
+ bool is_negedge = clock_negedge.count(sig[i]);
+ if (is_posedge != is_negedge)
+ comments.push_back(witness_signal(
+ is_posedge ? "posedge" : "negedge", 1, i, get_id(wire), -1, wire));
+ }
+ }
+ if (wire->port_input)
+ comments.push_back(witness_signal("input", wire->width, 0, get_id(wire), -1, wire));
std::string smtlib2_comb_expr;
if (is_smtlib2_comb_expr) {
smtlib2_comb_expr =
@@ -968,6 +1008,8 @@ struct Smt2Worker
if (!bvmode && GetSize(sig) > 1)
log_error("smtlib2_comb_expr is unsupported on multi-bit wires when -nobv is specified: wire %s.%s",
log_id(module), log_id(wire));
+
+ comments.push_back(witness_signal("blackbox", wire->width, 0, get_id(wire), -1, wire));
}
auto &out_decls = is_smtlib2_comb_expr ? smtlib2_decls : decls;
if (bvmode && GetSize(sig) > 1) {
@@ -1136,7 +1178,7 @@ struct Smt2Worker
ex_state_eq.push_back(stringf("(= %s %s)", get_bool(cell->getPort(ID::Q)).c_str(), get_bool(cell->getPort(ID::Q), "other_state").c_str()));
}
- if (cell->type.in(ID($ff), ID($dff)))
+ if (cell->type.in(ID($ff), ID($dff), ID($anyinit)))
{
std::string expr_d = get_bv(cell->getPort(ID::D));
std::string expr_q = get_bv(cell->getPort(ID::Q), "next_state");
@@ -1435,6 +1477,90 @@ struct Smt2Worker
f << "true)";
f << stringf(" ; end of module %s\n", get_id(module));
}
+
+ template<class T> static std::vector<std::string> witness_path(T *obj) {
+ std::vector<std::string> path;
+ if (obj->name.isPublic()) {
+ auto hdlname = obj->get_string_attribute(ID::hdlname);
+ for (auto token : split_tokens(hdlname))
+ path.push_back("\\" + token);
+ }
+ if (path.empty())
+ path.push_back(obj->name.str());
+ return path;
+ }
+
+ std::string witness_signal(const char *type, int width, int offset, const std::string &smtname, int smtid, RTLIL::Wire *wire)
+ {
+ std::vector<std::string> hiername;
+ const char *wire_name = wire->name.c_str();
+ if (wire_name[0] == '\\') {
+ auto hdlname = wire->get_string_attribute(ID::hdlname);
+ for (auto token : split_tokens(hdlname))
+ hiername.push_back("\\" + token);
+ }
+ if (hiername.empty())
+ hiername.push_back(wire->name.str());
+
+ std::string line = "; yosys-smt2-witness ";
+ (json11::Json { json11::Json::object {
+ { "type", type },
+ { "offset", offset },
+ { "width", width },
+ { "smtname", smtname.empty() ? json11::Json(smtid) : json11::Json(smtname) },
+ { "path", witness_path(wire) },
+ }}).dump(line);
+ line += "\n";
+ return line;
+ }
+
+ std::string witness_cell(const char *smtname, RTLIL::Cell *cell)
+ {
+ std::string line = "; yosys-smt2-witness ";
+ (json11::Json {json11::Json::object {
+ { "type", "cell" },
+ { "smtname", smtname },
+ { "path", witness_path(cell) },
+ }}).dump(line);
+ line += "\n";
+ return line;
+ }
+
+ std::string witness_memory(const char *smtname, RTLIL::Cell *cell, Mem *mem)
+ {
+ json11::Json::array uninitialized;
+ auto init_data = mem->get_init_data();
+
+ int cursor = 0;
+
+ while (cursor < init_data.size()) {
+ while (cursor < init_data.size() && init_data[cursor] != State::Sx)
+ cursor++;
+ int offset = cursor;
+ while (cursor < init_data.size() && init_data[cursor] == State::Sx)
+ cursor++;
+ int width = cursor - offset;
+ if (width)
+ uninitialized.push_back(json11::Json::object {
+ {"width", width},
+ {"offset", offset},
+ });
+ }
+
+ std::string line = "; yosys-smt2-witness ";
+ (json11::Json { json11::Json::object {
+ { "type", "mem" },
+ { "width", mem->width },
+ { "size", mem->size },
+ { "rom", mem->wr_ports.empty() },
+ { "statebv", statebv },
+ { "smtname", smtname },
+ { "uninitialized", uninitialized },
+ { "path", witness_path(cell) },
+ }}).dump(line);
+ line += "\n";
+ return line;
+ }
};
struct Smt2Backend : public Backend {