| /* |
| * 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/yosys.h" |
| #include "kernel/sigtools.h" |
| |
| USING_YOSYS_NAMESPACE |
| PRIVATE_NAMESPACE_BEGIN |
| |
| struct ChformalPass : public Pass { |
| ChformalPass() : Pass("chformal", "change formal constraints of the design") { } |
| void help() YS_OVERRIDE |
| { |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| log("\n"); |
| log(" chformal [types] [mode] [options] [selection]\n"); |
| log("\n"); |
| log("Make changes to the formal constraints of the design. The [types] options\n"); |
| log("the type of constraint to operate on. If none of the following options are given,\n"); |
| log("the command will operate on all constraint types:\n"); |
| log("\n"); |
| log(" -assert $assert cells, representing assert(...) constraints\n"); |
| log(" -assume $assume cells, representing assume(...) constraints\n"); |
| log(" -live $live cells, representing assert(s_eventually ...)\n"); |
| log(" -fair $fair cells, representing assume(s_eventually ...)\n"); |
| log(" -cover $cover cells, representing cover() statements\n"); |
| log("\n"); |
| log("Exactly one of the following modes must be specified:\n"); |
| log("\n"); |
| log(" -remove\n"); |
| log(" remove the cells and thus constraints from the design\n"); |
| log("\n"); |
| log(" -early\n"); |
| log(" bypass FFs that only delay the activation of a constraint\n"); |
| log("\n"); |
| log(" -delay <N>\n"); |
| log(" delay activation of the constraint by <N> clock cycles\n"); |
| log("\n"); |
| log(" -skip <N>\n"); |
| log(" ignore activation of the constraint in the first <N> clock cycles\n"); |
| log("\n"); |
| log(" -assert2assume\n"); |
| log(" -assume2assert\n"); |
| log(" -live2fair\n"); |
| log(" -fair2live\n"); |
| log(" change the roles of cells as indicated. these options can be combined\n"); |
| log("\n"); |
| } |
| void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE |
| { |
| bool assert2assume = false; |
| bool assume2assert = false; |
| bool live2fair = false; |
| bool fair2live = false; |
| |
| pool<IdString> constr_types; |
| char mode = 0; |
| int mode_arg = 0; |
| |
| size_t argidx; |
| for (argidx = 1; argidx < args.size(); argidx++) |
| { |
| if (args[argidx] == "-assert") { |
| constr_types.insert("$assert"); |
| continue; |
| } |
| if (args[argidx] == "-assume") { |
| constr_types.insert("$assume"); |
| continue; |
| } |
| if (args[argidx] == "-live") { |
| constr_types.insert("$live"); |
| continue; |
| } |
| if (args[argidx] == "-fair") { |
| constr_types.insert("$fair"); |
| continue; |
| } |
| if (args[argidx] == "-cover") { |
| constr_types.insert("$cover"); |
| continue; |
| } |
| if (mode == 0 && args[argidx] == "-remove") { |
| mode = 'r'; |
| continue; |
| } |
| if (mode == 0 && args[argidx] == "-early") { |
| mode = 'e'; |
| continue; |
| } |
| if (mode == 0 && args[argidx] == "-delay" && argidx+1 < args.size()) { |
| mode = 'd'; |
| mode_arg = atoi(args[++argidx].c_str()); |
| continue; |
| } |
| if (mode == 0 && args[argidx] == "-skip" && argidx+1 < args.size()) { |
| mode = 's'; |
| mode_arg = atoi(args[++argidx].c_str()); |
| continue; |
| } |
| if ((mode == 0 || mode == 'c') && args[argidx] == "-assert2assume") { |
| assert2assume = true; |
| mode = 'c'; |
| continue; |
| } |
| if ((mode == 0 || mode == 'c') && args[argidx] == "-assume2assert") { |
| assume2assert = true; |
| mode = 'c'; |
| continue; |
| } |
| if ((mode == 0 || mode == 'c') && args[argidx] == "-live2fair") { |
| live2fair = true; |
| mode = 'c'; |
| continue; |
| } |
| if ((mode == 0 || mode == 'c') && args[argidx] == "-fair2live") { |
| fair2live = true; |
| mode = 'c'; |
| continue; |
| } |
| break; |
| } |
| extra_args(args, argidx, design); |
| |
| if (constr_types.empty()) { |
| constr_types.insert("$assert"); |
| constr_types.insert("$assume"); |
| constr_types.insert("$live"); |
| constr_types.insert("$fair"); |
| constr_types.insert("$cover"); |
| } |
| |
| if (mode == 0) |
| log_cmd_error("Mode option is missing.\n"); |
| |
| for (auto module : design->selected_modules()) |
| { |
| vector<Cell*> constr_cells; |
| |
| for (auto cell : module->selected_cells()) |
| if (constr_types.count(cell->type)) |
| constr_cells.push_back(cell); |
| |
| if (mode == 'r') |
| { |
| for (auto cell : constr_cells) |
| module->remove(cell); |
| } |
| else |
| if (mode == 'e') |
| { |
| SigMap sigmap(module); |
| dict<SigBit, pair<SigBit, pair<SigBit, bool>>> ffmap; |
| pool<SigBit> init_zero, init_one; |
| |
| for (auto wire : module->wires()) |
| { |
| if (wire->attributes.count("\\init") == 0) |
| continue; |
| |
| SigSpec initsig = sigmap(wire); |
| Const initval = wire->attributes.at("\\init"); |
| |
| for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) { |
| if (initval[i] == State::S0) |
| init_zero.insert(initsig[i]); |
| if (initval[i] == State::S1) |
| init_one.insert(initsig[i]); |
| } |
| } |
| |
| for (auto cell : module->selected_cells()) |
| { |
| if (cell->type == "$ff") { |
| SigSpec D = sigmap(cell->getPort("\\D")); |
| SigSpec Q = sigmap(cell->getPort("\\Q")); |
| for (int i = 0; i < GetSize(D); i++) |
| ffmap[Q[i]] = make_pair(D[i], make_pair(State::Sm, false)); |
| } |
| if (cell->type == "$dff") { |
| SigSpec D = sigmap(cell->getPort("\\D")); |
| SigSpec Q = sigmap(cell->getPort("\\Q")); |
| SigSpec C = sigmap(cell->getPort("\\CLK")); |
| bool clockpol = cell->getParam("\\CLK_POLARITY").as_bool(); |
| for (int i = 0; i < GetSize(D); i++) |
| ffmap[Q[i]] = make_pair(D[i], make_pair(C, clockpol)); |
| } |
| } |
| |
| for (auto cell : constr_cells) |
| while (true) |
| { |
| SigSpec A = sigmap(cell->getPort("\\A")); |
| SigSpec EN = sigmap(cell->getPort("\\EN")); |
| |
| if (ffmap.count(A) == 0 || ffmap.count(EN) == 0) |
| break; |
| |
| if (!init_zero.count(EN)) { |
| if (cell->type == "$cover") break; |
| if (cell->type.in("$assert", "$assume") && !init_one.count(A)) break; |
| } |
| |
| const auto &A_map = ffmap.at(A); |
| const auto &EN_map = ffmap.at(EN); |
| |
| if (A_map.second != EN_map.second) |
| break; |
| |
| cell->setPort("\\A", A_map.first); |
| cell->setPort("\\EN", EN_map.first); |
| } |
| } |
| else |
| if (mode == 'd') |
| { |
| for (auto cell : constr_cells) |
| for (int i = 0; i < mode_arg; i++) |
| { |
| SigSpec orig_a = cell->getPort("\\A"); |
| SigSpec orig_en = cell->getPort("\\EN"); |
| |
| Wire *new_a = module->addWire(NEW_ID); |
| Wire *new_en = module->addWire(NEW_ID); |
| new_en->attributes["\\init"] = State::S0; |
| |
| module->addFf(NEW_ID, orig_a, new_a); |
| module->addFf(NEW_ID, orig_en, new_en); |
| |
| cell->setPort("\\A", new_a); |
| cell->setPort("\\EN", new_en); |
| } |
| } |
| else |
| if (mode == 's') |
| { |
| SigSpec en = State::S1; |
| |
| for (int i = 0; i < mode_arg; i++) { |
| Wire *w = module->addWire(NEW_ID); |
| w->attributes["\\init"] = State::S0; |
| module->addFf(NEW_ID, en, w); |
| en = w; |
| } |
| |
| for (auto cell : constr_cells) |
| cell->setPort("\\EN", module->LogicAnd(NEW_ID, en, cell->getPort("\\EN"))); |
| } |
| else |
| if (mode == 'c') |
| { |
| for (auto cell : constr_cells) |
| if (assert2assume && cell->type == "$assert") |
| cell->type = "$assume"; |
| else if (assume2assert && cell->type == "$assume") |
| cell->type = "$assert"; |
| else if (live2fair && cell->type == "$live") |
| cell->type = "$fair"; |
| else if (fair2live && cell->type == "$fair") |
| cell->type = "$live"; |
| } |
| } |
| } |
| } ChformalPass; |
| |
| PRIVATE_NAMESPACE_END |