diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1b57af60acb..efd76e9cd25 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2677,6 +2677,19 @@ RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, const RTLIL::SigSpec &s return cell; } +RTLIL::Cell* RTLIL::Module::addFa(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src) +{ + RTLIL::Cell *cell = addCell(name, ID($fa)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::B, sig_b); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::X, sig_x); + cell->setPort(ID::Y, sig_y); + cell->set_src_attribute(src); + return cell; +} + RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src) { RTLIL::Cell *cell = addCell(name, ID($slice)); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c50d75e9087..3dff48b4f79 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1298,6 +1298,8 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); + RTLIL::Cell* addFa (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index e749168522d..000dcff14ec 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -52,6 +52,9 @@ or in generic synthesis call with -booth argument: synth -top my_design -booth */ +//FIXME: These debug prints are broken now, should be fixed or removed. +//#define DEBUG_CPA + #include "kernel/sigtools.h" #include "kernel/yosys.h" @@ -66,170 +69,89 @@ struct BoothPassWorker { BoothPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } - // Helper routines for building architecture subcomponents - - RTLIL::Wire *mk_wireFromSigSpec(const SigSpec &v) - { - - auto g = module->addCell(NEW_ID, ID($pos)); - Wire *ret = module->addWire(NEW_ID, 1); - g->setPort(ID::A, v); - g->setPort(ID::Y, ret); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - return ret; - } - - // fuse wires. - void join_wires_with_buffer(RTLIL::Wire *ip, RTLIL::Wire *op) - { - std::string wire_name = "join_"; - auto g = module->addCell(new_id(wire_name, __LINE__, ""), ID($pos)); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - g->setPort(ID::A, ip); - g->setPort(ID::Y, op); - } - - // Unary gate - RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, std::string &op_name) - { - std::string op_wire_name; - if (op_name.empty()) - op_wire_name = name + "_o"; - else - op_wire_name = op_name; - RTLIL::Wire *ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); - auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); - g->setPort(ID::A, ip1); - g->setPort(ID::Y, ret); - g->setParam(ID::A_SIGNED, false); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - return ret; - } - - // Binary gate - RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, RTLIL::Wire *ip2, std::string &op_name) - { - auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); - std::string op_wire_name; - if (op_name.empty()) - op_wire_name = name + "_o"; - else - op_wire_name = op_name; - - auto ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); - - g->setPort(ID::A, ip1); - g->setPort(ID::B, ip2); - g->setPort(ID::Y, ret); - g->setParam(ID::A_SIGNED, false); - g->setParam(ID::B_SIGNED, false); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::B_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - return ret; - } - // Booth unsigned decoder lsb - void BuildBur4d_lsb(std::string &name, RTLIL::Wire *lsb_i, RTLIL::Wire *one_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o, - std::string op_wire_name) + SigBit Bur4d_lsb(std::string name, SigBit lsb_i, SigBit one_i, SigBit s_i) { - std::string empty; - auto and_op = mk_ugate2(ID($and), name, lsb_i, one_i, empty); - ppij_o = mk_ugate2(ID($xor), name, and_op, s_i, op_wire_name); + SigBit and_op = module->AndGate(NEW_ID_SUFFIX(name), lsb_i, one_i); + return module->XorGate(NEW_ID_SUFFIX(name), and_op, s_i); } // Booth unsigned radix4 decoder - void BuildBur4d_n(std::string &name, RTLIL::Wire *yn_i, RTLIL::Wire *ynm1_i, RTLIL::Wire *one_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, - RTLIL::Wire *&ppij_o) + SigBit Bur4d_n(std::string name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i) { // ppij = ((yn & one) | (ynm1 & two)) ^ s; - std::string empty; - auto an1 = mk_ugate2(ID($and), name, yn_i, one_i, empty); - auto an2 = mk_ugate2(ID($and), name, ynm1_i, two_i, empty); - auto or1 = mk_ugate2(ID($or), name, an1, an2, empty); - ppij_o = mk_ugate2(ID($xor), name, s_i, or1, empty); + SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), yn_i, one_i); + SigBit an2 = module->AndGate(NEW_ID_SUFFIX(name), ynm1_i, two_i); + SigBit or1 = module->OrGate(NEW_ID_SUFFIX(name), an1, an2); + return module->XorGate(NEW_ID_SUFFIX(name), s_i, or1); } // Booth unsigned radix4 decoder - void BuildBur4d_msb(std::string &name, RTLIL::Wire *msb_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o) + SigBit Bur4d_msb(std::string name, SigBit msb_i, SigBit two_i, SigBit s_i) { // ppij = (msb & two) ^ s; - std::string empty; - auto an1 = mk_ugate2(ID($and), name, msb_i, two_i, empty); - ppij_o = mk_ugate2(ID($xor), name, s_i, an1, empty); + SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), msb_i, two_i); + return module->XorGate(NEW_ID_SUFFIX(name), s_i, an1); } // half adder, used in CPA - void BuildHa(std::string &name, RTLIL::Wire *a_i, RTLIL::Wire *b_i, RTLIL::Wire *&s_o, RTLIL::Wire *&c_o) + void BuildHa(std::string name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) { - std::string empty; - s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); - c_o = mk_ugate2(ID($and), name, a_i, b_i, empty); + s_o = module->XorGate(NEW_ID_SUFFIX(name), a_i, b_i); + c_o = module->AndGate(NEW_ID_SUFFIX(name), a_i, b_i); } // Booth unsigned radix 4 encoder - void BuildBur4e(std::string &name, RTLIL::Wire *y0_i, RTLIL::Wire *y1_i, RTLIL::Wire *y2_i, - - RTLIL::Wire *&one_o, RTLIL::Wire *&two_o, RTLIL::Wire *&s_o, RTLIL::Wire *&sb_o) + void BuildBur4e(std::string name, SigBit y0_i, SigBit y1_i, SigBit y2_i, + SigBit &one_o, SigBit &two_o, SigBit &s_o, SigBit &sb_o) { - - std::string empty; - one_o = mk_ugate2(ID($xor), name, y0_i, y1_i, empty); + one_o = module->XorGate(NEW_ID_SUFFIX(name), y0_i, y1_i); s_o = y2_i; - sb_o = mk_ugate1(ID($not), name, y2_i, empty); - auto inv_y1_xor_y2 = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y1_i, y2_i, empty), empty); - two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); + sb_o = module->NotGate(NEW_ID_SUFFIX(name), y2_i); + SigBit y1_xnor_y2 = module->XnorGate(NEW_ID_SUFFIX(name), y1_i, y2_i); + two_o = module->NorGate(NEW_ID_SUFFIX(name), y1_xnor_y2, one_o); } - void BuildBr4e(std::string &name, RTLIL::Wire *y2_m1_i, - RTLIL::Wire *y2_i, // y2i - RTLIL::Wire *y2_p1_i, - - RTLIL::Wire *&negi_o, RTLIL::Wire *&twoi_n_o, RTLIL::Wire *&onei_n_o, RTLIL::Wire *&cori_o) + void BuildBr4e(std::string name, SigBit y2_m1_i, + SigBit y2_i, // y2i + SigBit y2_p1_i, + SigBit &negi_o, SigBit &twoi_n_o, SigBit &onei_n_o, SigBit &cori_o) { + auto y2_p1_n = module->NotGate(NEW_ID_SUFFIX(name), y2_p1_i); + auto y2_n = module->NotGate(NEW_ID_SUFFIX(name), y2_i); + auto y2_m1_n = module->NotGate(NEW_ID_SUFFIX(name), y2_m1_i); - std::string empty; - auto y2_p1_n = mk_ugate1(ID($not), name, y2_p1_i, empty); - auto y2_n = mk_ugate1(ID($not), name, y2_i, empty); - auto y2_m1_n = mk_ugate1(ID($not), name, y2_m1_i, empty); + negi_o = y2_p1_i; - // negi_o = y2_p1_i - negi_o = mk_ugate1(ID($pos), name, y2_p1_i, empty); // twoi_n = ~( // (y2_p1_n & y2_i & y2_m1_i) | // (y2_p1 & y2_n & y2_m1_n) // ) - auto and3_1 = mk_ugate2(ID($and), name, y2_p1_n, mk_ugate2(ID($and), name, y2_i, y2_m1_i, empty), empty); - auto and3_2 = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($and), name, y2_n, y2_m1_n, empty), empty); + twoi_n_o = module->NorGate(NEW_ID_SUFFIX(name), + module->AndGate(NEW_ID_SUFFIX(name), y2_p1_n, module->AndGate(NEW_ID_SUFFIX(name), y2_i, y2_m1_i)), + module->AndGate(NEW_ID_SUFFIX(name), y2_p1_i, module->AndGate(NEW_ID_SUFFIX(name), y2_n, y2_m1_n)) + ); - twoi_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, and3_1, and3_2, empty), empty); // onei_n = ~(y2_m1_i ^ y2_i); - onei_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y2_m1_i, y2_i, empty), empty); + onei_n_o = module->XnorGate(NEW_ID_SUFFIX(name), y2_m1_i, y2_i); // cori = (y2_m1_n | y2_n) & y2_p1_i; - cori_o = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($or), name, y2_m1_n, y2_n, empty), empty); + cori_o = module->AndGate(NEW_ID_SUFFIX(name), module->OrGate(NEW_ID_SUFFIX(name), y2_m1_n, y2_n), y2_p1_i); } // // signed booth radix 4 decoder // - void BuildBr4d(std::string &name, RTLIL::Wire *nxj_m1_i, RTLIL::Wire *twoi_n_i, RTLIL::Wire *xj_i, RTLIL::Wire *negi_i, RTLIL::Wire *onei_n_i, - - RTLIL::Wire *&ppij_o, RTLIL::Wire *&nxj_o) + void BuildBr4d(std::string name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, + SigBit &ppij_o, SigBit &nxj_o) { - - std::string empty; // nxj_in = xnor(xj,negi) // nxj_o = xnj_in, // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); - nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); - RTLIL::Wire *or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); - RTLIL::Wire *or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); - ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); + nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), xj_i, negi_i); + ppij_o = module->NandGate(NEW_ID_SUFFIX(name), + module->OrGate(NEW_ID_SUFFIX(name), nxj_m1_i, twoi_n_i), + module->OrGate(NEW_ID_SUFFIX(name), nxj_o, onei_n_i) + ); } /* @@ -237,12 +159,9 @@ struct BoothPassWorker { using non-booth encoded logic. We can save a booth encoder for the first couple of bits. */ - void BuildBoothQ1(std::string &name, RTLIL::Wire *negi_i, RTLIL::Wire *cori_i, RTLIL::Wire *x0_i, RTLIL::Wire *x1_i, RTLIL::Wire *y0_i, - RTLIL::Wire *y1_i, - - RTLIL::Wire *&nxj_o, RTLIL::Wire *&cor_o, RTLIL::Wire *&pp0_o, RTLIL::Wire *&pp1_o - - ) + void BuildBoothQ1(std::string name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, + SigBit y1_i, + SigBit &nxj_o, SigBit &cor_o, SigBit &pp0_o, SigBit &pp1_o) { /* assign NXJO = ~(X1 ^ NEGI); @@ -255,122 +174,105 @@ struct BoothPassWorker { //correction propagation assign CORO = (~PP1 & ~PP0)? CORI : 1'b0; */ - std::string empty; - nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); - pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); - RTLIL::Wire *pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); - RTLIL::Wire *pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); - pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty); - - RTLIL::Wire *pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); - cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); + nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), x1_i, negi_i); + pp0_o = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y0_i); + SigBit pp1_1_int = module->AndGate(NEW_ID_SUFFIX(name), x1_i, y0_i); + SigBit pp1_2_int = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y1_i); + pp1_o = module->XorGate(NEW_ID_SUFFIX(name), pp1_1_int, pp1_2_int); + + SigBit pp1_nor_pp0 = module->NorGate(NEW_ID_SUFFIX(name), pp1_o, pp0_o); + cor_o = module->AndGate(NEW_ID_SUFFIX(name), pp1_nor_pp0, cori_i); } void run() { for (auto cell : module->selected_cells()) { - if (cell->type.in(ID($mul))) { - RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); - RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); - RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); - if (GetSize(A) >= 4 && GetSize(B) >= 4 && GetSize(Y) >= 8 && - ((cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) || - (!cell->getParam(ID::A_SIGNED).as_bool() && !cell->getParam(ID::B_SIGNED).as_bool()))) { - bool is_signed = false; - if (cell->getParam(ID::A_SIGNED).as_bool()) { - log(" By passing macc inferencing for signed multiplier -- generating booth\n"); - is_signed = true; - } else - log(" By passing macc inferencing for unsigned multiplier -- generating booth\n"); - - int x_sz = GetSize(A); - int y_sz = GetSize(B); - int z_sz = GetSize(Y); - - // To simplify the generator size the arguments - // to be the same. Then allow logic synthesis to - // clean things up. Size to biggest - - int x_sz_revised = x_sz; - int y_sz_revised = y_sz; - - if (x_sz != y_sz) { - if (x_sz < y_sz) { - if (y_sz % 2 != 0) { - x_sz_revised = y_sz + 1; - y_sz_revised = y_sz + 1; - } else - x_sz_revised = y_sz; - - } else { - if (x_sz % 2 != 0) { - y_sz_revised = x_sz + 1; - x_sz_revised = x_sz + 1; - } else - y_sz_revised = x_sz; - } + if (cell->type != ID($mul)) + continue; + + SigSpec A = cell->getPort(ID::A); + SigSpec B = cell->getPort(ID::B); + SigSpec Y = cell->getPort(ID::Y); + int x_sz = GetSize(A), y_sz = GetSize(B), z_sz = GetSize(Y); + + if (x_sz < 4 || y_sz < 4 || z_sz < 8) { + log_debug("Not mapping cell %s sized at %dx%x, %x: size below threshold\n", + log_id(cell), x_sz, y_sz, z_sz); + continue; + } + + log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool()); + bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); + + log("Mapping cell %s to %s Booth multiplier\n", log_id(cell), is_signed ? "signed" : "unsigned"); + + // To simplify the generator size the arguments + // to be the same. Then allow logic synthesis to + // clean things up. Size to biggest + + int x_sz_revised = x_sz; + int y_sz_revised = y_sz; + + if (x_sz != y_sz) { + if (x_sz < y_sz) { + if (y_sz % 2 != 0) { + x_sz_revised = y_sz + 1; + y_sz_revised = y_sz + 1; } else { - if (x_sz % 2 != 0) { - y_sz_revised = y_sz + 1; - x_sz_revised = x_sz + 1; - } + x_sz_revised = y_sz; + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = x_sz + 1; + x_sz_revised = x_sz + 1; + } else { + y_sz_revised = x_sz; } - - log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); - - Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); - Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); - - std::string buf_name = "expand_a_buf_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setParam(ID::A_WIDTH, x_sz); - buf->setParam(ID::Y_WIDTH, x_sz_revised); - buf->setPort(ID::A, SigSpec(A)); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - buf->setPort(ID::Y, SigSpec(expanded_A)); - - buf_name = "expand_b_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, SigSpec(B)); - buf->setParam(ID::A_WIDTH, y_sz); - buf->setParam(ID::Y_WIDTH, y_sz_revised); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - buf->setPort(ID::Y, SigSpec(expanded_B)); - - // Make sure output domain is big enough to take - // all combinations. - // Later logic synthesis will kill unused - // portions of the output domain. - - unsigned required_op_size = x_sz_revised + y_sz_revised; - Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); - // now connect the expanded_Y with a tap to fill out sig Spec Y - buf_name = "reducer_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, expanded_Y); - buf->setParam(ID::A_WIDTH, required_op_size); - buf->setParam(ID::Y_WIDTH, z_sz); // The real user width - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - // wire in output Y - buf->setPort(ID::Y, SigSpec(Y)); - - if (is_signed == false) /* unsigned multiplier */ - CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size, - expanded_A, // multiplicand - expanded_B, // multiplier(scanned) - expanded_Y // result - ); - else /*signed multiplier */ - CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size, - expanded_A, // multiplicand - expanded_B, // multiplier(scanned) - expanded_Y // result (sized) - ); - module->remove(cell); - booth_counter++; - continue; } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = y_sz + 1; + x_sz_revised = x_sz + 1; + } + } + + log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); + + + A.extend_u0(x_sz_revised, is_signed); + B.extend_u0(y_sz_revised, is_signed); + + // Make sure output domain is big enough to take + // all combinations. + // Later logic synthesis will kill unused + // portions of the output domain. + + int required_op_size = x_sz_revised + y_sz_revised; + + if (required_op_size != z_sz) { + SigSpec expanded_Y = module->addWire(NEW_ID, required_op_size); + SigSpec Y_driver = expanded_Y; + Y_driver.extend_u0(Y.size(), is_signed); + module->connect(Y, Y_driver); + Y = expanded_Y; } + log_assert(GetSize(Y) == required_op_size); + + if (!is_signed) /* unsigned multiplier */ + CreateBoothUMult(module, + A, // multiplicand + B, // multiplier(scanned) + Y // result + ); + else /* signed multiplier */ + CreateBoothSMult(module, + A, // multiplicand + B, // multiplier(scanned) + Y // result (sized) + ); + + module->remove(cell); + booth_counter++; } } @@ -382,19 +284,17 @@ struct BoothPassWorker { extra row of decoders and extended multiplier */ - void CreateBoothUMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, - RTLIL::Wire *X, // multiplicand - RTLIL::Wire *Y, // multiplier - RTLIL::Wire *Z) + void CreateBoothUMult(RTLIL::Module *module, + SigSpec X, // multiplicand + SigSpec Y, // multiplier + SigSpec Z) { // result + int x_sz = X.size(), z_sz = Z.size(); - std::vector one_int; - std::vector two_int; - std::vector s_int; - std::vector sb_int; + SigSpec one_int, two_int, s_int, sb_int; int encoder_count = 0; - BuildBoothUMultEncoders(Y, y_sz, one_int, two_int, s_int, sb_int, module, encoder_count); + BuildBoothUMultEncoders(Y, one_int, two_int, s_int, sb_int, module, encoder_count); // Build the decoder rows // format of each Partial product to be passed to CSA @@ -404,31 +304,10 @@ struct BoothPassWorker { // Shift // Sign bit to be added // - std::vector, int, RTLIL::Wire *>> ppij_int; - - static int constant_ix; - constant_ix++; - std::string buf_name = "constant_buf_" + std::to_string(constant_ix); - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - RTLIL::Wire *constant_one = module->addWire(new_id(buf_name, __LINE__, ""), 1); - buf->setPort(ID::A, State::S1); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, constant_one); - - constant_ix++; - buf_name = "constant_buf_" + std::to_string(constant_ix); - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - RTLIL::Wire *constant_zero = module->addWire(new_id(buf_name, __LINE__, ""), 1); - buf->setPort(ID::A, State::S0); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, constant_zero); + std::vector> ppij_int; // Row 0: special case 1. Format S/.S.S.C.Data - std::vector ppij_row_0; + SigSpec ppij_row_0; BuildBoothUMultDecoderRow0(module, X, s_int, sb_int, one_int, two_int, ppij_row_0); // data, shift, sign @@ -436,11 +315,11 @@ struct BoothPassWorker { for (int i = 1; i < encoder_count - 2; i++) { // format 1,S.Data.shift = encoder_ix*2,sign = sb_int[i] - std::vector ppij_row_n; + SigSpec ppij_row_n; BuildBoothUMultDecoderRowN(module, X, // multiplicand - one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, constant_one, i, + one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, i, false, // include sign false // include constant ); @@ -450,18 +329,18 @@ struct BoothPassWorker { // Build second to last row // format S/,Data + sign bit - std::vector ppij_row_em1; + SigSpec ppij_row_em1; BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 2], two_int[encoder_count - 2], s_int[encoder_count - 2], - sb_int[encoder_count - 2], ppij_row_em1, constant_one, encoder_count - 2, + sb_int[encoder_count - 2], ppij_row_em1, encoder_count - 2, false, // include sign true // no constant ); ppij_int.push_back(std::make_tuple(ppij_row_em1, (encoder_count - 2) * 2, s_int[encoder_count - 2])); // Build last row // format Data + sign bit - std::vector ppij_row_e; + SigSpec ppij_row_e; BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 1], two_int[encoder_count - 1], s_int[encoder_count - 1], - sb_int[encoder_count - 1], ppij_row_e, constant_one, encoder_count - 1, + sb_int[encoder_count - 1], ppij_row_e, encoder_count - 1, true, // no sign true // no constant ); @@ -471,13 +350,13 @@ struct BoothPassWorker { // DebugDumpPP(ppij_int); // Summation of Partial Products (Wallace Tree) - std::vector> aligned_pp; + std::vector aligned_pp; aligned_pp.resize(encoder_count + 1); // make an entirely redundant row // just for sign bit in lsb. (We then filter this out). // resize all to be same size as z for (int i = 0; i < encoder_count + 1; i++) - aligned_pp[i].resize(z_sz); + aligned_pp[i].extend_u0(z_sz); AlignPP(x_sz, z_sz, ppij_int, aligned_pp); @@ -485,8 +364,8 @@ struct BoothPassWorker { // Later on yosys will clean up unused constants // DebugDumpAlignPP(aligned_pp); - std::vector s_vec; - std::vector c_vec; + SigSpec s_vec; + SigSpec c_vec; std::vector> debug_csa_trees; debug_csa_trees.resize(z_sz); @@ -504,84 +383,59 @@ struct BoothPassWorker { */ void BuildBoothUMultDecoderRow0(RTLIL::Module *module, - RTLIL::Wire *X, // multiplicand - std::vector &s_int, std::vector &sb_int, std::vector &one_int, - std::vector &two_int, std::vector &ppij_vec) + SigSpec X, // multiplicand + SigSpec s_int, SigSpec sb_int, SigSpec one_int, + SigSpec two_int, SigSpec &ppij_vec) { (void)module; int x_sz = GetSize(X); + SigBit ppij; // lsb - std::string dec_name = "row0_lsb_dec"; - - RTLIL::Wire *ppij; - std::string ppij_name = "ppij_0_0"; - BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int[0], s_int[0], ppij, ppij_name); - ppij_vec.push_back(ppij); + ppij_vec.append(Bur4d_lsb("row0_lsb_dec", X[0], one_int[0], s_int[0])); // 1..xsize -1 - for (int i = 1; i < x_sz; i++) { - dec_name = "row0_dec_" + std::to_string(i); - RTLIL::Wire *ppij; - BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int[0], two_int[0], - s_int[0], ppij); - ppij_vec.push_back(ppij); - } + for (int i = 1; i < x_sz; i++) + ppij_vec.append(Bur4d_n(stringf("row0_dec_%d", i), X[i], X[i - 1], + one_int[0], two_int[0], s_int[0])); // The redundant bit. Duplicate decoding of last bit. - dec_name = "row0_dec_msb"; - BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int[0], s_int[0], ppij); - ppij_vec.push_back(ppij); + ppij_vec.append(Bur4d_msb("row0_dec_msb", X[x_sz - 1], two_int[0], s_int[0])); // append the sign bits - ppij_vec.push_back(s_int[0]); - ppij_vec.push_back(s_int[0]); - ppij_vec.push_back(sb_int[0]); + ppij_vec.append(s_int[0]); + ppij_vec.append(s_int[0]); + ppij_vec.append(sb_int[0]); } // Build a generic row of decoders. void BuildBoothUMultDecoderRowN(RTLIL::Module *module, - RTLIL::Wire *X, // multiplicand - RTLIL::Wire *one_int, RTLIL::Wire *two_int, RTLIL::Wire *s_int, RTLIL::Wire *sb_int, - std::vector &ppij_vec, RTLIL::Wire *constant_one, int row_ix, bool no_sign, bool no_constant) + SigSpec X, // multiplicand + SigSpec one_int, SigSpec two_int, SigSpec s_int, SigSpec sb_int, + SigSpec &ppij_vec, int row_ix, bool no_sign, bool no_constant) { (void)module; int x_sz = GetSize(X); // lsb - std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; - RTLIL::Wire *ppij = nullptr; - std::string empty; - std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec"; - BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int, s_int, ppij, empty); - - ppij_vec.push_back(ppij); + ppij_vec.append(Bur4d_lsb(stringf("row_%d_lsb_dec", row_ix), X[0], one_int, s_int)); // core bits - for (int i = 1; i < x_sz; i++) { - - dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); - RTLIL::Wire *ppij = nullptr; - BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int, two_int, - s_int, ppij); - ppij_vec.push_back(ppij); - } + for (int i = 1; i < x_sz; i++) + ppij_vec.append(Bur4d_n(stringf("row_%d_dec_%d", row_ix, i), X[i], X[i - 1], + one_int, two_int, s_int)); // redundant bit - - dec_name = "row_dec_red"; - BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int, s_int, ppij); - ppij_vec.push_back(ppij); + ppij_vec.append(Bur4d_msb("row_dec_red", X[x_sz - 1], two_int, s_int)); // sign bit - if (no_sign == false) // if no sign is false then make a sign bit - ppij_vec.push_back(sb_int); + if (!no_sign) // if no sign is false then make a sign bit + ppij_vec.append(sb_int); // constant bit - if (no_constant == false) { // if non constant is false make a constant bit - ppij_vec.push_back(constant_one); - } + if (!no_constant) // if non constant is false make a constant bit + ppij_vec.append(State::S1); } void DebugDumpAlignPP(std::vector> &aligned_pp) @@ -663,8 +517,8 @@ struct BoothPassWorker { } } - void BuildCSATree(RTLIL::Module *module, std::vector> &bits_to_reduce, std::vector &s_vec, - std::vector &c_vec, std::vector> &debug_csa_trees) + void BuildCSATree(RTLIL::Module *module, std::vector &bits_to_reduce, SigSpec &s_vec, + SigSpec &c_vec, std::vector> &debug_csa_trees) { if (!(bits_to_reduce.size() > 0)) @@ -672,24 +526,24 @@ struct BoothPassWorker { int column_size = bits_to_reduce[0].size(); int row_size = bits_to_reduce.size(); - std::vector carry_bits_to_add_to_next_column; + SigSpec carry_bits_to_add_to_next_column; for (int column_ix = 0; column_ix < column_size; column_ix++) { // get the bits in this column. - std::vector column_bits; + SigSpec column_bits; for (int row_ix = 0; row_ix < row_size; row_ix++) { - if (bits_to_reduce[row_ix].at(column_ix)) - column_bits.push_back(bits_to_reduce[row_ix].at(column_ix)); + if (bits_to_reduce[row_ix][column_ix].wire) + column_bits.append(bits_to_reduce[row_ix][column_ix]); } for (auto c : carry_bits_to_add_to_next_column) { #ifdef DEBUG_CSA printf("\t Propagating column bit %s to column %d from column %d\n", c->name.c_str(), column_ix, column_ix - 1); #endif - column_bits.push_back(c); + column_bits.append(c); } - carry_bits_to_add_to_next_column.resize(0); + carry_bits_to_add_to_next_column = {}; #ifdef DEBUG_CSA printf("Column %d Reducing %d bits\n", column_ix, column_bits.size()); @@ -699,16 +553,15 @@ struct BoothPassWorker { printf("\n"); #endif - RTLIL::Wire *s = nullptr; - RTLIL::Wire *c = nullptr; + SigBit s, c; #ifdef DEBUG_CSA int csa_count_before = debug_csa_trees[column_ix].size(); #endif ReduceBits(module, column_ix, column_bits, s, c, carry_bits_to_add_to_next_column, debug_csa_trees); - s_vec.push_back(s); - c_vec.push_back(c); + s_vec.append(s); + c_vec.append(c); #ifdef DEBUG_CSA int csa_count_after = debug_csa_trees[column_ix].size(); @@ -738,8 +591,8 @@ struct BoothPassWorker { Pad out rows with zeros and left the opt pass clean them up. */ - void AlignPP(int x_sz, int z_sz, std::vector, int, RTLIL::Wire *>> &ppij_int, - std::vector> &aligned_pp) + void AlignPP(int x_sz, int z_sz, std::vector> &ppij_int, + std::vector &aligned_pp) { unsigned aligned_pp_ix = aligned_pp.size() - 1; @@ -748,7 +601,7 @@ struct BoothPassWorker { for (unsigned i = 0; i < aligned_pp.size(); i++) { for (int j = 0; j < z_sz; j++) { - aligned_pp[i][j] = nullptr; + aligned_pp[i][j] = State::S0; } } @@ -758,21 +611,19 @@ struct BoothPassWorker { // in first column of the last partial product // which is at index corresponding to size of multiplicand { - RTLIL::Wire *prior_row_sign = nullptr; - prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); - if (prior_row_sign) { + SigBit prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); + //if (prior_row_sign) { log_assert(aligned_pp_ix < aligned_pp.size()); log_assert(x_sz - 1 < (int)(aligned_pp[aligned_pp_ix].size())); aligned_pp[aligned_pp_ix][x_sz - 1] = prior_row_sign; - } + //} } for (int row_ix = aligned_pp_ix - 1; row_ix >= 0; row_ix--) { int shift_amount = get<1>(ppij_int[row_ix]); - RTLIL::Wire *prior_row_sign = nullptr; // copy in data - unsigned copy_ix = shift_amount; + int copy_ix = shift_amount; for (auto w : get<0>(ppij_int[row_ix])) { if (copy_ix < aligned_pp[row_ix].size()) { aligned_pp[row_ix][copy_ix] = w; @@ -786,7 +637,7 @@ struct BoothPassWorker { // the destination of the sign bit is the (row_ix -1)*2 // eg destination for sign bit for row 0 is 0. // eg destination for sign bit for row 1 is 1 - prior_row_sign = get<2>(ppij_int[row_ix - 1]); + SigBit prior_row_sign = get<2>(ppij_int[row_ix - 1]); copy_ix = (row_ix - 1) * 2; aligned_pp[row_ix][copy_ix] = prior_row_sign; } @@ -797,32 +648,22 @@ struct BoothPassWorker { Build a Carry Propagate Adder ----------------------------- First build the sum and carry vectors to be added. - Axioms: - c_vec.size() == s_vec.size() - result.size() == s_vec.size() + 2; (assume result is reserved to hold correct size) */ - void BuildCPA(RTLIL::Module *module, std::vector &s_vec, std::vector &c_vec, RTLIL::Wire *result) + void BuildCPA(RTLIL::Module *module, SigSpec s_vec, SigSpec c_vec, SigSpec result) { - static int cpa_id; cpa_id++; - RTLIL::Wire *carry = nullptr; - - log_assert(s_vec.size() == c_vec.size()); + log_assert(c_vec.size() == s_vec.size()); + log_assert(result.size() == s_vec.size()); - for (unsigned n = 0; n < s_vec.size(); n++) { + SigBit carry; + for (int n = 0; n < s_vec.size(); n++) { std::string carry_name; // Base Case: Bit 0 is sum 0 if (n == 0) { - std::string buf_name = "base_buf_" + std::to_string(cpa_id) + "_" + std::to_string(n); - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, s_vec[0]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, false); - buf->setPort(ID::Y, SigSpec(result, 0, 1)); + module->addBufGate(NEW_ID_SUFFIX(stringf("base_buf_%d_%d", cpa_id, n)), s_vec[0], result[0]); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IP 0 %s \n", n, buf->name.c_str(), s_vec[0]->name.c_str()); @@ -835,10 +676,9 @@ struct BoothPassWorker { // else if (n == 1) { std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); - RTLIL::Wire *ha_op; + SigBit ha_op; BuildHa(ha_name, s_vec[n], c_vec[n - 1], ha_op, carry); - - module->connect(ha_op, SigSpec(result, n, 1)); + module->connect(result[n], ha_op); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] \n", n, ha_cell->name.c_str(), s_vec[n]->name.c_str(), @@ -847,54 +687,45 @@ struct BoothPassWorker { } // End Case - else if (n == (unsigned)((s_vec.size() - 1))) { + else if (n == s_vec.size() - 1) { // Make the carry results.. Two extra bits after fa. - std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); - auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); - fa_cell->setParam(ID::WIDTH, 1); - carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); - fa_cell->setPort(ID::A, s_vec[n]); - fa_cell->setPort(ID::B, c_vec[n - 1]); - fa_cell->setPort(ID::C, carry); - // wire in result and carry out - fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); - - // make a new carry bit for carry out... - carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); - fa_cell->setPort(ID::X, carry); + SigBit carry_out = module->addWire(NEW_ID, 1); + module->addFa(NEW_ID_SUFFIX(stringf("cpa_%d_fa_%d", cpa_id, n)), + /* A */ s_vec[n], + /* B */ c_vec[n - 1], + /* C */ carry, + /* X */ carry_out, + /* Y */ result[n] + ); + carry = carry_out; #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), c_vec[n - 1]->name.c_str(), carry->name.c_str()); #endif - if (n + 1 < (unsigned)(GetSize(result))) { + if (n + 1 < GetSize(result)) { // Now make a half adder: c_vec[n] = carry std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); - RTLIL::Wire *ha_sum; - RTLIL::Wire *ha_carry; + SigBit ha_sum; + SigBit ha_carry; BuildHa(ha_name, c_vec[n], carry, ha_sum, ha_carry); - if (n + 1 < (unsigned)GetSize(result)) - module->connect(ha_sum, SigSpec(result, n + 1, 1)); - if (n + 2 < (unsigned)GetSize(result)) - module->connect(ha_carry, SigSpec(result, n + 2, 1)); + if (n + 1 < GetSize(result)) + module->connect(result[n + 1], ha_sum); + if (n + 2 < GetSize(result)) + module->connect(result[n + 2], ha_carry); } } // Step case else { - std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); - auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); - fa_cell->setParam(ID::WIDTH, 1); - - carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); - fa_cell->setPort(ID::A, s_vec[n]); - fa_cell->setPort(ID::B, c_vec[n - 1]); - fa_cell->setPort(ID::C, carry); - // wire in result and carry out - fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); - // make a new carry bit for carry out... - carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); - fa_cell->setPort(ID::X, carry); - + SigBit carry_out = module->addWire(NEW_ID_SUFFIX(stringf("cpa_%d_carry_%d", cpa_id, n)), 1); + module->addFa(NEW_ID_SUFFIX(stringf("cpa_%d_fa_%d", cpa_id, n)), + /* A */ s_vec[n], + /* B */ c_vec[n - 1], + /* C */ carry, + /* X */ carry_out, + /* Y */ result[n] + ); + carry = carry_out; #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), c_vec[n - 1]->name.c_str(), carry->name.c_str()); @@ -907,99 +738,72 @@ struct BoothPassWorker { // Pass the carry bits from each csa to the next // column for summation. - void ReduceBits(RTLIL::Module *module, int column_ix, std::vector &column_bits, RTLIL::Wire *&s_result, RTLIL::Wire *&c_result, - std::vector &carry_bits_to_sum, std::vector> &debug_csa_trees) + void ReduceBits(RTLIL::Module *module, int column_ix, SigSpec column_bits, SigBit &s_result, SigBit &c_result, + SigSpec &carry_bits_to_sum, std::vector> &debug_csa_trees) { int csa_ix = 0; int column_size = column_bits.size(); - static int unique_id = 0; - - unique_id++; if (column_size > 0) { - unsigned var_ix = 0; - std::vector first_csa_ips; + int var_ix = 0; + SigSpec first_csa_ips; // get the first 3 inputs, if possible for (var_ix = 0; var_ix < column_bits.size() && first_csa_ips.size() != 3; var_ix++) { - if (column_bits[var_ix]) - first_csa_ips.push_back(column_bits[var_ix]); + if (column_bits[var_ix].is_wire()) + first_csa_ips.append(column_bits[var_ix]); } if (first_csa_ips.size() > 0) { // build the first csa - std::string csa_name = - "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_" + std::to_string(unique_id) + "_"; - auto csa = module->addCell(NEW_ID, - // new_id(csa_name, - // __LINE__, - // ""), - ID($fa)); - csa->setParam(ID::WIDTH, 1); - debug_csa_trees[column_ix].push_back(csa); - csa_ix++; - - csa->setPort(ID::A, first_csa_ips[0]); + auto s_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_s", column_ix, csa_ix + 1)), 1); + auto c_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_c", column_ix, csa_ix + 1)), 1); - if (first_csa_ips.size() > 1) - csa->setPort(ID::B, first_csa_ips[1]); - else - csa->setPort(ID::B, State::S0); - - if (first_csa_ips.size() > 2) - csa->setPort(ID::C, first_csa_ips[2]); - else - csa->setPort(ID::C, State::S0); + auto csa = module->addFa(NEW_ID_SUFFIX(stringf("csa_%d_%d", column_ix, csa_ix)), + /* A */ first_csa_ips[0], + /* B */ first_csa_ips.size() > 1 ? first_csa_ips[1] : State::S0, + /* C */ first_csa_ips.size() > 2 ? first_csa_ips[2] : State::S0, + /* X */ c_wire, + /* Y */ s_wire + ); - std::string sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; - auto s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); - csa->setPort(ID::Y, s_wire); s_result = s_wire; - std::string carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; - auto c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); - csa->setPort(ID::X, c_wire); c_result = c_wire; + debug_csa_trees[column_ix].push_back(csa); + csa_ix++; + if (var_ix <= column_bits.size() - 1) - carry_bits_to_sum.push_back(c_wire); + carry_bits_to_sum.append(c_wire); // Now build the rest of the tree if we can while (var_ix <= column_bits.size() - 1) { - std::vector csa_ips; + SigSpec csa_ips; // get the next two variables to sum for (; var_ix <= column_bits.size() - 1 && csa_ips.size() < 2;) { // skip any empty bits - if (column_bits[var_ix] != nullptr) - csa_ips.push_back(column_bits[var_ix]); + if (column_bits[var_ix].is_wire()) + csa_ips.append(column_bits[var_ix]); var_ix++; } if (csa_ips.size() > 0) { - csa_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix); - auto csa = module->addCell(new_id(csa_name, __LINE__, ""), ID($fa)); - csa->setParam(ID::WIDTH, 1); - debug_csa_trees[column_ix].push_back(csa); + auto c_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_c", column_ix, csa_ix + 1)), 1); + auto s_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_s", column_ix, csa_ix + 1)), 1); + + auto csa = module->addFa(NEW_ID_SUFFIX(stringf("csa_%d_%d", column_ix, csa_ix)), + /* A */ s_result, + /* B */ csa_ips[0], + /* C */ csa_ips.size() > 1 ? csa_ips[1] : State::S0, + /* X */ c_wire, + /* Y */ s_wire + ); + debug_csa_trees[column_ix].push_back(csa); csa_ix++; - // prior level - csa->setPort(ID::A, s_wire); - csa->setPort(ID::B, csa_ips[0]); - if (csa_ips.size() > 1) - csa->setPort(ID::C, csa_ips[1]); - else - csa->setPort(ID::C, State::S0); - - carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; - c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); if (var_ix <= column_bits.size() - 1) - carry_bits_to_sum.push_back(c_wire); - - sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; - s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); - - csa->setPort(ID::X, c_wire); - csa->setPort(ID::Y, s_wire); + carry_bits_to_sum.append(c_wire); s_result = s_wire; c_result = c_wire; @@ -1009,28 +813,22 @@ struct BoothPassWorker { } } - void BuildBoothUMultEncoders(RTLIL::Wire *Y, int y_sz, std::vector &one_int, std::vector &two_int, - std::vector &s_int, std::vector &sb_int, RTLIL::Module *module, int &encoder_ix) + void BuildBoothUMultEncoders(SigSpec Y, SigSpec &one_int, SigSpec &two_int, + SigSpec &s_int, SigSpec &sb_int, RTLIL::Module *module, int &encoder_ix) { - for (int y_ix = 0; y_ix < y_sz;) { - std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; + int y_sz = GetSize(Y); - std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); - - std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.push_back(module->addWire(new_id(one_name, __LINE__, ""), 1)); - - std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + for (int y_ix = 0; y_ix < y_sz;) { + std::string enc_name = stringf("bur_enc_%d", encoder_ix); - std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); + one_int.append(module->addWire(NEW_ID_SUFFIX(stringf("one_int_%d", encoder_ix)), 1)); + s_int.append(module->addWire(NEW_ID_SUFFIX(stringf("s_int_%d", encoder_ix)), 1)); + sb_int.append(module->addWire(NEW_ID_SUFFIX(stringf("sb_int_%d", encoder_ix)), 1)); if (y_ix == 0) { - - BuildBur4e(enc_name, mk_wireFromSigSpec(State::S0), mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), - mk_wireFromSigSpec(SigSpec(Y, y_ix + 1, 1)), one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + BuildBur4e(enc_name, State::S0, Y[y_ix], + Y[y_ix + 1], one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); y_ix = y_ix + 1; @@ -1041,71 +839,61 @@ struct BoothPassWorker { // then add an extra booth encoder bounded by // zeroes to ensure unsigned works. // - RTLIL::Wire *y0_wire; - RTLIL::Wire *y1_wire; - RTLIL::Wire *y2_wire; + SigBit y0, y1, y2; bool need_padded_cell = false; if (y_ix > y_sz - 1) { - y0_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y0 = State::S0; need_padded_cell = false; } else { - y0_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y0 = Y[y_ix]; y_ix++; } if (y_ix > y_sz - 1) { need_padded_cell = false; - y1_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y1 = State::S0; } else { - y1_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y1 = Y[y_ix]; y_ix++; } if (y_ix > y_sz - 1) { need_padded_cell = false; - y2_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y2 = State::S0; } else { if (y_ix == y_sz - 1) need_padded_cell = true; else need_padded_cell = false; - y2_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y2 = Y[y_ix]; - BuildBur4e(enc_name, y0_wire, y1_wire, y2_wire, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + BuildBur4e(enc_name, y0, y1, y2, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); } encoder_ix++; if (need_padded_cell == true) { - // make extra encoder cell // y_ix at y0, rest 0 - std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; - - std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); - - std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + std::string enc_name = stringf("br_enc_pad_%d", encoder_ix); - std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); + one_int.append(module->addWire(NEW_ID_SUFFIX(stringf("one_int_%d", encoder_ix)), 1)); + s_int.append(module->addWire(NEW_ID_SUFFIX(stringf("s_int_%d", encoder_ix)), 1)); + sb_int.append(module->addWire(NEW_ID_SUFFIX(stringf("sb_int_%d", encoder_ix)), 1)); - std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + SigBit one_o_int, two_o_int, s_o_int, sb_o_int; + BuildBur4e(enc_name, Y[y_ix], State::S0, + State::S0, one_o_int, two_o_int, s_o_int, sb_o_int); - RTLIL::Wire *one_o_int, *two_o_int, *s_o_int, *sb_o_int; - BuildBur4e(enc_name, mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), mk_wireFromSigSpec(State::S0), - mk_wireFromSigSpec(State::S0), one_o_int, two_o_int, s_o_int, sb_o_int); - - join_wires_with_buffer(one_o_int, one_int[encoder_ix]); - join_wires_with_buffer(two_o_int, two_int[encoder_ix]); - join_wires_with_buffer(s_o_int, s_int[encoder_ix]); - join_wires_with_buffer(sb_o_int, sb_int[encoder_ix]); + module->connect(one_int[encoder_ix], one_o_int); + module->connect(two_int[encoder_ix], two_o_int); + module->connect(s_int[encoder_ix], s_o_int); + module->connect(sb_int[encoder_ix], sb_o_int); y_ix++; encoder_ix++; } @@ -1116,87 +904,76 @@ struct BoothPassWorker { /* Signed Multiplier */ - void CreateBoothSMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, RTLIL::Wire *X, RTLIL::Wire *Y, RTLIL::Wire *Z) + void CreateBoothSMult(RTLIL::Module *module, SigSpec X, SigSpec Y, SigSpec Z) { // product + int x_sz = X.size(), y_sz = Y.size(), z_sz = Z.size(); + unsigned enc_count = (y_sz / 2) + (((y_sz % 2) != 0) ? 1 : 0); int dec_count = x_sz + 1; int fa_count = x_sz + 4; int fa_row_count = enc_count - 1; - log("Signed multiplier generator using low Power Negative First Booth Algorithm. Multiplicand of size %d Multiplier of size %d. " - "Result of size %d. %d encoders %d decoders\n", - x_sz, y_sz, z_sz, enc_count, dec_count); + log_debug("Mapping %d x %d -> %d multiplier: %d encoders %d decoders\n", x_sz, y_sz, z_sz, enc_count, dec_count); - RTLIL::Wire **negi_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **twoi_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **onei_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **cori_n_int = new RTLIL::Wire *[enc_count]; + SigSpec negi_n_int, twoi_n_int, onei_n_int, cori_n_int; + + negi_n_int.extend_u0(enc_count); + twoi_n_int.extend_u0(enc_count); + onei_n_int.extend_u0(enc_count); + cori_n_int.extend_u0(enc_count); for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { - std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; - std::string negi_name = "negi_n_int" + std::to_string(encoder_ix) + "_"; - negi_n_int[encoder_ix - 1] = module->addWire(new_id(negi_name, __LINE__, ""), 1); - std::string twoi_name = "twoi_n_int_" + std::to_string(encoder_ix) + "_"; - twoi_n_int[encoder_ix - 1] = module->addWire(new_id(twoi_name, __LINE__, ""), 1); - std::string onei_name = "onei_n_int_" + std::to_string(encoder_ix) + "_"; - onei_n_int[encoder_ix - 1] = module->addWire(new_id(onei_name, __LINE__, ""), 1); - std::string cori_name = "cori_n_int_" + std::to_string(encoder_ix) + "_"; - cori_n_int[encoder_ix - 1] = module->addWire(new_id(cori_name, __LINE__, ""), 1); + std::string enc_name = stringf("enc_%d", encoder_ix); + negi_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("negi_n_int_%d", encoder_ix)), 1); + twoi_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("twoi_n_int_%d", encoder_ix)), 1); + onei_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("onei_n_int_%d", encoder_ix)), 1); + cori_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("cori_n_int_%d", encoder_ix)), 1); if (encoder_ix == 1) { - - BuildBr4e(enc_name, mk_wireFromSigSpec(SigSpec(State::S0)), mk_wireFromSigSpec(SigSpec(Y, 0, 1)), - mk_wireFromSigSpec(SigSpec(Y, 1, 1)), - + BuildBr4e(enc_name, State::S0, Y[0], Y[1], negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); } else { - RTLIL::Wire *y1_wire; - RTLIL::Wire *y2_wire; - RTLIL::Wire *y3_wire; + SigBit y1, y2, y3; + + y1 = Y[(encoder_ix - 1) * 2 - 1]; - y1_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 - 1), 1)); //-1 if ((encoder_ix - 1) * 2 >= (unsigned)y_sz) - y2_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + y2 = State::S0; // constant 0 else - y2_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2), 1)); // 0 + y2 = Y[(encoder_ix - 1) * 2]; // 0 if (((encoder_ix - 1) * 2 + 1) >= (unsigned)y_sz) - y3_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + y3 = State::S0; // constant 0 else - y3_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 + 1), 1)); //+1 - - BuildBr4e(enc_name, y1_wire, y2_wire, y3_wire, + y3 = Y[(encoder_ix - 1) * 2 + 1]; //+1 + BuildBr4e(enc_name, y1, y2, y3, negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); } } // Decoders and PP generation - RTLIL::Wire **PPij = new RTLIL::Wire *[enc_count * dec_count]; - RTLIL::Wire **nxj = new RTLIL::Wire *[enc_count * dec_count]; + SigSpec PPij(State::S0, enc_count * dec_count); + SigSpec nxj(State::S0, enc_count * dec_count); for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { - std::string ppij_name = "ppij_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(ppij_name, __LINE__, ""), 1); - std::string nxj_name; - if (decoder_ix == 1) - nxj_name = "nxj_pre_dec" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - else - nxj_name = "nxj_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = + module->addWire(NEW_ID_SUFFIX(stringf("ppij_%d_%d", encoder_ix, decoder_ix)), 1); - nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(nxj_name, __LINE__, ""), 1); + nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = + module->addWire(NEW_ID_SUFFIX(stringf("nxj_%s%d_%d", decoder_ix == 1 ? "pre_dec_" : "", + encoder_ix, decoder_ix)), 1); } } // // build decoder array // - for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { // pre-decoder std::string pre_dec_name = "pre_dec_" + std::to_string(encoder_ix) + "_"; @@ -1204,10 +981,10 @@ struct BoothPassWorker { if (encoder_ix == 1) { // quadrant 1 optimization } else { - auto cell = module->addCell(new_id(pre_dec_name, __LINE__, ""), ID($_NOT_)); - cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - cell->setPort(ID::A, negi_n_int[encoder_ix - 1]); - cell->setPort(ID::Y, nxj[(encoder_ix - 1) * dec_count]); + module->addNotGate(NEW_ID_SUFFIX(stringf("pre_dec_%d", encoder_ix)), + negi_n_int[encoder_ix - 1], + nxj[(encoder_ix - 1) * dec_count] + ); } for (int decoder_ix = 1; decoder_ix < dec_count; decoder_ix++) { @@ -1217,19 +994,18 @@ struct BoothPassWorker { if ((decoder_ix == 1 || decoder_ix == 2) && encoder_ix == 1) continue; - std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - + std::string dec_name = stringf("dec_%d_%d", encoder_ix, decoder_ix); BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1], twoi_n_int[encoder_ix - 1], - mk_wireFromSigSpec(SigSpec(X, decoder_ix - 1, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + X[decoder_ix - 1], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1], nxj[((encoder_ix - 1) * dec_count) + decoder_ix]); } // duplicate end for sign fix // applies to 9th decoder (xsz+1 decoder). - std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; - RTLIL::Wire *unused_op = nullptr; + std::string dec_name = stringf("dec_%d_%d", encoder_ix, x_sz + 1); + SigBit unused_op; BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + dec_count - 1], twoi_n_int[encoder_ix - 1], - mk_wireFromSigSpec(SigSpec(X, dec_count - 2, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + X[dec_count - 2], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + dec_count - 1], unused_op); } @@ -1239,16 +1015,15 @@ struct BoothPassWorker { int fa_el_ix = 0; int fa_row_ix = 0; // use 1 d arrays (2d cannot have variable sized indices) - RTLIL::Wire **fa_sum_n = new RTLIL::Wire *[fa_row_count * fa_count]; - RTLIL::Wire **fa_carry_n = new RTLIL::Wire *[fa_row_count * fa_count]; + SigSpec fa_sum_n(State::S0, fa_row_count * fa_count); + SigSpec fa_carry_n(State::S0, fa_row_count * fa_count); for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { - - std::string fa_sum_name = "fa_sum_n_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_sum_name, __LINE__, ""), 1); - std::string fa_carry_name = "fa_carry_n" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_carry_name, __LINE__, ""), 1); + fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = + module->addWire(NEW_ID_SUFFIX(stringf("fa_sum_n_%d_%d", fa_row_ix, fa_el_ix)), 1); + fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = + module->addWire(NEW_ID_SUFFIX(stringf("fa_carry_n_%d_%d", fa_row_ix, fa_el_ix)), 1); } } @@ -1271,67 +1046,52 @@ struct BoothPassWorker { // step case else if (fa_el_ix >= 2 && fa_el_ix <= x_sz) { // middle (2...x_sz cells) - bfa_name = "bfa_0_step_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, PPij[(0 * dec_count) + fa_el_ix]); - cell->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_step_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ PPij[(0 * dec_count) + fa_el_ix], + /* B */ PPij[(1 * dec_count) + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } // end 3 cells: x_sz+1.2.3 // else { // fa_el_ix = x_sz+1 - bfa_name = "bfa_0_se_0" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, PPij[(0 * dec_count) + x_sz]); - cell1->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); - cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_0_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ PPij[(0 * dec_count) + x_sz], + /* B */ PPij[(1 * dec_count) + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); // exception:invert ppi fa_el_ix++; - exc_inv_name = "bfa_0_exc_inv1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cellinv1 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv1->add_strpool_attribute(ID::src, cellinv1->get_strpool_attribute(ID::src)); - - RTLIL::Wire *d08_inv = module->addWire(NEW_ID, 1); - - cellinv1->setPort(ID::A, PPij[(0 * dec_count) + dec_count - 1]); - cellinv1->setPort(ID::Y, d08_inv); - - exc_inv_name = "bfa_0_exc_inv2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - - auto cellinv2 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv2->add_strpool_attribute(ID::src, cellinv2->get_strpool_attribute(ID::src)); - RTLIL::Wire *d18_inv = module->addWire(NEW_ID, 1); - cellinv2->setPort(ID::A, PPij[(1 * dec_count) + dec_count - 1]); - cellinv2->setPort(ID::Y, d18_inv); - - bfa_name = "bfa_0_se_1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, d08_inv); - cell2->setPort(ID::B, d18_inv); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + SigBit d08_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_0_exc_inv1_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[(0 * dec_count) + dec_count - 1]); + + SigBit d18_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_0_exc_inv2_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[(1 * dec_count) + dec_count - 1]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_1_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ d08_inv, + /* B */ d18_inv, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); // sign extension fa_el_ix++; - bfa_name = "bfa_0_se_2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell3 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell3->setParam(ID::WIDTH, 1); - cell3->setPort(ID::A, State::S0); - cell3->setPort(ID::B, State::S1); - cell3->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell3->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell3->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_2_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ State::S0, + /* B */ State::S1, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } } @@ -1342,89 +1102,71 @@ struct BoothPassWorker { if (fa_el_ix == 0) { // first two cells: have B input hooked to 0. // column is offset by row_ix*2 - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + 2]); // from prior full adder row - cell1->setPort(ID::B, State::S0); - cell1->setPort(ID::C, cori_n_int[fa_row_ix]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_base_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + 2], + /* B */ State::S0, + /* C */ cori_n_int[fa_row_ix], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); fa_el_ix++; - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, - fa_sum_n[(fa_row_ix - 1) * fa_count + 3]); // from prior full adder row - cell2->setPort(ID::B, State::S0); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_base_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + 3], // from prior full adder row + /* B */ State::S0, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); + } else if (fa_el_ix >= 2 && fa_el_ix <= x_sz + 1) { // middle (2...x_sz+1 cells) - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_step_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2]); - cell->setPort(ID::B, PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_step_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2], + /* B */ PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } else if (fa_el_ix > x_sz + 1) { // end two bits: sign extension - std::string se_inv_name; - se_inv_name = "bfa_" + std::to_string(fa_row_ix) + "_se_inv_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cellinv = module->addCell(new_id(se_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv->add_strpool_attribute(ID::src, cellinv->get_strpool_attribute(ID::src)); - RTLIL::Wire *d_inv = module->addWire(NEW_ID, 1); - cellinv->setPort(ID::A, PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); - cellinv->setPort(ID::Y, d_inv); - - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1]); - cell1->setPort(ID::B, d_inv); - cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + SigBit d_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_se_inv_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_se_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1], + /* B */ d_inv, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); fa_el_ix++; // sign extension - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, State::S0); - cell2->setPort(ID::B, State::S1); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_se_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ State::S0, + /* B */ State::S1, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } } } } // instantiate the cpa - RTLIL::Wire **cpa_carry = new RTLIL::Wire *[z_sz]; + SigSpec cpa_carry; - for (int cix = 0; cix < z_sz; cix++) { - std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; - cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); - } + for (int cix = 0; cix < z_sz; cix++) + cpa_carry.append(module->addWire(NEW_ID_SUFFIX(stringf("cpa_carry_%d", cix)), 1)); for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { - // The end case where we pass the last two summands // from prior row directly to product output // without using a cpa cell. This is always @@ -1432,38 +1174,27 @@ struct BoothPassWorker { if (cpa_ix <= fa_row_count * 2 - 1) { int fa_row_ix = cpa_ix / 2; - std::string buf_name = - "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 0]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + module->addBufGate(NEW_ID_SUFFIX(stringf("pp_buf_%d_driven_by_fa_row_%d", cpa_ix, fa_row_ix)), + fa_sum_n[(fa_row_ix * fa_count) + 0], Z[cpa_ix]); cpa_ix++; - buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 1]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + module->addBufGate(NEW_ID_SUFFIX(stringf("pp_buf_%d_driven_by_fa_row_%d", cpa_ix, fa_row_ix)), + fa_sum_n[(fa_row_ix * fa_count) + 1], Z[cpa_ix]); } else { int offset = fa_row_count * 2; bool base_case = cpa_ix - offset == 0 ? true : false; - std::string cpa_name = "cpa_" + std::to_string(cpa_ix - offset) + "_"; + std::string cpa_name = stringf("cpa_%d", cpa_ix - offset); - RTLIL::Wire *ci_wire; + SigBit ci; if (base_case) - ci_wire = cori_n_int[enc_count - 1]; + ci = cori_n_int[enc_count - 1]; else - ci_wire = cpa_carry[cpa_ix - offset - 1]; + ci = cpa_carry[cpa_ix - offset - 1]; - RTLIL::Wire *op_wire = module->addWire(NEW_ID, 1); - BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci_wire, op_wire, + SigBit op; + BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci, op, cpa_carry[cpa_ix - offset]); - module->connect(op_wire, SigSpec(Z, cpa_ix, 1)); + module->connect(Z[cpa_ix], op); } } @@ -1473,51 +1204,72 @@ struct BoothPassWorker { // std::string q1_name = "icb_booth_q1_"; - RTLIL::Wire *pp0_o_int; - RTLIL::Wire *pp1_o_int; - RTLIL::Wire *nxj_o_int; - RTLIL::Wire *cor_o_int; + SigBit pp0_o_int; + SigBit pp1_o_int; + SigBit nxj_o_int; + SigBit cor_o_int; BuildBoothQ1(q1_name, negi_n_int[0], // negi cori_n_int[0], // cori - mk_wireFromSigSpec(SigSpec(X, 0, 1)), // x0 - mk_wireFromSigSpec(SigSpec(X, 1, 1)), // x1 - mk_wireFromSigSpec(SigSpec(Y, 0, 1)), // y0 - mk_wireFromSigSpec(SigSpec(Y, 1, 1)), // y1 + X[0], X[1], Y[0], Y[1], nxj_o_int, cor_o_int, pp0_o_int, pp1_o_int); - join_wires_with_buffer(pp0_o_int, fa_sum_n[(0 * fa_count) + 0]); - join_wires_with_buffer(pp1_o_int, fa_sum_n[(0 * fa_count) + 1]); - join_wires_with_buffer(cor_o_int, fa_carry_n[(0 * fa_count) + 1]); - join_wires_with_buffer(nxj_o_int, nxj[(0 * dec_count) + 2]); - - delete[] negi_n_int; - delete[] twoi_n_int; - delete[] onei_n_int; - delete[] cori_n_int; - - delete[] fa_sum_n; - delete[] fa_carry_n; - delete[] cpa_carry; + module->connect(fa_sum_n[(0 * fa_count) + 0], pp0_o_int); + module->connect(fa_sum_n[(0 * fa_count) + 1], pp1_o_int); + module->connect(fa_carry_n[(0 * fa_count) + 1], cor_o_int); + module->connect(nxj[(0 * dec_count) + 2], nxj_o_int); } }; struct BoothPass : public Pass { - BoothPass() : Pass("booth", "Map $mul to booth multipliers") {} + BoothPass() : Pass("booth", "map $mul cells to Booth multipliers") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" booth [selection]\n"); + log("\n"); + log("This pass replaces multiplier cells with an implementation based on the Booth\n"); + log("algorithm. It operates on $mul cells whose width of operands is at least 4x4\n"); + log("and whose width of result is at least 8. The detailed architecture is selected\n"); + log("from two options based on the signedness of the operands to the $mul cell.\n"); + log("\n"); + log("See the references below for the description of the architectures.\n"); + log("\n"); + log("Signed-multiplier architecture:\n"); + log("Y. J. Chang, Y. C. Cheng, S. C. Liao and C. H. Hsiao, \"A Low Power Radix-4 Booth\n"); + log("Multiplier With Pre-Encoded Mechanism,\" in IEEE Access, vol. 8, pp. 114842-114853,\n"); + log("2020, doi: 10.1109/ACCESS.2020.3003684\n"); + log("\n"); + log("Unsigned-multiplier architecture:\n"); + log("G. W. Bewick, \"Fast Multiplication: Algorithms and Implementations,\" PhD Thesis,\n"); + log("Department of Electrical Engineering, Stanford University, 1994\n"); + log("\n"); + } void execute(vector args, RTLIL::Design *design) override { - (void)args; - log_header(design, - "Executing booth pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); - for (auto mod : design->selected_modules()) + log_header(design, "Executing BOOTH pass (map to Booth multipliers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + int total = 0; + + for (auto mod : design->selected_modules()) { if (!mod->has_processes_warn()) { BoothPassWorker worker(mod); worker.run(); - log_header(design, "Created %d booth multipliers.\n", worker.booth_counter); + total += worker.booth_counter; } + } + + log("Mapped %d multipliers.\n", total); } } MultPass; diff --git a/tests/techmap/booth.ys b/tests/techmap/booth.ys index f1dce1f3b27..ab7efc7b7fd 100644 --- a/tests/techmap/booth.ys +++ b/tests/techmap/booth.ys @@ -1 +1 @@ -test_cell -s 1694091355 -n 1000 -script booth_map_script.ys_ $mul +test_cell -s 1694091355 -n 100 -script booth_map_script.ys_ $mul