3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-12 20:18:20 +00:00

booth: Streamline the low-level circuit emission

For the basic single-bit operations, opt for gate cells (`$_AND_` etc.)
instead of the coarse cells (`$and` etc.). For the emission of cells
move to the conventional module methods (`module->addAndGate`) away
from the local helpers. While at it, touch on the surrounding code.
This commit is contained in:
Martin Povišer 2023-09-19 15:48:23 +02:00
parent cb05262fc4
commit 986507f95f

View file

@ -108,98 +108,88 @@ struct BoothPassWorker {
} }
// Booth unsigned decoder lsb // Booth unsigned decoder lsb
void BuildBur4d_lsb(std::string &name, SigBit lsb_i, SigBit one_i, SigBit s_i, SigBit &ppij_o, SigBit Bur4d_lsb(std::string name, SigBit lsb_i, SigBit one_i, SigBit s_i)
std::string op_wire_name)
{ {
std::string empty; SigBit and_op = module->AndGate(NEW_ID_SUFFIX(name), lsb_i, one_i);
auto and_op = mk_ugate2(ID($and), name, lsb_i, one_i, empty); return module->XorGate(NEW_ID_SUFFIX(name), and_op, s_i);
ppij_o = mk_ugate2(ID($xor), name, and_op, s_i, op_wire_name);
} }
// Booth unsigned radix4 decoder // Booth unsigned radix4 decoder
void BuildBur4d_n(std::string &name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i, SigBit Bur4d_n(std::string name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i)
SigBit &ppij_o)
{ {
// ppij = ((yn & one) | (ynm1 & two)) ^ s; // ppij = ((yn & one) | (ynm1 & two)) ^ s;
std::string empty; SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), yn_i, one_i);
auto an1 = mk_ugate2(ID($and), name, yn_i, one_i, empty); SigBit an2 = module->AndGate(NEW_ID_SUFFIX(name), ynm1_i, two_i);
auto an2 = mk_ugate2(ID($and), name, ynm1_i, two_i, empty); SigBit or1 = module->OrGate(NEW_ID_SUFFIX(name), an1, an2);
auto or1 = mk_ugate2(ID($or), name, an1, an2, empty); return module->XorGate(NEW_ID_SUFFIX(name), s_i, or1);
ppij_o = mk_ugate2(ID($xor), name, s_i, or1, empty);
} }
// Booth unsigned radix4 decoder // Booth unsigned radix4 decoder
void BuildBur4d_msb(std::string &name, SigBit msb_i, SigBit two_i, SigBit s_i, SigBit &ppij_o) SigBit Bur4d_msb(std::string name, SigBit msb_i, SigBit two_i, SigBit s_i)
{ {
// ppij = (msb & two) ^ s; // ppij = (msb & two) ^ s;
std::string empty; SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), msb_i, two_i);
auto an1 = mk_ugate2(ID($and), name, msb_i, two_i, empty); return module->XorGate(NEW_ID_SUFFIX(name), s_i, an1);
ppij_o = mk_ugate2(ID($xor), name, s_i, an1, empty);
} }
// half adder, used in CPA // half adder, used in CPA
void BuildHa(std::string &name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) void BuildHa(std::string name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o)
{ {
std::string empty; s_o = module->XorGate(NEW_ID_SUFFIX(name), a_i, b_i);
s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); c_o = module->AndGate(NEW_ID_SUFFIX(name), a_i, b_i);
c_o = mk_ugate2(ID($and), name, a_i, b_i, empty);
} }
// Booth unsigned radix 4 encoder // Booth unsigned radix 4 encoder
void BuildBur4e(std::string &name, SigBit y0_i, SigBit y1_i, SigBit y2_i, 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) SigBit &one_o, SigBit &two_o, SigBit &s_o, SigBit &sb_o)
{ {
one_o = module->XorGate(NEW_ID_SUFFIX(name), y0_i, y1_i);
std::string empty;
one_o = mk_ugate2(ID($xor), name, y0_i, y1_i, empty);
s_o = y2_i; s_o = y2_i;
sb_o = mk_ugate1(ID($not), name, y2_i, empty); sb_o = module->NotGate(NEW_ID_SUFFIX(name), y2_i);
auto inv_y1_xor_y2 = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y1_i, y2_i, empty), empty); SigBit y1_xnor_y2 = module->XnorGate(NEW_ID_SUFFIX(name), y1_i, y2_i);
two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); two_o = module->NorGate(NEW_ID_SUFFIX(name), y1_xnor_y2, one_o);
} }
void BuildBr4e(std::string &name, SigBit y2_m1_i, void BuildBr4e(std::string name, SigBit y2_m1_i,
SigBit y2_i, // y2i SigBit y2_i, // y2i
SigBit y2_p1_i, SigBit y2_p1_i,
SigBit &negi_o, SigBit &twoi_n_o, SigBit &onei_n_o, SigBit &cori_o) 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; negi_o = y2_p1_i;
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 = mk_ugate1(ID($pos), name, y2_p1_i, empty);
// twoi_n = ~( // twoi_n = ~(
// (y2_p1_n & y2_i & y2_m1_i) | // (y2_p1_n & y2_i & y2_m1_i) |
// (y2_p1 & y2_n & y2_m1_n) // (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); twoi_n_o = module->NorGate(NEW_ID_SUFFIX(name),
auto and3_2 = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($and), name, y2_n, y2_m1_n, empty), empty); 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 = ~(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 = (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 // signed booth radix 4 decoder
// //
void BuildBr4d(std::string &name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, 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) SigBit &ppij_o, SigBit &nxj_o)
{ {
std::string empty;
// nxj_in = xnor(xj,negi) // nxj_in = xnor(xj,negi)
// nxj_o = xnj_in, // nxj_o = xnj_in,
// ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i));
nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), xj_i, negi_i);
SigBit or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); ppij_o = module->NandGate(NEW_ID_SUFFIX(name),
SigBit or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); module->OrGate(NEW_ID_SUFFIX(name), nxj_m1_i, twoi_n_i),
ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); module->OrGate(NEW_ID_SUFFIX(name), nxj_o, onei_n_i)
);
} }
/* /*
@ -207,7 +197,7 @@ struct BoothPassWorker {
using non-booth encoded logic. We can save a booth using non-booth encoded logic. We can save a booth
encoder for the first couple of bits. encoder for the first couple of bits.
*/ */
void BuildBoothQ1(std::string &name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, void BuildBoothQ1(std::string name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i,
SigBit y1_i, SigBit y1_i,
SigBit &nxj_o, SigBit &cor_o, SigBit &pp0_o, SigBit &pp1_o) SigBit &nxj_o, SigBit &cor_o, SigBit &pp0_o, SigBit &pp1_o)
{ {
@ -222,15 +212,14 @@ struct BoothPassWorker {
//correction propagation //correction propagation
assign CORO = (~PP1 & ~PP0)? CORI : 1'b0; assign CORO = (~PP1 & ~PP0)? CORI : 1'b0;
*/ */
std::string empty; nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), x1_i, negi_i);
nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); pp0_o = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y0_i);
pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); SigBit pp1_1_int = module->AndGate(NEW_ID_SUFFIX(name), x1_i, y0_i);
SigBit pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); SigBit pp1_2_int = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y1_i);
SigBit pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); pp1_o = module->XorGate(NEW_ID_SUFFIX(name), pp1_1_int, pp1_2_int);
pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty);
SigBit pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); SigBit pp1_nor_pp0 = module->NorGate(NEW_ID_SUFFIX(name), pp1_o, pp0_o);
cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); cor_o = module->AndGate(NEW_ID_SUFFIX(name), pp1_nor_pp0, cori_i);
} }
void run() void run()
@ -454,28 +443,18 @@ struct BoothPassWorker {
{ {
(void)module; (void)module;
int x_sz = GetSize(X); int x_sz = GetSize(X);
SigBit ppij;
// lsb // lsb
std::string dec_name = "row0_lsb_dec"; ppij_vec.append(Bur4d_lsb("row0_lsb_dec", X[0], one_int[0], s_int[0]));
SigBit ppij;
std::string ppij_name = "ppij_0_0";
BuildBur4d_lsb(dec_name, X[0], one_int[0], s_int[0], ppij, ppij_name);
ppij_vec.append(ppij);
// 1..xsize -1 // 1..xsize -1
for (int i = 1; i < x_sz; i++) { for (int i = 1; i < x_sz; i++)
dec_name = "row0_dec_" + std::to_string(i); ppij_vec.append(Bur4d_n(stringf("row0_dec_%d", i), X[i], X[i - 1],
SigBit ppij; one_int[0], two_int[0], s_int[0]));
BuildBur4d_n(dec_name, X[i], X[i - 1], one_int[0], two_int[0],
s_int[0], ppij);
ppij_vec.append(ppij);
}
// The redundant bit. Duplicate decoding of last bit. // The redundant bit. Duplicate decoding of last bit.
dec_name = "row0_dec_msb"; ppij_vec.append(Bur4d_msb("row0_dec_msb", X[x_sz - 1], two_int[0], s_int[0]));
BuildBur4d_msb(dec_name, X[x_sz - 1], two_int[0], s_int[0], ppij);
ppij_vec.append(ppij);
// append the sign bits // append the sign bits
ppij_vec.append(s_int[0]); ppij_vec.append(s_int[0]);
@ -494,37 +473,23 @@ struct BoothPassWorker {
int x_sz = GetSize(X); int x_sz = GetSize(X);
// lsb // lsb
std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; ppij_vec.append(Bur4d_lsb(stringf("row_%d_lsb_dec", row_ix), X[0], one_int, s_int));
SigBit ppij;
std::string empty;
std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec";
BuildBur4d_lsb(dec_name, X[0], one_int, s_int, ppij, empty);
ppij_vec.append(ppij);
// core bits // core bits
for (int i = 1; i < x_sz; i++) { 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],
dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); one_int, two_int, s_int));
BuildBur4d_n(dec_name, X[i], X[i - 1],
one_int, two_int, s_int, ppij);
ppij_vec.append(ppij);
}
// redundant bit // redundant bit
ppij_vec.append(Bur4d_msb("row_dec_red", X[x_sz - 1], two_int, s_int));
dec_name = "row_dec_red";
BuildBur4d_msb(dec_name, X[x_sz - 1], two_int, s_int, ppij);
ppij_vec.append(ppij);
// sign bit // sign bit
if (no_sign == false) // if no sign is false then make a sign bit if (!no_sign) // if no sign is false then make a sign bit
ppij_vec.append(sb_int); ppij_vec.append(sb_int);
// constant bit // constant bit
if (no_constant == false) { // if non constant is false make a constant bit if (!no_constant) // if non constant is false make a constant bit
ppij_vec.append(State::S1); ppij_vec.append(State::S1);
}
} }
void DebugDumpAlignPP(std::vector<std::vector<RTLIL::Wire *>> &aligned_pp) void DebugDumpAlignPP(std::vector<std::vector<RTLIL::Wire *>> &aligned_pp)