3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-06-23 01:00:29 +00:00
yosys/techlibs/rapidflex/src/rf_new_dsp.cc
2026-05-14 17:57:12 -07:00

441 lines
12 KiB
C++

#include "kernel/sigtools.h"
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
#include "rf_new_dsp_pm.h"
void swapinput(RTLIL::SigSpec &sigA, RTLIL::SigSpec &sigB) {
if (GetSize(sigA) < GetSize(sigB)) {
RTLIL::SigSpec sigC = sigB;
sigB = sigA;
sigA = sigC;
}
}
void rf_new_dsp(rf_new_dsp_pm &pm) {
auto &st = pm.st_rf_new_dsp;
log("mul1: %s\n", log_id(st.mul1, "--"));
log("mul2: %s\n", log_id(st.mul2, "--"));
log("mul3: %s\n", log_id(st.mul3, "--"));
log("mul4: %s\n", log_id(st.mul4, "--"));
log("postAdd1: %s\n", log_id(st.postAdd1, "--"));
log("postAdd2: %s\n", log_id(st.postAdd2, "--"));
log("postAdd3: %s\n", log_id(st.postAdd3, "--"));
log("postAdd4: %s\n", log_id(st.postAdd4, "--"));
RTLIL::SigSpec sigA, sigB, sigD, sigY;
// mode
string mode;
if (st.level == 4) {
if (st.dinput)
mode +=
"1001"; // 4-level mac with d input: d + a1*b1 + a2*b2 + a3*b3 + a4*b4
else
mode +=
"0000"; // 4-level mac without d input: a1*b1 + a2*b2 + a3*b3 + a4*b4
}
if (st.level == 3)
mode += "1001"; // 3-level mac with d input: d + a1*b1 + a2*b2 + a3*b3
if (st.level == 2) {
if (st.dinput)
mode += "0001"; // 2-level mac with d input: d + a1*b1 + a2*b2
else
mode += "0010"; // 2-level mac without d input: a1*b1 + a2*b2
}
if (st.level == 1) {
if (st.dinput)
mode += "0101"; // 1-level mac with d input: d + a1*b1
else
return;
}
// input size
int n_size = 0;
int m_size = 0;
int d_size = 0;
string cell_base_name = "mad";
string cell_size_name = "";
string cell_cfg_name = "";
string cell_full_name = "";
if (st.mul1) {
swapinput(st.sigA1, st.sigB1);
n_size = n_size > GetSize(st.sigA1) ? n_size : GetSize(st.sigA1);
m_size = m_size > GetSize(st.sigB1) ? m_size : GetSize(st.sigB1);
}
if (st.mul2) {
swapinput(st.sigA2, st.sigB2);
n_size = n_size > GetSize(st.sigA2) ? n_size : GetSize(st.sigA2);
m_size = m_size > GetSize(st.sigB2) ? m_size : GetSize(st.sigB2);
}
if (st.mul3) {
swapinput(st.sigA3, st.sigB3);
n_size = n_size > GetSize(st.sigA3) ? n_size : GetSize(st.sigA3);
m_size = m_size > GetSize(st.sigB3) ? m_size : GetSize(st.sigB3);
}
if (st.mul4) {
swapinput(st.sigA4, st.sigB4);
n_size = n_size > GetSize(st.sigA4) ? n_size : GetSize(st.sigA4);
m_size = m_size > GetSize(st.sigB4) ? m_size : GetSize(st.sigB4);
}
if (st.dinput)
d_size = GetSize(st.sigD);
if (mode == "0100") {
n_size = (n_size + 1) / 2;
m_size = (m_size + 1) / 2;
}
if (n_size <= 2 && m_size <= 2 && d_size <= 4) {
// Too narrow
return;
} else if (n_size <= 12 && m_size <= 10 && d_size <= 30) {
cell_size_name = "12x10x22";
n_size = 12;
m_size = 10;
d_size = 30;
} else if (n_size <= 24 && m_size <= 20 && d_size <= 52) {
cell_size_name = "24x20x44";
n_size = 24;
m_size = 20;
d_size = 52;
} else {
// Too wide
return;
}
// cell
cell_full_name = cell_base_name + cell_size_name + cell_cfg_name;
string cellname;
cellname += "newdsp_" + RTLIL::unescape_id(st.mul1->name);
RTLIL::Cell *cell = pm.module->addCell(RTLIL::escape_id(cellname),
RTLIL::escape_id(cell_full_name));
// D input
bool d_signed = false;
if (st.dinput) {
d_signed = st.postAdd1->getParam(ID(A_SIGNED)).as_bool();
if (mode == "0001")
sigD.extend_u0(d_size);
sigD.append(st.sigD);
}
sigD.extend_u0(2 * d_size, d_signed);
// output
if (st.multiout2 || st.multiout3) {
auto *wire = pm.module->addWire(NEW_ID, d_size - GetSize(st.sigY2));
sigY.append(st.sigY2);
sigY.append(wire);
sigY.append(st.sigY);
} else if (mode == "0001" || (st.level == 4 && st.dinput)) {
auto *wire = pm.module->addWire(NEW_ID, d_size);
sigY.append(wire);
sigY.append(st.sigY);
} else
sigY.append(st.sigY);
auto *wire = pm.module->addWire(NEW_ID, 2 * d_size - GetSize(sigY));
sigY.append(wire);
// input
bool a_signed, b_signed;
if (mode == "0001") {
sigA.extend_u0(2 * n_size);
sigB.extend_u0(2 * m_size);
}
if (st.mul1 && mode != "0100") {
a_signed = st.mul1->getParam(ID(A_SIGNED)).as_bool();
b_signed = st.mul1->getParam(ID(B_SIGNED)).as_bool();
st.sigA1.extend_u0(n_size, a_signed);
st.sigB1.extend_u0(m_size, b_signed);
sigA.append(st.sigA1);
sigB.append(st.sigB1);
}
if (mode == "0100") {
a_signed = st.mul1->getParam(ID(A_SIGNED)).as_bool();
b_signed = st.mul1->getParam(ID(B_SIGNED)).as_bool();
st.sigA1.extend_u0(2 * n_size, a_signed);
st.sigB1.extend_u0(2 * m_size, b_signed);
sigA.append(st.sigA1);
sigB.append(st.sigB1);
}
if (!st.dinput && st.mul4) {
a_signed = st.mul4->getParam(ID(A_SIGNED)).as_bool();
b_signed = st.mul4->getParam(ID(B_SIGNED)).as_bool();
st.sigA4.extend_u0(n_size, a_signed);
st.sigB4.extend_u0(m_size, b_signed);
sigA.append(st.sigA4);
sigB.append(st.sigB4);
}
if (st.mul2) {
a_signed = st.mul2->getParam(ID(A_SIGNED)).as_bool();
b_signed = st.mul2->getParam(ID(B_SIGNED)).as_bool();
st.sigA2.extend_u0(n_size, a_signed);
st.sigB2.extend_u0(m_size, b_signed);
sigA.append(st.sigA2);
sigB.append(st.sigB2);
}
if (st.mul3) {
a_signed = st.mul3->getParam(ID(A_SIGNED)).as_bool();
b_signed = st.mul3->getParam(ID(B_SIGNED)).as_bool();
st.sigA3.extend_u0(n_size, a_signed);
st.sigB3.extend_u0(m_size, b_signed);
sigA.append(st.sigA3);
sigB.append(st.sigB3);
}
if (st.dinput && st.mul4) {
a_signed = st.mul4->getParam(ID(A_SIGNED)).as_bool();
b_signed = st.mul4->getParam(ID(B_SIGNED)).as_bool();
st.sigA4.extend_u0(n_size, a_signed);
st.sigB4.extend_u0(m_size, b_signed);
sigA.append(st.sigA4);
sigB.append(st.sigB4);
}
sigA.extend_u0(4 * n_size);
sigB.extend_u0(4 * m_size);
// reg
mode = "00000" + mode + "0000";
if (st.level == 1) {
if (st.ffA1 && st.ffB1 && !(st.dinput && !st.ffD)) {
mode[1] = mode[2] = '1';
pm.autoremove(st.ffA1);
pm.autoremove(st.ffB1);
if (st.dinput)
pm.autoremove(st.ffD);
}
if (st.ffM1 && st.ffD && st.postAdd1) {
mode[11] = '1';
pm.autoremove(st.ffM1);
pm.autoremove(st.ffD);
}
if (st.ffY1 || (!st.postAdd1 && st.ffM1)) {
mode[3] = mode[4] = '1';
pm.autoremove(st.ffY1);
pm.autoremove(st.ffM1);
}
}
if (st.level == 2) {
if (st.ffA1 && st.ffB1 && st.ffA2 && st.ffB2 && st.dinput &&
st.ffD) // in reg
{
mode[1] = mode[2] = '1';
pm.autoremove(st.ffA1);
pm.autoremove(st.ffB1);
pm.autoremove(st.ffA2);
pm.autoremove(st.ffB2);
pm.autoremove(st.ffD);
}
if (st.ffA1 && st.ffB1 && st.ffA4 && st.ffB4 && !st.dinput) // in reg
{
mode[1] = mode[2] = '1';
pm.autoremove(st.ffA1);
pm.autoremove(st.ffB1);
pm.autoremove(st.ffA4);
pm.autoremove(st.ffB4);
}
if (st.ffM1 && ((st.dinput && st.ffM2) || st.ffD)) // mul in reg
{
mode[11] = '1';
pm.autoremove(st.ffM1);
pm.autoremove(st.ffD);
if (st.dinput)
pm.autoremove(st.ffM2);
}
if (st.ffY1 && st.ffY2 && st.dinput) // mul out reg
{
mode[12] = '1';
pm.autoremove(st.ffY1);
pm.autoremove(st.ffY2);
} else if (st.ffY1 || st.ffY2) // out reg
{
mode[3] = mode[4] = '1';
pm.autoremove(st.ffY1);
pm.autoremove(st.ffY2);
}
}
if (st.ffA1 && st.ffB1 && st.ffA2 && st.ffB2 && st.dinput &&
st.ffD) // in reg low
{
mode[2] = '1';
pm.autoremove(st.ffA1);
pm.autoremove(st.ffB1);
pm.autoremove(st.ffA2);
pm.autoremove(st.ffB2);
pm.autoremove(st.ffD);
}
if (st.ffA1 && st.ffB1 && st.ffA4 && st.ffB4 && !st.dinput) // in reg low
{
mode[2] = '1';
pm.autoremove(st.ffA1);
pm.autoremove(st.ffB1);
pm.autoremove(st.ffA4);
pm.autoremove(st.ffB4);
}
if (st.level == 3) {
if (st.ffA3 && st.ffB3 && st.dinput) // in reg high
{
mode[1] = '1';
pm.autoremove(st.ffA3);
pm.autoremove(st.ffB3);
}
if (st.ffA2 && st.ffB2 && !st.dinput) // in reg high
{
mode[1] = '1';
pm.autoremove(st.ffA2);
pm.autoremove(st.ffB2);
}
if (st.ffM1 && st.ffM2 && ((st.dinput && st.ffM3) || st.ffD)) // mul in reg
{
mode[11] = '1';
pm.autoremove(st.ffM1);
pm.autoremove(st.ffD);
pm.autoremove(st.ffM2);
if (st.dinput)
pm.autoremove(st.ffM3);
}
if (st.ffY1 && st.ffY2 && !(st.dinput && !st.ffY3)) // mul out reg
{
mode[12] = '1';
pm.autoremove(st.ffY1);
pm.autoremove(st.ffY2);
if (st.dinput)
pm.autoremove(st.ffY3);
} else if (st.ffY2 || st.ffY3) // out reg
{
mode[3] = mode[4] = '1';
pm.autoremove(st.ffY2);
pm.autoremove(st.ffY3);
}
}
if (st.level == 4) {
if (st.ffA3 && st.ffB3 && st.ffA4 && st.ffB4 && st.dinput) // in reg high
{
mode[1] = '1';
pm.autoremove(st.ffA3);
pm.autoremove(st.ffB3);
pm.autoremove(st.ffA4);
pm.autoremove(st.ffB4);
}
if (st.ffA2 && st.ffB2 && st.ffA3 && st.ffB3 && !st.dinput) // in reg high
{
mode[1] = '1';
pm.autoremove(st.ffA2);
pm.autoremove(st.ffB2);
pm.autoremove(st.ffA3);
pm.autoremove(st.ffB3);
}
if (st.ffM1 && st.ffM2 && st.ffM3 &&
((st.dinput && st.ffM4) || st.ffD)) // mul in reg
{
mode[11] = '1';
pm.autoremove(st.ffM1);
pm.autoremove(st.ffD);
pm.autoremove(st.ffM2);
pm.autoremove(st.ffM3);
if (st.dinput)
pm.autoremove(st.ffM4);
}
if (st.ffY1 && st.ffY2 && st.ffY3 &&
!(st.dinput && !st.ffY4)) // mul out reg
{
mode[12] = '1';
pm.autoremove(st.ffY1);
pm.autoremove(st.ffY2);
pm.autoremove(st.ffY3);
if (st.dinput)
pm.autoremove(st.ffY4);
} else if (st.ffY3 || st.ffY4) // out reg high
{
if (st.multiout2 || st.multiout3)
mode[3] = '1';
else
mode[3] = mode[4] = '1';
pm.autoremove(st.ffY3);
pm.autoremove(st.ffY4);
}
if (st.ffMY) // out reg low
{
mode[4] = '1';
pm.autoremove(st.ffMY);
}
}
cell->setPort(RTLIL::escape_id("a_i"), sigA);
cell->setPort(RTLIL::escape_id("b_i"), sigB);
cell->setPort(RTLIL::escape_id("d_i"), sigD);
cell->setPort(RTLIL::escape_id("out_o"), sigY);
cell->setPort(RTLIL::escape_id("mode_i"), Const::from_string(mode));
if (st.clock != SigBit())
cell->setPort(RTLIL::escape_id("clk_i"), st.clock);
cell->setPort(RTLIL::escape_id("rst_acc"), RTLIL::SigSpec(0, 1));
cell->setPort(RTLIL::escape_id("accsel"), RTLIL::SigSpec(0, 1));
cell->setPort(RTLIL::escape_id("cas_g"), RTLIL::SigSpec(0, 1));
pm.autoremove(st.mul1);
pm.autoremove(st.mul2);
pm.autoremove(st.mul3);
pm.autoremove(st.mul4);
pm.autoremove(st.postAdd1);
pm.autoremove(st.postAdd2);
pm.autoremove(st.postAdd3);
pm.autoremove(st.postAdd4);
}
struct RfNewDSP : public Pass {
bool show_help;
RfNewDSP()
: Pass("rf_new_dsp",
"Extract multiply-add operators and map to new_dsps") {}
void help() override {
log("\n");
log(" rf_new_dsp [options] [selection]\n");
log("\n");
log(" Extract multiply-add operators and map to new_dsps\n");
log("\n");
log(" -help: show help desk\n");
log("\n");
log(" -n_size: specify input n size\n");
log("\n");
log(" -m_size: specify input m size\n");
log("\n");
}
void clear_flags() override { show_help = false; }
void execute(std::vector<std::string> a_Args,
RTLIL::Design *a_Design) override {
log_header(a_Design, "Executing RF_NEW_DSP pass.\n");
size_t argidx;
for (argidx = 1; argidx < a_Args.size(); argidx++) {
if (a_Args[argidx] == "-help") {
show_help = true;
continue;
}
break;
}
extra_args(a_Args, argidx, a_Design);
if (show_help) {
help();
return;
}
for (auto module : a_Design->selected_modules()) {
rf_new_dsp_pm pm(module, module->selected_cells());
pm.run_rf_new_dsp(rf_new_dsp);
}
}
} RfNewDsp;
PRIVATE_NAMESPACE_END