/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf * * 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 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