mirror of https://github.com/YosysHQ/yosys.git
booth: Rewrite the main cell selection loop
This commit is contained in:
parent
986507f95f
commit
30f8387b75
|
@ -225,108 +225,92 @@ struct BoothPassWorker {
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
for (auto cell : module->selected_cells()) {
|
for (auto cell : module->selected_cells()) {
|
||||||
if (cell->type.in(ID($mul))) {
|
if (cell->type != ID($mul))
|
||||||
RTLIL::SigSpec A = sigmap(cell->getPort(ID::A));
|
continue;
|
||||||
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);
|
SigSpec A = cell->getPort(ID::A);
|
||||||
int y_sz = GetSize(B);
|
SigSpec B = cell->getPort(ID::B);
|
||||||
int z_sz = GetSize(Y);
|
SigSpec Y = cell->getPort(ID::Y);
|
||||||
|
int x_sz = GetSize(A), y_sz = GetSize(B), z_sz = GetSize(Y);
|
||||||
|
|
||||||
// To simplify the generator size the arguments
|
if (x_sz < 4 || y_sz < 4 || z_sz < 8) {
|
||||||
// to be the same. Then allow logic synthesis to
|
log_debug("Not mapping cell %s sized at %dx%x, %x: size below threshold\n",
|
||||||
// clean things up. Size to biggest
|
log_id(cell), x_sz, y_sz, z_sz);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int x_sz_revised = x_sz;
|
log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool());
|
||||||
int y_sz_revised = y_sz;
|
bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
|
||||||
|
|
||||||
if (x_sz != y_sz) {
|
log("Mapping cell %s to %s Booth multiplier\n", log_id(cell), is_signed ? "signed" : "unsigned");
|
||||||
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 {
|
// To simplify the generator size the arguments
|
||||||
if (x_sz % 2 != 0) {
|
// to be the same. Then allow logic synthesis to
|
||||||
y_sz_revised = x_sz + 1;
|
// clean things up. Size to biggest
|
||||||
x_sz_revised = x_sz + 1;
|
|
||||||
} else
|
int x_sz_revised = x_sz;
|
||||||
y_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 {
|
} else {
|
||||||
if (x_sz % 2 != 0) {
|
x_sz_revised = y_sz;
|
||||||
y_sz_revised = y_sz + 1;
|
}
|
||||||
x_sz_revised = x_sz + 1;
|
} 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));
|
} else {
|
||||||
|
if (x_sz % 2 != 0) {
|
||||||
Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised);
|
y_sz_revised = y_sz + 1;
|
||||||
Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised);
|
x_sz_revised = x_sz + 1;
|
||||||
|
|
||||||
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,
|
|
||||||
expanded_A, // multiplicand
|
|
||||||
expanded_B, // multiplier(scanned)
|
|
||||||
expanded_Y // result
|
|
||||||
);
|
|
||||||
else /*signed multiplier */
|
|
||||||
CreateBoothSMult(module,
|
|
||||||
expanded_A, // multiplicand
|
|
||||||
expanded_B, // multiplier(scanned)
|
|
||||||
expanded_Y // result (sized)
|
|
||||||
);
|
|
||||||
module->remove(cell);
|
|
||||||
booth_counter++;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue