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

Fixed edge size cases for signed/unsigned booth generator

This commit is contained in:
andyfox-rushc 2023-09-08 13:41:31 -07:00
parent 25a33d4082
commit 411acc4a0a

View file

@ -295,45 +295,85 @@ struct MultPassWorker {
int y_sz = GetSize(B); int y_sz = GetSize(B);
int z_sz = GetSize(Y); int z_sz = GetSize(Y);
// create a buffer for each ip // To simplify the generator size the arguments
std::string buf_name = "u_mult_multiplicand_buf_"; // to be the same. Then allow logic synthesis to
auto A_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); // clean things up. Size to biggest
A_Buf->setParam(ID::A_WIDTH, x_sz);
A_Buf->setParam(ID::Y_WIDTH, x_sz);
A_Buf->setPort(ID::A, SigSpec(A));
A_Buf->setParam(ID::A_SIGNED, false);
std::string wire_name = "u_mult_A"; int x_sz_revised = x_sz;
auto A_Wire = module->addWire(new_id(wire_name, __LINE__, ""), x_sz); int y_sz_revised = y_sz;
A_Buf->setPort(ID::Y, A_Wire); 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;
buf_name = "u_mult_multiplier_buf_"; log("Resized x to %d ", x_sz_revised);
auto B_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); } else {
B_Buf->setParam(ID::A_WIDTH, y_sz); if (x_sz % 2 != 0) {
B_Buf->setParam(ID::Y_WIDTH, y_sz); y_sz_revised = x_sz + 1;
B_Buf->setPort(ID::A, SigSpec(B)); x_sz_revised = x_sz + 1;
B_Buf->setParam(ID::A_SIGNED, false); } else
y_sz_revised = x_sz;
log("Resized y to %d ", y_sz_revised);
}
} else {
if (x_sz % 2 != 0) {
y_sz_revised = y_sz + 1;
x_sz_revised = x_sz + 1;
}
}
wire_name = "u_mult_B"; log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0));
auto B_Wire = module->addWire(new_id(wire_name, __LINE__, ""), y_sz);
B_Buf->setPort(ID::Y, B_Wire);
buf_name = "u_mult_result_buf_"; Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised);
auto Z_Buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised);
Z_Buf->setParam(ID::A_WIDTH, z_sz);
Z_Buf->setParam(ID::Y_WIDTH, z_sz);
Z_Buf->setPort(ID::Y, SigSpec(Y));
Z_Buf->setParam(ID::A_SIGNED, false);
wire_name = "u_mult_Z";
auto Z_Wire = module->addWire(new_id(wire_name, __LINE__, ""), z_sz);
Z_Buf->setPort(ID::A, Z_Wire);
CreateBoothUMult(module, x_sz, y_sz, z_sz, std::string buf_name = "expand_a_buf_";
A_Wire, // multiplicand auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos));
B_Wire, // multiplier(scanned) buf->setParam(ID::A_WIDTH, x_sz);
Z_Wire // result buf->setParam(ID::Y_WIDTH, x_sz_revised);
buf->setPort(ID::A, SigSpec(A));
buf->setParam(ID::A_SIGNED, 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, 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);
CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size,
expanded_A, // multiplicand
expanded_B, // multiplier(scanned)
expanded_Y // result
); );
// now connect the expanded_Y with a tap to fill out sig Spec Y
log("Adding reducer on output from %u to %u ", required_op_size, z_sz);
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, false);
// wire in output Y
buf->setPort(ID::Y, SigSpec(Y));
module->remove(cell); module->remove(cell);
booth_counter++; booth_counter++;
continue; continue;
@ -344,47 +384,81 @@ struct MultPassWorker {
int y_sz = GetSize(B); int y_sz = GetSize(B);
int z_sz = GetSize(Y); int z_sz = GetSize(Y);
// make wire of correct size to feed multiplier // To simplify the generator size the arguments
Wire *expanded_A = module->addWire(NEW_ID, x_sz); // to be the same. Then allow logic synthesis to
// clean things up. Size to biggest
Wire *expanded_B = module->addWire(NEW_ID, y_sz); 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;
log("Resized x to %d ", x_sz_revised);
} 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("Resized y to %d ", y_sz_revised);
}
} 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));
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_"; std::string buf_name = "expand_a_buf_";
auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos));
buf->setParam(ID::A_WIDTH, x_sz); buf->setParam(ID::A_WIDTH, x_sz);
buf->setParam(ID::Y_WIDTH, x_sz); buf->setParam(ID::Y_WIDTH, x_sz_revised);
buf->setPort(ID::A, SigSpec(A)); buf->setPort(ID::A, SigSpec(A));
buf->setParam(ID::A_SIGNED, is_signed ? true : false); buf->setParam(ID::A_SIGNED, true);
buf->setPort(ID::Y, SigSpec(expanded_A)); buf->setPort(ID::Y, SigSpec(expanded_A));
buf_name = "expand_b_buf_"; buf_name = "expand_b_buf_";
buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos));
buf->setPort(ID::A, SigSpec(B)); buf->setPort(ID::A, SigSpec(B));
buf->setParam(ID::A_WIDTH, y_sz); buf->setParam(ID::A_WIDTH, y_sz);
buf->setParam(ID::Y_WIDTH, y_sz); buf->setParam(ID::Y_WIDTH, y_sz_revised);
buf->setParam(ID::A_SIGNED, true);
buf->setParam(ID::A_SIGNED, is_signed ? true : false);
buf->setPort(ID::Y, SigSpec(expanded_B)); buf->setPort(ID::Y, SigSpec(expanded_B));
// // Make sure output domain is big enough to take
// Make a wire to take the expanded output // all combinations.
// wires // Later logic synthesis will kill unused
// // portions of the output domain.
Wire *expanded_Y = module->addWire(NEW_ID, (is_signed == false ? z_sz + 2 : z_sz)); unsigned required_op_size = x_sz_revised + y_sz_revised;
CreateBoothSMult(module, x_sz, y_sz, (is_signed == false ? z_sz + 2 : z_sz),
Wire *expanded_Y = module->addWire(NEW_ID, required_op_size);
CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size,
expanded_A, // multiplicand expanded_A, // multiplicand
expanded_B, // multiplier(scanned) expanded_B, // multiplier(scanned)
expanded_Y // result expanded_Y // result (sized)
); );
// now connect the expanded_Y with a tap to fill out sig Spec Y // now connect the expanded_Y with a tap to fill out sig Spec Y
log("Adding reducer on output from %u to %u ", required_op_size, z_sz);
buf_name = "reducer_buf_"; buf_name = "reducer_buf_";
buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos));
buf->setPort(ID::A, expanded_Y); buf->setPort(ID::A, expanded_Y);
buf->setParam(ID::A_WIDTH, is_signed == false ? z_sz + 2 : z_sz); buf->setParam(ID::A_WIDTH, required_op_size);
buf->setParam(ID::Y_WIDTH, z_sz); buf->setParam(ID::Y_WIDTH, z_sz); // The real user width
buf->setParam(ID::A_SIGNED, is_signed ? true : false); buf->setParam(ID::A_SIGNED, true);
// wire in output Y // wire in output Y
buf->setPort(ID::Y, SigSpec(Y)); buf->setPort(ID::Y, SigSpec(Y));
@ -1451,7 +1525,7 @@ struct MultPassWorker {
std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_";
cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1);
} }
log(" Building cpa array for booth\n"); log(" Building cpa array for booth for output size %u\n", z_sz);
for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) {
// The end case where we pass the last two summands // The end case where we pass the last two summands
@ -1525,15 +1599,16 @@ struct MultPassWorker {
}; };
struct MultPass : public Pass { struct MultPass : public Pass {
MultPass() : Pass("multpass") {} MultPass() : Pass("multpass", "Map $mul to booth multipliers") {}
void execute(vector<string> args, RTLIL::Design *design) override void execute(vector<string> args, RTLIL::Design *design) override
{ {
(void)args; (void)args;
log("Multiplier Pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); log_header(design, "Executing multpass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n");
for (auto mod : design->selected_modules()) for (auto mod : design->selected_modules())
if (!mod->has_processes_warn()) { if (!mod->has_processes_warn()) {
MultPassWorker worker(mod); MultPassWorker worker(mod);
worker.run(); worker.run();
log_header(design, "Created %d booth multipliers.\n", worker.booth_counter);
} }
} }
} MultPass; } MultPass;