Added support for resource sharing in mux control logic

This commit is contained in:
Clifford Wolf 2014-07-20 20:44:14 +02:00
parent 1ce5e83555
commit 04fcb07213
1 changed files with 152 additions and 83 deletions

View File

@ -42,6 +42,7 @@ struct ShareWorker
ModWalker modwalker;
std::set<RTLIL::Cell*> cells_to_remove;
std::set<RTLIL::Cell*> recursion_state;
// ------------------------------------------------------------------------------
@ -52,58 +53,36 @@ struct ShareWorker
void find_terminal_bits()
{
std::set<RTLIL::SigBit> queue_strong_bits, queue_weak_bits;
std::set<RTLIL::SigBit> queue_bits;
std::set<RTLIL::Cell*> visited_cells;
queue_weak_bits.insert(modwalker.signal_outputs.begin(), modwalker.signal_outputs.end());
queue_bits.insert(modwalker.signal_outputs.begin(), modwalker.signal_outputs.end());
for (auto &it : module->cells)
{
RTLIL::Cell *cell = it.second;
if (cell->type == "$mux" || cell->type == "$pmux")
{
std::vector<RTLIL::SigBit> bits = modwalker.sigmap(cell->connections.at("\\S"));
queue_strong_bits.insert(bits.begin(), bits.end());
if (!fwd_ct.cell_known(it.second->type)) {
std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[it.second];
queue_bits.insert(bits.begin(), bits.end());
}
else if (!fwd_ct.cell_known(cell->type))
{
std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[cell];
queue_weak_bits.insert(bits.begin(), bits.end());
}
}
terminal_bits.insert(queue_strong_bits.begin(), queue_strong_bits.end());
terminal_bits.insert(queue_weak_bits.begin(), queue_weak_bits.end());
terminal_bits.insert(queue_bits.begin(), queue_bits.end());
while (!queue_strong_bits.empty())
while (!queue_bits.empty())
{
std::set<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, queue_strong_bits);
queue_strong_bits.clear();
for (auto &pbit : portbits)
if (fwd_ct.cell_known(pbit.cell->type) && visited_cells.count(pbit.cell) == 0) {
std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[pbit.cell];
terminal_bits.insert(bits.begin(), bits.end());
queue_strong_bits.insert(bits.begin(), bits.end());
visited_cells.insert(pbit.cell);
}
}
while (!queue_weak_bits.empty())
{
std::set<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, queue_weak_bits);
queue_weak_bits.clear();
modwalker.get_drivers(portbits, queue_bits);
queue_bits.clear();
for (auto &pbit : portbits) {
if (pbit.cell->type == "$mux" || pbit.cell->type == "$pmux")
continue;
if (pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") {
std::set<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->connections.at("\\S")).to_sigbit_set();
terminal_bits.insert(bits.begin(), bits.end());
queue_bits.insert(bits.begin(), bits.end());
visited_cells.insert(pbit.cell);
}
if (fwd_ct.cell_known(pbit.cell->type) && visited_cells.count(pbit.cell) == 0) {
std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[pbit.cell];
terminal_bits.insert(bits.begin(), bits.end());
queue_weak_bits.insert(bits.begin(), bits.end());
queue_bits.insert(bits.begin(), bits.end());
visited_cells.insert(pbit.cell);
}
}
@ -306,6 +285,48 @@ struct ShareWorker
}
// -------------------------------------------
// Finding forbidden control inputs for a cell
// -------------------------------------------
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> forbidden_controls_cache;
const std::set<RTLIL::SigBit> &find_forbidden_controls(RTLIL::Cell *cell)
{
if (recursion_state.count(cell)) {
static std::set<RTLIL::SigBit> empty_controls_set;
return empty_controls_set;
}
if (forbidden_controls_cache.count(cell))
return forbidden_controls_cache.at(cell);
std::set<ModWalker::PortBit> pbits;
std::set<RTLIL::Cell*> consumer_cells;
modwalker.get_consumers(pbits, modwalker.cell_outputs[cell]);
for (auto &bit : pbits) {
if ((bit.cell->type == "$mux" || bit.cell->type == "$pmux") && bit.port == "\\S")
forbidden_controls_cache[cell].insert(bit.cell->connections.at("\\S").extract(bit.offset, 1));
consumer_cells.insert(bit.cell);
}
recursion_state.insert(cell);
for (auto c : consumer_cells)
if (fwd_ct.cell_known(c->type)) {
const std::set<RTLIL::SigBit> &bits = find_forbidden_controls(c);
forbidden_controls_cache[cell].insert(bits.begin(), bits.end());
}
log_assert(recursion_state.count(cell));
recursion_state.erase(cell);
return forbidden_controls_cache[cell];
}
// --------------------------------------------------------
// Finding control inputs and activation pattern for a cell
// --------------------------------------------------------
@ -344,11 +365,16 @@ struct ShareWorker
const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
{
if (recursion_state.count(cell)) {
static std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> empty_patterns_set;
return empty_patterns_set;
}
if (activation_patterns_cache.count(cell))
return activation_patterns_cache.at(cell);
const std::set<RTLIL::SigBit> &cell_out_bits = modwalker.cell_outputs[cell];
std::set<RTLIL::Cell*> driven_cells;
std::set<RTLIL::Cell*> driven_cells, driven_data_muxes;
for (auto &bit : cell_out_bits)
{
@ -359,55 +385,59 @@ struct ShareWorker
}
for (auto &pbit : modwalker.signal_consumers[bit]) {
log_assert(fwd_ct.cell_known(pbit.cell->type));
driven_cells.insert(pbit.cell);
if ((pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") && (pbit.port == "\\A" || pbit.port == "\\B"))
driven_data_muxes.insert(pbit.cell);
else
driven_cells.insert(pbit.cell);
}
}
for (auto c : driven_cells)
recursion_state.insert(cell);
for (auto c : driven_data_muxes)
{
const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
if (c->type == "$mux" || c->type == "$pmux")
{
bool used_in_a = false;
std::set<int> used_in_b_parts;
bool used_in_a = false;
std::set<int> used_in_b_parts;
int width = c->parameters.at("\\WIDTH").as_int();
std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->connections.at("\\A"));
std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->connections.at("\\B"));
std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->connections.at("\\S"));
int width = c->parameters.at("\\WIDTH").as_int();
std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->connections.at("\\A"));
std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->connections.at("\\B"));
std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->connections.at("\\S"));
for (auto &bit : sig_a)
if (cell_out_bits.count(bit))
used_in_a = true;
for (auto &bit : sig_a)
if (cell_out_bits.count(bit))
used_in_a = true;
for (int i = 0; i < SIZE(sig_b); i++)
if (cell_out_bits.count(sig_b[i]))
used_in_b_parts.insert(i / width);
for (int i = 0; i < SIZE(sig_b); i++)
if (cell_out_bits.count(sig_b[i]))
used_in_b_parts.insert(i / width);
if (used_in_a)
for (auto p : c_patterns) {
for (int i = 0; i < SIZE(sig_s); i++)
p.first.append_bit(sig_s[i]), p.second.bits.push_back(RTLIL::State::S0);
if (sort_check_activation_pattern(p))
activation_patterns_cache[cell].insert(p);
}
if (used_in_a)
for (auto p : c_patterns) {
for (int i = 0; i < SIZE(sig_s); i++)
p.first.append_bit(sig_s[i]), p.second.bits.push_back(RTLIL::State::S0);
if (sort_check_activation_pattern(p))
activation_patterns_cache[cell].insert(p);
}
for (int idx : used_in_b_parts)
for (auto p : c_patterns) {
p.first.append_bit(sig_s[idx]), p.second.bits.push_back(RTLIL::State::S1);
if (sort_check_activation_pattern(p))
activation_patterns_cache[cell].insert(p);
}
}
else
{
// Not a mux: just copy the activation patterns
for (auto &p : c_patterns)
activation_patterns_cache[cell].insert(p);
}
for (int idx : used_in_b_parts)
for (auto p : c_patterns) {
p.first.append_bit(sig_s[idx]), p.second.bits.push_back(RTLIL::State::S1);
if (sort_check_activation_pattern(p))
activation_patterns_cache[cell].insert(p);
}
}
for (auto c : driven_cells) {
const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
activation_patterns_cache[cell].insert(c_patterns.begin(), c_patterns.end());
}
log_assert(recursion_state.count(cell));
recursion_state.erase(cell);
optimize_activation_patterns(activation_patterns_cache[cell]);
if (activation_patterns_cache[cell].empty()) {
log("%sFound cell that is never activated: %s\n", indent, log_id(cell));
@ -434,6 +464,24 @@ struct ShareWorker
return signal;
}
void filter_activation_patterns(std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &out,
const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &in, const std::set<RTLIL::SigBit> &filter_bits)
{
for (auto &p : in)
{
std::vector<RTLIL::SigBit> p_first = p.first;
std::pair<RTLIL::SigSpec, RTLIL::Const> new_p;
for (int i = 0; i < SIZE(p_first); i++)
if (filter_bits.count(p_first[i]) == 0) {
new_p.first.append_bit(p_first[i]);
new_p.second.bits.push_back(p.second.bits.at(i));
}
out.insert(new_p);
}
}
RTLIL::SigSpec make_cell_activation_logic(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns)
{
RTLIL::Wire *all_cases_wire = module->new_wire(0, NEW_ID);
@ -533,6 +581,25 @@ struct ShareWorker
log(" Found %d activation_patterns using ctrl signal %s.\n",
SIZE(other_cell_activation_patterns), log_signal(other_cell_activation_signals));
const std::set<RTLIL::SigBit> &cell_forbidden_controls = find_forbidden_controls(cell);
const std::set<RTLIL::SigBit> &other_cell_forbidden_controls = find_forbidden_controls(other_cell);
std::set<RTLIL::SigBit> union_forbidden_controls;
union_forbidden_controls.insert(cell_forbidden_controls.begin(), cell_forbidden_controls.end());
union_forbidden_controls.insert(other_cell_forbidden_controls.begin(), other_cell_forbidden_controls.end());
if (!union_forbidden_controls.empty())
log(" Forbidden control signals for this pair of cells: %s\n", log_signal(union_forbidden_controls));
std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> filtered_cell_activation_patterns;
std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> filtered_other_cell_activation_patterns;
filter_activation_patterns(filtered_cell_activation_patterns, cell_activation_patterns, union_forbidden_controls);
filter_activation_patterns(filtered_other_cell_activation_patterns, other_cell_activation_patterns, union_forbidden_controls);
optimize_activation_patterns(filtered_cell_activation_patterns);
optimize_activation_patterns(filtered_other_cell_activation_patterns);
ezDefaultSAT ez;
SatGen satgen(&ez, &modwalker.sigmap);
@ -542,13 +609,13 @@ struct ShareWorker
std::vector<int> cell_active, other_cell_active;
RTLIL::SigSpec all_ctrl_signals;
for (auto &p : cell_activation_patterns) {
for (auto &p : filtered_cell_activation_patterns) {
log(" Activation pattern for cell %s: %s = %s\n", log_id(cell), log_signal(p.first), log_signal(p.second));
cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
all_ctrl_signals.append(p.first);
}
for (auto &p : other_cell_activation_patterns) {
for (auto &p : filtered_other_cell_activation_patterns) {
log(" Activation pattern for cell %s: %s = %s\n", log_id(other_cell), log_signal(p.first), log_signal(p.second));
other_cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
all_ctrl_signals.append(p.first);
@ -604,19 +671,19 @@ struct ShareWorker
int cell_select_score = 0;
int other_cell_select_score = 0;
for (auto &p : cell_activation_patterns)
for (auto &p : filtered_cell_activation_patterns)
cell_select_score += p.first.width;
for (auto &p : other_cell_activation_patterns)
for (auto &p : filtered_other_cell_activation_patterns)
other_cell_select_score += p.first.width;
RTLIL::Cell *supercell;
if (cell_select_score <= other_cell_select_score) {
RTLIL::SigSpec act = make_cell_activation_logic(cell_activation_patterns);
RTLIL::SigSpec act = make_cell_activation_logic(filtered_cell_activation_patterns);
supercell = make_supercell(cell, other_cell, act);
log(" Activation signal for %s: %s\n", log_id(cell), log_signal(act));
} else {
RTLIL::SigSpec act = make_cell_activation_logic(other_cell_activation_patterns);
RTLIL::SigSpec act = make_cell_activation_logic(filtered_other_cell_activation_patterns);
supercell = make_supercell(other_cell, cell, act);
log(" Activation signal for %s: %s\n", log_id(other_cell), log_signal(act));
}
@ -624,8 +691,8 @@ struct ShareWorker
log(" New cell: %s (%s)\n", log_id(supercell), log_id(supercell->type));
std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> supercell_activation_patterns;
supercell_activation_patterns.insert(cell_activation_patterns.begin(), cell_activation_patterns.end());
supercell_activation_patterns.insert(other_cell_activation_patterns.begin(), other_cell_activation_patterns.end());
supercell_activation_patterns.insert(filtered_cell_activation_patterns.begin(), filtered_cell_activation_patterns.end());
supercell_activation_patterns.insert(filtered_other_cell_activation_patterns.begin(), filtered_other_cell_activation_patterns.end());
optimize_activation_patterns(supercell_activation_patterns);
activation_patterns_cache[supercell] = supercell_activation_patterns;
shareable_cells.insert(supercell);
@ -644,6 +711,8 @@ struct ShareWorker
delete c;
}
}
log_assert(recursion_state.empty());
}
};