| /* | |
| * 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 | |
| void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell) | |
| { | |
| if (cell->type == ID($dffsr)) | |
| { | |
| int width = cell->getParam(ID(WIDTH)).as_int(); | |
| bool setpol = cell->getParam(ID(SET_POLARITY)).as_bool(); | |
| bool clrpol = cell->getParam(ID(CLR_POLARITY)).as_bool(); | |
| SigBit setunused = setpol ? State::S0 : State::S1; | |
| SigBit clrunused = clrpol ? State::S0 : State::S1; | |
| SigSpec setsig = sigmap(cell->getPort(ID(SET))); | |
| SigSpec clrsig = sigmap(cell->getPort(ID(CLR))); | |
| Const reset_val; | |
| SigSpec setctrl, clrctrl; | |
| for (int i = 0; i < width; i++) | |
| { | |
| SigBit setbit = setsig[i], clrbit = clrsig[i]; | |
| if (setbit == setunused) { | |
| clrctrl.append(clrbit); | |
| reset_val.bits.push_back(State::S0); | |
| continue; | |
| } | |
| if (clrbit == clrunused) { | |
| setctrl.append(setbit); | |
| reset_val.bits.push_back(State::S1); | |
| continue; | |
| } | |
| return; | |
| } | |
| setctrl.sort_and_unify(); | |
| clrctrl.sort_and_unify(); | |
| if (GetSize(setctrl) > 1 || GetSize(clrctrl) > 1) | |
| return; | |
| if (GetSize(setctrl) == 0 && GetSize(clrctrl) == 0) | |
| return; | |
| if (GetSize(setctrl) == 1 && GetSize(clrctrl) == 1) { | |
| if (setpol != clrpol) | |
| return; | |
| if (setctrl != clrctrl) | |
| return; | |
| } | |
| log("Converting %s cell %s.%s to $adff.\n", log_id(cell->type), log_id(module), log_id(cell)); | |
| if (GetSize(setctrl) == 1) { | |
| cell->setPort(ID(ARST), setctrl); | |
| cell->setParam(ID(ARST_POLARITY), setpol); | |
| } else { | |
| cell->setPort(ID(ARST), clrctrl); | |
| cell->setParam(ID(ARST_POLARITY), clrpol); | |
| } | |
| cell->type = ID($adff); | |
| cell->unsetPort(ID(SET)); | |
| cell->unsetPort(ID(CLR)); | |
| cell->setParam(ID(ARST_VALUE), reset_val); | |
| cell->unsetParam(ID(SET_POLARITY)); | |
| cell->unsetParam(ID(CLR_POLARITY)); | |
| return; | |
| } | |
| if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), | |
| ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_))) | |
| { | |
| char clkpol = cell->type.c_str()[8]; | |
| char setpol = cell->type.c_str()[9]; | |
| char clrpol = cell->type.c_str()[10]; | |
| SigBit setbit = sigmap(cell->getPort(ID(S))); | |
| SigBit clrbit = sigmap(cell->getPort(ID(R))); | |
| SigBit setunused = setpol == 'P' ? State::S0 : State::S1; | |
| SigBit clrunused = clrpol == 'P' ? State::S0 : State::S1; | |
| IdString oldtype = cell->type; | |
| if (setbit == setunused) { | |
| cell->type = stringf("$_DFF_%c%c0_", clkpol, clrpol); | |
| cell->unsetPort(ID(S)); | |
| goto converted_gate; | |
| } | |
| if (clrbit == clrunused) { | |
| cell->type = stringf("$_DFF_%c%c1_", clkpol, setpol); | |
| cell->setPort(ID(R), cell->getPort(ID(S))); | |
| cell->unsetPort(ID(S)); | |
| goto converted_gate; | |
| } | |
| return; | |
| converted_gate: | |
| log("Converting %s cell %s.%s to %s.\n", log_id(oldtype), log_id(module), log_id(cell), log_id(cell->type)); | |
| return; | |
| } | |
| } | |
| void adff_worker(SigMap &sigmap, Module *module, Cell *cell) | |
| { | |
| if (cell->type == ID($adff)) | |
| { | |
| bool rstpol = cell->getParam(ID(ARST_POLARITY)).as_bool(); | |
| SigBit rstunused = rstpol ? State::S0 : State::S1; | |
| SigSpec rstsig = sigmap(cell->getPort(ID(ARST))); | |
| if (rstsig != rstunused) | |
| return; | |
| log("Converting %s cell %s.%s to $dff.\n", log_id(cell->type), log_id(module), log_id(cell)); | |
| cell->type = ID($dff); | |
| cell->unsetPort(ID(ARST)); | |
| cell->unsetParam(ID(ARST_VALUE)); | |
| cell->unsetParam(ID(ARST_POLARITY)); | |
| return; | |
| } | |
| if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), | |
| ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_))) | |
| { | |
| char clkpol = cell->type.c_str()[6]; | |
| char rstpol = cell->type.c_str()[7]; | |
| SigBit rstbit = sigmap(cell->getPort(ID(R))); | |
| SigBit rstunused = rstpol == 'P' ? State::S0 : State::S1; | |
| if (rstbit != rstunused) | |
| return; | |
| IdString newtype = stringf("$_DFF_%c_", clkpol); | |
| log("Converting %s cell %s.%s to %s.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(newtype)); | |
| cell->type = newtype; | |
| cell->unsetPort(ID(R)); | |
| return; | |
| } | |
| } | |
| struct Dffsr2dffPass : public Pass { | |
| Dffsr2dffPass() : Pass("dffsr2dff", "convert DFFSR cells to simpler FF cell types") { } | |
| void help() YS_OVERRIDE | |
| { | |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | |
| log("\n"); | |
| log(" dffsr2dff [options] [selection]\n"); | |
| log("\n"); | |
| log("This pass converts DFFSR cells ($dffsr, $_DFFSR_???_) and ADFF cells ($adff,\n"); | |
| log("$_DFF_???_) to simpler FF cell types when any of the set/reset inputs is unused.\n"); | |
| log("\n"); | |
| } | |
| void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | |
| { | |
| log_header(design, "Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n"); | |
| size_t argidx; | |
| for (argidx = 1; argidx < args.size(); argidx++) | |
| { | |
| // if (args[argidx] == "-v") { | |
| // continue; | |
| // } | |
| break; | |
| } | |
| extra_args(args, argidx, design); | |
| for (auto module : design->selected_modules()) { | |
| SigMap sigmap(module); | |
| for (auto cell : module->selected_cells()) { | |
| dffsr_worker(sigmap, module, cell); | |
| adff_worker(sigmap, module, cell); | |
| } | |
| } | |
| } | |
| } Dffsr2dffPass; | |
| PRIVATE_NAMESPACE_END |