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

booth: Replace the default signed architecture

Generalize what was formerly the unsigned-only architecture to support
both signed and unsigned multiplication, use that as default, and set
aside the special low-power architecture that was formerly used for
signed multipliers.
This commit is contained in:
Martin Povišer 2023-11-20 17:24:24 +01:00
parent f50894d8bf
commit 48b73be8c6

View file

@ -276,18 +276,12 @@ struct BoothPassWorker {
} }
log_assert(GetSize(Y) == required_op_size); log_assert(GetSize(Y) == required_op_size);
if (!is_signed) /* unsigned multiplier */ CreateBoothMult(module,
CreateBoothUMult(module, A, // multiplicand
A, // multiplicand B, // multiplier(scanned)
B, // multiplier(scanned) Y, // result
Y // result is_signed
); );
else /* signed multiplier */
CreateBoothSMult(module,
A, // multiplicand
B, // multiplier(scanned)
Y // result (sized)
);
module->remove(cell); module->remove(cell);
booth_counter++; booth_counter++;
@ -295,24 +289,23 @@ struct BoothPassWorker {
} }
/* /*
Build Unsigned Multiplier. Build Multiplier.
------------------------- -------------------------
Create a booth unsigned multiplier. Uses a generic booth multiplier
Uses a generic booth multiplier with
extra row of decoders and extended multiplier
*/ */
void CreateBoothUMult(RTLIL::Module *module, void CreateBoothMult(RTLIL::Module *module,
SigSpec X, // multiplicand SigSpec X, // multiplicand
SigSpec Y, // multiplier SigSpec Y, // multiplier
SigSpec Z) SigSpec Z,
bool is_signed)
{ // result { // result
int z_sz = Z.size(); int z_sz = Z.size();
SigSpec one_int, two_int, s_int, sb_int; SigSpec one_int, two_int, s_int, sb_int;
int encoder_count = 0; int encoder_count = 0;
BuildBoothUMultEncoders(Y, one_int, two_int, s_int, sb_int, module, encoder_count); BuildBoothMultEncoders(Y, one_int, two_int, s_int, sb_int, module, encoder_count, is_signed);
// Build the decoder rows // Build the decoder rows
// format of each Partial product to be passed to CSA // format of each Partial product to be passed to CSA
@ -326,7 +319,7 @@ struct BoothPassWorker {
// Row 0: special case 1. Format S/.S.S.C.Data // Row 0: special case 1. Format S/.S.S.C.Data
SigSpec ppij_row_0; SigSpec ppij_row_0;
BuildBoothUMultDecoderRow0(module, X, s_int, sb_int, one_int, two_int, ppij_row_0); BuildBoothMultDecoderRow0(module, X, s_int, sb_int, one_int, two_int, ppij_row_0, is_signed);
// data, shift, sign // data, shift, sign
ppij_int.push_back(std::make_tuple(ppij_row_0, 0, s_int[0])); ppij_int.push_back(std::make_tuple(ppij_row_0, 0, s_int[0]));
@ -335,9 +328,10 @@ struct BoothPassWorker {
// format 1,S.Data.shift = encoder_ix*2,sign = sb_int[i] // format 1,S.Data.shift = encoder_ix*2,sign = sb_int[i]
SigSpec ppij_row_n; SigSpec ppij_row_n;
BuildBoothUMultDecoderRowN(module, BuildBoothMultDecoderRowN(module,
X, // multiplicand X, // multiplicand
one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, i one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, i,
is_signed
); );
// data, shift, sign // data, shift, sign
ppij_int.push_back(std::make_tuple(ppij_row_n, i * 2, s_int[i])); ppij_int.push_back(std::make_tuple(ppij_row_n, i * 2, s_int[i]));
@ -373,6 +367,7 @@ struct BoothPassWorker {
// Debug code: Dump out the csa trees // Debug code: Dump out the csa trees
// DumpCSATrees(debug_csa_trees); // DumpCSATrees(debug_csa_trees);
// Build the CPA to do the final accumulation. // Build the CPA to do the final accumulation.
BuildCPA(module, s_vec, c_vec, Z); BuildCPA(module, s_vec, c_vec, Z);
} }
@ -380,11 +375,12 @@ struct BoothPassWorker {
Build Row 0 of decoders Build Row 0 of decoders
*/ */
void BuildBoothUMultDecoderRow0(RTLIL::Module *module, void BuildBoothMultDecoderRow0(RTLIL::Module *module,
SigSpec X, // multiplicand SigSpec X, // multiplicand
SigSpec s_int, SigSpec sb_int, SigSpec one_int, SigSpec s_int, SigSpec sb_int, SigSpec one_int,
SigSpec two_int, SigSpec &ppij_vec) SigSpec two_int, SigSpec &ppij_vec, bool is_signed)
{ {
(void)sb_int;
(void)module; (void)module;
int x_sz = GetSize(X); int x_sz = GetSize(X);
SigBit ppij; SigBit ppij;
@ -397,21 +393,32 @@ struct BoothPassWorker {
ppij_vec.append(Bur4d_n(stringf("row0_dec_%d", i), X[i], X[i - 1], ppij_vec.append(Bur4d_n(stringf("row0_dec_%d", i), X[i], X[i - 1],
one_int[0], two_int[0], s_int[0])); one_int[0], two_int[0], s_int[0]));
// The redundant bit. Duplicate decoding of last bit. // The redundant bit. Duplicate decoding of last bit.
ppij_vec.append(Bur4d_msb("row0_dec_msb", X[x_sz - 1], two_int[0], s_int[0])); if (!is_signed) {
ppij_vec.append(Bur4d_msb("row0_dec_msb", X.msb(), two_int[0], s_int[0]));
} else {
ppij_vec.append(Bur4d_n("row0_dec_msb", X.msb(), X.msb(),
one_int[0], two_int[0], s_int[0]));
}
// append the sign bits // append the sign bits
ppij_vec.append(s_int[0]); if (is_signed) {
ppij_vec.append(s_int[0]); SigBit e = module->XorGate(NEW_ID, s_int[0], module->AndGate(NEW_ID, X.msb(), module->OrGate(NEW_ID, two_int[0], one_int[0])));
ppij_vec.append(sb_int[0]); ppij_vec.append({module->NotGate(NEW_ID, e), e, e});
} else {
// append the sign bits
ppij_vec.append({module->NotGate(NEW_ID, s_int[0]), s_int[0], s_int[0]});
}
} }
// Build a generic row of decoders. // Build a generic row of decoders.
void BuildBoothUMultDecoderRowN(RTLIL::Module *module, void BuildBoothMultDecoderRowN(RTLIL::Module *module,
SigSpec X, // multiplicand SigSpec X, // multiplicand
SigSpec one_int, SigSpec two_int, SigSpec s_int, SigSpec sb_int, SigSpec one_int, SigSpec two_int, SigSpec s_int, SigSpec sb_int,
SigSpec &ppij_vec, int row_ix) SigSpec &ppij_vec, int row_ix,
bool is_signed)
{ {
(void)module; (void)module;
int x_sz = GetSize(X); int x_sz = GetSize(X);
@ -424,13 +431,14 @@ struct BoothPassWorker {
ppij_vec.append(Bur4d_n(stringf("row_%d_dec_%d", row_ix, i), X[i], X[i - 1], ppij_vec.append(Bur4d_n(stringf("row_%d_dec_%d", row_ix, i), X[i], X[i - 1],
one_int, two_int, s_int)); one_int, two_int, s_int));
// redundant bit if (!is_signed) { // redundant bit
ppij_vec.append(Bur4d_msb("row_dec_red", X[x_sz - 1], two_int, s_int)); ppij_vec.append(Bur4d_msb("row_dec_red", X[x_sz - 1], two_int, s_int));
} else {
ppij_vec.append(Bur4d_n(stringf("row_%d_dec_msb", row_ix), X[x_sz - 1], X[x_sz - 1],
one_int, two_int, s_int));
}
// sign bit ppij_vec.append(!is_signed ? sb_int[0] : module->XorGate(NEW_ID, sb_int, module->AndGate(NEW_ID, X.msb(), module->OrGate(NEW_ID, two_int, one_int))));
ppij_vec.append(sb_int);
// constant bit
ppij_vec.append(State::S1); ppij_vec.append(State::S1);
} }
@ -807,12 +815,12 @@ struct BoothPassWorker {
} }
} }
void BuildBoothUMultEncoders(SigSpec Y, SigSpec &one_int, SigSpec &two_int, void BuildBoothMultEncoders(SigSpec Y, SigSpec &one_int, SigSpec &two_int,
SigSpec &s_int, SigSpec &sb_int, RTLIL::Module *module, int &encoder_ix) SigSpec &s_int, SigSpec &sb_int, RTLIL::Module *module, int &encoder_ix, bool is_signed)
{ {
int y_sz = GetSize(Y); int y_sz = GetSize(Y);
for (int y_ix = 0; y_ix < y_sz;) { for (int y_ix = 0; y_ix < (!is_signed ? y_sz : y_sz - 1);) {
std::string enc_name = stringf("bur_enc_%d", encoder_ix); std::string enc_name = stringf("bur_enc_%d", encoder_ix);
two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1));
@ -838,7 +846,7 @@ struct BoothPassWorker {
bool need_padded_cell = false; bool need_padded_cell = false;
if (y_ix > y_sz - 1) { if (y_ix > y_sz - 1) {
y0 = State::S0; y0 = is_signed ? Y.msb() : State::S0;
need_padded_cell = false; need_padded_cell = false;
} else { } else {
y0 = Y[y_ix]; y0 = Y[y_ix];
@ -847,7 +855,7 @@ struct BoothPassWorker {
if (y_ix > y_sz - 1) { if (y_ix > y_sz - 1) {
need_padded_cell = false; need_padded_cell = false;
y1 = State::S0; y1 = is_signed ? Y.msb() : State::S0;
} else { } else {
y1 = Y[y_ix]; y1 = Y[y_ix];
y_ix++; y_ix++;
@ -855,10 +863,10 @@ struct BoothPassWorker {
if (y_ix > y_sz - 1) { if (y_ix > y_sz - 1) {
need_padded_cell = false; need_padded_cell = false;
y2 = State::S0; y2 = is_signed ? Y.msb() : State::S0;
} else { } else {
if (y_ix == y_sz - 1) if (y_ix == y_sz - 1)
need_padded_cell = true; need_padded_cell = !is_signed;
else else
need_padded_cell = false; need_padded_cell = false;
y2 = Y[y_ix]; y2 = Y[y_ix];