2014-02-01 03:35:56 -06:00
|
|
|
/*
|
|
|
|
* yosys -- Yosys Open SYnthesis Suite
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kernel/register.h"
|
|
|
|
#include "kernel/rtlil.h"
|
|
|
|
#include "kernel/log.h"
|
|
|
|
|
|
|
|
static void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL::Design *design)
|
|
|
|
{
|
|
|
|
bool flag_ignore_gold_x = false;
|
|
|
|
bool flag_make_outputs = false;
|
2014-02-05 19:20:55 -06:00
|
|
|
bool flag_make_outcmp = false;
|
2014-02-01 03:35:56 -06:00
|
|
|
bool flag_make_assert = false;
|
2014-07-20 08:23:08 -05:00
|
|
|
bool flag_flatten = false;
|
2014-02-01 03:35:56 -06:00
|
|
|
|
2014-05-28 11:05:38 -05:00
|
|
|
log_header("Executing MITER pass (creating miter circuit).\n");
|
|
|
|
|
2014-02-01 03:35:56 -06:00
|
|
|
size_t argidx;
|
|
|
|
for (argidx = 2; argidx < args.size(); argidx++)
|
|
|
|
{
|
|
|
|
if (args[argidx] == "-ignore_gold_x") {
|
|
|
|
flag_ignore_gold_x = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (args[argidx] == "-make_outputs") {
|
|
|
|
flag_make_outputs = true;
|
|
|
|
continue;
|
|
|
|
}
|
2014-02-05 19:20:55 -06:00
|
|
|
if (args[argidx] == "-make_outcmp") {
|
|
|
|
flag_make_outcmp = true;
|
|
|
|
continue;
|
|
|
|
}
|
2014-02-01 03:35:56 -06:00
|
|
|
if (args[argidx] == "-make_assert") {
|
|
|
|
flag_make_assert = true;
|
|
|
|
continue;
|
|
|
|
}
|
2014-07-20 08:23:08 -05:00
|
|
|
if (args[argidx] == "-flatten") {
|
|
|
|
flag_flatten = true;
|
|
|
|
continue;
|
|
|
|
}
|
2014-02-01 03:35:56 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (argidx+3 != args.size() || args[argidx].substr(0, 1) == "-")
|
|
|
|
that->cmd_error(args, argidx, "command argument error");
|
|
|
|
|
2014-08-02 09:03:18 -05:00
|
|
|
RTLIL::IdString gold_name = RTLIL::escape_id(args[argidx++]);
|
|
|
|
RTLIL::IdString gate_name = RTLIL::escape_id(args[argidx++]);
|
|
|
|
RTLIL::IdString miter_name = RTLIL::escape_id(args[argidx++]);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
2014-07-27 03:18:00 -05:00
|
|
|
if (design->modules_.count(gold_name) == 0)
|
2014-02-01 03:35:56 -06:00
|
|
|
log_cmd_error("Can't find gold module %s!\n", gold_name.c_str());
|
2014-07-27 03:18:00 -05:00
|
|
|
if (design->modules_.count(gate_name) == 0)
|
2014-02-01 03:35:56 -06:00
|
|
|
log_cmd_error("Can't find gate module %s!\n", gate_name.c_str());
|
2014-07-27 03:18:00 -05:00
|
|
|
if (design->modules_.count(miter_name) != 0)
|
2014-02-01 03:35:56 -06:00
|
|
|
log_cmd_error("There is already a module %s!\n", gate_name.c_str());
|
|
|
|
|
2014-07-27 03:18:00 -05:00
|
|
|
RTLIL::Module *gold_module = design->modules_.at(gold_name);
|
|
|
|
RTLIL::Module *gate_module = design->modules_.at(gate_name);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
2014-07-26 18:49:51 -05:00
|
|
|
for (auto &it : gold_module->wires_) {
|
2014-02-01 03:35:56 -06:00
|
|
|
RTLIL::Wire *w1 = it.second, *w2;
|
|
|
|
if (w1->port_id == 0)
|
|
|
|
continue;
|
2014-07-26 18:49:51 -05:00
|
|
|
if (gate_module->wires_.count(it.second->name) == 0)
|
2014-02-01 03:35:56 -06:00
|
|
|
goto match_gold_port_error;
|
2014-07-26 18:49:51 -05:00
|
|
|
w2 = gate_module->wires_.at(it.second->name);
|
2014-02-01 03:35:56 -06:00
|
|
|
if (w1->port_input != w2->port_input)
|
|
|
|
goto match_gold_port_error;
|
|
|
|
if (w1->port_output != w2->port_output)
|
|
|
|
goto match_gold_port_error;
|
|
|
|
if (w1->width != w2->width)
|
|
|
|
goto match_gold_port_error;
|
|
|
|
continue;
|
|
|
|
match_gold_port_error:
|
|
|
|
log_cmd_error("No matching port in gate module was found for %s!\n", it.second->name.c_str());
|
|
|
|
}
|
|
|
|
|
2014-07-26 18:49:51 -05:00
|
|
|
for (auto &it : gate_module->wires_) {
|
2014-02-01 03:35:56 -06:00
|
|
|
RTLIL::Wire *w1 = it.second, *w2;
|
|
|
|
if (w1->port_id == 0)
|
|
|
|
continue;
|
2014-07-26 18:49:51 -05:00
|
|
|
if (gold_module->wires_.count(it.second->name) == 0)
|
2014-02-01 03:35:56 -06:00
|
|
|
goto match_gate_port_error;
|
2014-07-26 18:49:51 -05:00
|
|
|
w2 = gold_module->wires_.at(it.second->name);
|
2014-02-01 03:35:56 -06:00
|
|
|
if (w1->port_input != w2->port_input)
|
|
|
|
goto match_gate_port_error;
|
|
|
|
if (w1->port_output != w2->port_output)
|
|
|
|
goto match_gate_port_error;
|
|
|
|
if (w1->width != w2->width)
|
|
|
|
goto match_gate_port_error;
|
|
|
|
continue;
|
|
|
|
match_gate_port_error:
|
|
|
|
log_cmd_error("No matching port in gold module was found for %s!\n", it.second->name.c_str());
|
|
|
|
}
|
|
|
|
|
2014-05-28 11:05:38 -05:00
|
|
|
log("Creating miter cell \"%s\" with gold cell \"%s\" and gate cell \"%s\".\n", RTLIL::id2cstr(miter_name), RTLIL::id2cstr(gold_name), RTLIL::id2cstr(gate_name));
|
|
|
|
|
2014-02-01 03:35:56 -06:00
|
|
|
RTLIL::Module *miter_module = new RTLIL::Module;
|
|
|
|
miter_module->name = miter_name;
|
2014-07-31 07:11:39 -05:00
|
|
|
design->add(miter_module);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *gold_cell = miter_module->addCell("\\gold", gold_name);
|
|
|
|
RTLIL::Cell *gate_cell = miter_module->addCell("\\gate", gate_name);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
|
|
|
RTLIL::SigSpec all_conditions;
|
|
|
|
|
2014-07-26 18:49:51 -05:00
|
|
|
for (auto &it : gold_module->wires_)
|
2014-02-01 03:35:56 -06:00
|
|
|
{
|
|
|
|
RTLIL::Wire *w1 = it.second;
|
|
|
|
|
|
|
|
if (w1->port_input)
|
|
|
|
{
|
2014-07-26 13:12:50 -05:00
|
|
|
RTLIL::Wire *w2 = miter_module->addWire("\\in_" + RTLIL::unescape_id(w1->name), w1->width);
|
2014-02-01 03:35:56 -06:00
|
|
|
w2->port_input = true;
|
|
|
|
|
2014-07-31 09:38:54 -05:00
|
|
|
gold_cell->setPort(w1->name, w2);
|
|
|
|
gate_cell->setPort(w1->name, w2);
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (w1->port_output)
|
|
|
|
{
|
2014-07-26 13:12:50 -05:00
|
|
|
RTLIL::Wire *w2_gold = miter_module->addWire("\\gold_" + RTLIL::unescape_id(w1->name), w1->width);
|
2014-02-01 03:35:56 -06:00
|
|
|
w2_gold->port_output = flag_make_outputs;
|
|
|
|
|
2014-07-26 13:12:50 -05:00
|
|
|
RTLIL::Wire *w2_gate = miter_module->addWire("\\gate_" + RTLIL::unescape_id(w1->name), w1->width);
|
2014-02-01 03:35:56 -06:00
|
|
|
w2_gate->port_output = flag_make_outputs;
|
|
|
|
|
2014-07-31 09:38:54 -05:00
|
|
|
gold_cell->setPort(w1->name, w2_gold);
|
|
|
|
gate_cell->setPort(w1->name, w2_gate);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
2014-02-05 19:20:55 -06:00
|
|
|
RTLIL::SigSpec this_condition;
|
|
|
|
|
2014-02-01 03:35:56 -06:00
|
|
|
if (flag_ignore_gold_x)
|
|
|
|
{
|
2014-07-21 05:35:06 -05:00
|
|
|
RTLIL::SigSpec gold_x = miter_module->addWire(NEW_ID, w2_gold->width);
|
2014-02-01 03:35:56 -06:00
|
|
|
for (int i = 0; i < w2_gold->width; i++) {
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *eqx_cell = miter_module->addCell(NEW_ID, "$eqx");
|
2014-02-01 03:35:56 -06:00
|
|
|
eqx_cell->parameters["\\A_WIDTH"] = 1;
|
|
|
|
eqx_cell->parameters["\\B_WIDTH"] = 1;
|
|
|
|
eqx_cell->parameters["\\Y_WIDTH"] = 1;
|
|
|
|
eqx_cell->parameters["\\A_SIGNED"] = 0;
|
|
|
|
eqx_cell->parameters["\\B_SIGNED"] = 0;
|
2014-07-31 09:38:54 -05:00
|
|
|
eqx_cell->setPort("\\A", RTLIL::SigSpec(w2_gold, i));
|
|
|
|
eqx_cell->setPort("\\B", RTLIL::State::Sx);
|
|
|
|
eqx_cell->setPort("\\Y", gold_x.extract(i, 1));
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
|
|
|
|
2014-07-21 05:35:06 -05:00
|
|
|
RTLIL::SigSpec gold_masked = miter_module->addWire(NEW_ID, w2_gold->width);
|
|
|
|
RTLIL::SigSpec gate_masked = miter_module->addWire(NEW_ID, w2_gate->width);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *or_gold_cell = miter_module->addCell(NEW_ID, "$or");
|
2014-02-01 03:35:56 -06:00
|
|
|
or_gold_cell->parameters["\\A_WIDTH"] = w2_gold->width;
|
|
|
|
or_gold_cell->parameters["\\B_WIDTH"] = w2_gold->width;
|
|
|
|
or_gold_cell->parameters["\\Y_WIDTH"] = w2_gold->width;
|
|
|
|
or_gold_cell->parameters["\\A_SIGNED"] = 0;
|
|
|
|
or_gold_cell->parameters["\\B_SIGNED"] = 0;
|
2014-07-31 09:38:54 -05:00
|
|
|
or_gold_cell->setPort("\\A", w2_gold);
|
|
|
|
or_gold_cell->setPort("\\B", gold_x);
|
|
|
|
or_gold_cell->setPort("\\Y", gold_masked);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *or_gate_cell = miter_module->addCell(NEW_ID, "$or");
|
2014-02-01 03:35:56 -06:00
|
|
|
or_gate_cell->parameters["\\A_WIDTH"] = w2_gate->width;
|
|
|
|
or_gate_cell->parameters["\\B_WIDTH"] = w2_gate->width;
|
|
|
|
or_gate_cell->parameters["\\Y_WIDTH"] = w2_gate->width;
|
|
|
|
or_gate_cell->parameters["\\A_SIGNED"] = 0;
|
|
|
|
or_gate_cell->parameters["\\B_SIGNED"] = 0;
|
2014-07-31 09:38:54 -05:00
|
|
|
or_gate_cell->setPort("\\A", w2_gate);
|
|
|
|
or_gate_cell->setPort("\\B", gold_x);
|
|
|
|
or_gate_cell->setPort("\\Y", gate_masked);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *eq_cell = miter_module->addCell(NEW_ID, "$eqx");
|
2014-02-01 03:35:56 -06:00
|
|
|
eq_cell->parameters["\\A_WIDTH"] = w2_gold->width;
|
|
|
|
eq_cell->parameters["\\B_WIDTH"] = w2_gate->width;
|
|
|
|
eq_cell->parameters["\\Y_WIDTH"] = 1;
|
|
|
|
eq_cell->parameters["\\A_SIGNED"] = 0;
|
|
|
|
eq_cell->parameters["\\B_SIGNED"] = 0;
|
2014-07-31 09:38:54 -05:00
|
|
|
eq_cell->setPort("\\A", gold_masked);
|
|
|
|
eq_cell->setPort("\\B", gate_masked);
|
|
|
|
eq_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
|
|
|
|
this_condition = eq_cell->getPort("\\Y");
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *eq_cell = miter_module->addCell(NEW_ID, "$eqx");
|
2014-02-01 03:35:56 -06:00
|
|
|
eq_cell->parameters["\\A_WIDTH"] = w2_gold->width;
|
|
|
|
eq_cell->parameters["\\B_WIDTH"] = w2_gate->width;
|
|
|
|
eq_cell->parameters["\\Y_WIDTH"] = 1;
|
|
|
|
eq_cell->parameters["\\A_SIGNED"] = 0;
|
|
|
|
eq_cell->parameters["\\B_SIGNED"] = 0;
|
2014-07-31 09:38:54 -05:00
|
|
|
eq_cell->setPort("\\A", w2_gold);
|
|
|
|
eq_cell->setPort("\\B", w2_gate);
|
|
|
|
eq_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
|
|
|
|
this_condition = eq_cell->getPort("\\Y");
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
2014-02-05 19:20:55 -06:00
|
|
|
|
|
|
|
if (flag_make_outcmp)
|
|
|
|
{
|
2014-07-26 13:12:50 -05:00
|
|
|
RTLIL::Wire *w_cmp = miter_module->addWire("\\cmp_" + RTLIL::unescape_id(w1->name));
|
2014-02-05 19:20:55 -06:00
|
|
|
w_cmp->port_output = true;
|
2014-07-26 07:32:50 -05:00
|
|
|
miter_module->connect(RTLIL::SigSig(w_cmp, this_condition));
|
2014-02-05 19:20:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
all_conditions.append(this_condition);
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-22 13:15:14 -05:00
|
|
|
if (all_conditions.size() != 1) {
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *reduce_cell = miter_module->addCell(NEW_ID, "$reduce_and");
|
2014-07-22 13:15:14 -05:00
|
|
|
reduce_cell->parameters["\\A_WIDTH"] = all_conditions.size();
|
2014-02-01 03:35:56 -06:00
|
|
|
reduce_cell->parameters["\\Y_WIDTH"] = 1;
|
|
|
|
reduce_cell->parameters["\\A_SIGNED"] = 0;
|
2014-07-31 09:38:54 -05:00
|
|
|
reduce_cell->setPort("\\A", all_conditions);
|
|
|
|
reduce_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
|
|
|
|
all_conditions = reduce_cell->getPort("\\Y");
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flag_make_assert) {
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *assert_cell = miter_module->addCell(NEW_ID, "$assert");
|
2014-07-31 09:38:54 -05:00
|
|
|
assert_cell->setPort("\\A", all_conditions);
|
|
|
|
assert_cell->setPort("\\EN", RTLIL::SigSpec(1, 1));
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
|
|
|
|
2014-07-26 13:12:50 -05:00
|
|
|
RTLIL::Wire *w_trigger = miter_module->addWire("\\trigger");
|
2014-02-01 03:35:56 -06:00
|
|
|
w_trigger->port_output = true;
|
|
|
|
|
2014-07-25 08:05:18 -05:00
|
|
|
RTLIL::Cell *not_cell = miter_module->addCell(NEW_ID, "$not");
|
2014-07-22 13:15:14 -05:00
|
|
|
not_cell->parameters["\\A_WIDTH"] = all_conditions.size();
|
|
|
|
not_cell->parameters["\\A_WIDTH"] = all_conditions.size();
|
2014-02-01 03:35:56 -06:00
|
|
|
not_cell->parameters["\\Y_WIDTH"] = w_trigger->width;
|
|
|
|
not_cell->parameters["\\A_SIGNED"] = 0;
|
2014-07-31 09:38:54 -05:00
|
|
|
not_cell->setPort("\\A", all_conditions);
|
|
|
|
not_cell->setPort("\\Y", w_trigger);
|
2014-02-01 03:35:56 -06:00
|
|
|
|
|
|
|
miter_module->fixup_ports();
|
2014-07-20 08:23:08 -05:00
|
|
|
|
|
|
|
if (flag_flatten) {
|
|
|
|
log_push();
|
2014-08-07 09:42:35 -05:00
|
|
|
Pass::call_on_module(design, miter_module, "flatten; opt_const -keepdc -undriven;;");
|
2014-07-20 08:23:08 -05:00
|
|
|
log_pop();
|
|
|
|
}
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
struct MiterPass : public Pass {
|
|
|
|
MiterPass() : Pass("miter", "automatically create a miter circuit") { }
|
|
|
|
virtual void help()
|
|
|
|
{
|
|
|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
|
|
|
log("\n");
|
|
|
|
log(" miter -equiv [options] gold_name gate_name miter_name\n");
|
|
|
|
log("\n");
|
|
|
|
log("Creates a miter circuit for equivialence checking. The gold- and gate- modules\n");
|
|
|
|
log("must have the same interfaces. The miter circuit will have all inputs of the\n");
|
|
|
|
log("two source modules, prefixed with 'in_'. The miter circuit has a 'trigger'\n");
|
|
|
|
log("output that goes high if an output mismatch between the two source modules is\n");
|
|
|
|
log("detected.\n");
|
|
|
|
log("\n");
|
|
|
|
log(" -ignore_gold_x\n");
|
|
|
|
log(" a undef (x) bit in the gold module output will match any value in\n");
|
|
|
|
log(" the gate module output.\n");
|
|
|
|
log("\n");
|
|
|
|
log(" -make_outputs\n");
|
|
|
|
log(" also route the gold- and gate-outputs to 'gold_*' and 'gate_*' outputs\n");
|
|
|
|
log(" on the miter circuit.\n");
|
|
|
|
log("\n");
|
2014-02-05 19:20:55 -06:00
|
|
|
log(" -make_outcmp\n");
|
|
|
|
log(" also create a cmp_* output for each gold/gate output pair.\n");
|
|
|
|
log("\n");
|
2014-02-01 03:35:56 -06:00
|
|
|
log(" -make_assert\n");
|
|
|
|
log(" also create an 'assert' cell that checks if trigger is always low.\n");
|
|
|
|
log("\n");
|
2014-07-20 08:23:08 -05:00
|
|
|
log(" -flatten\n");
|
2014-08-07 09:42:35 -05:00
|
|
|
log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n");
|
2014-07-20 08:23:08 -05:00
|
|
|
log("\n");
|
2014-02-01 03:35:56 -06:00
|
|
|
}
|
|
|
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
|
|
|
{
|
|
|
|
if (args.size() > 1 && args[1] == "-equiv") {
|
|
|
|
create_miter_equiv(this, args, design);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_cmd_error("Missing mode parameter!\n");
|
|
|
|
}
|
|
|
|
} MiterPass;
|
|
|
|
|