diff --git a/passes/silimate/opt_compact_prefix.cc b/passes/silimate/opt_compact_prefix.cc index e9b82f18b..e367e0ee3 100644 --- a/passes/silimate/opt_compact_prefix.cc +++ b/passes/silimate/opt_compact_prefix.cc @@ -60,9 +60,22 @@ struct OptCompactPrefixWorker } } - Wire *port(const char *name) + vector input_ports() { - return module->wire(RTLIL::escape_id(name)); + vector ports; + for (auto wire : module->wires()) + if (wire->port_input) + ports.push_back(wire); + return ports; + } + + vector output_ports() + { + vector ports; + for (auto wire : module->wires()) + if (wire->port_output) + ports.push_back(wire); + return ports; } int count_cells(IdString type) @@ -195,19 +208,36 @@ struct OptCompactPrefixWorker return result; } - bool bmux_selects_stay_in_range(Wire *data, int loop_width) + int output_bits_controlled_by(Wire *control, Wire *output) { - bool saw_data_bmux = false; + pool bits; for (auto cell : module->cells()) { - if (cell->type != ID($bmux)) + if (cell->type != ID($mux)) + continue; + SigSpec sel = sigmap(cell->getPort(ID::S)); + if (GetSize(sel) != 1 || sel[0].wire != control) + continue; + for (auto bit : sigmap(cell->getPort(ID::Y))) + if (bit.wire == output) + bits.insert(bit.offset); + } + return GetSize(bits); + } + + bool indexed_reads_stay_in_range(Wire *data, int loop_width) + { + bool saw_data_read = false; + for (auto cell : module->cells()) { + if (!cell->type.in(ID($bmux), ID($shiftx))) continue; if (sigmap(cell->getPort(ID::A)) != sigmap(SigSpec(data))) continue; - saw_data_bmux = true; - if (eval_sig_at_zero(cell->getPort(ID::S)) >= loop_width) + saw_data_read = true; + IdString select_port = cell->type == ID($bmux) ? ID::S : ID::B; + if (eval_sig_at_zero(cell->getPort(select_port)) >= loop_width) return false; } - return saw_data_bmux; + return saw_data_read; } SigSpec zext(SigSpec sig, int width) @@ -311,12 +341,12 @@ struct OptCompactPrefixWorker bool rewrite_forward_dense_pack() { - Wire *sig = port("sig"); - Wire *sig2 = port("sig2"); - if (!sig || !sig2) - return false; - if (!sig->port_input || !sig2->port_output) + vector inputs = input_ports(); + vector outputs = output_ports(); + if (GetSize(inputs) != 1 || GetSize(outputs) != 1) return false; + Wire *sig = inputs[0]; + Wire *sig2 = outputs[0]; if (GetSize(sig) != GetSize(sig2)) return false; if (GetSize(sig) < 4 || GetSize(sig) > max_width) @@ -325,8 +355,6 @@ struct OptCompactPrefixWorker return false; if (count_binop_const(ID($add), 1) < GetSize(sig) - 2) return false; - if (count_cells(ID($shl)) < GetSize(sig) - 2) - return false; if (count_cells(ID($mux)) < GetSize(sig)) return false; if (!eval_sig_is_zero(SigSpec(sig2))) @@ -357,29 +385,45 @@ struct OptCompactPrefixWorker bool rewrite_reverse_suffix_read() { - Wire *disable = port("disable_in"); - Wire *data = port("data_in"); - Wire *mask = port("mask"); - if (!disable || !data || !mask) + vector inputs = input_ports(); + vector outputs = output_ports(); + if (GetSize(inputs) != 2 || GetSize(outputs) != 1) return false; - if (!disable->port_input || !data->port_input || !mask->port_output) - return false; - if (GetSize(disable) != GetSize(data) || GetSize(mask) != GetSize(data)) - return false; - if (GetSize(module->ports) != 3) + Wire *mask = outputs[0]; + if (GetSize(inputs[0]) != GetSize(inputs[1]) || GetSize(mask) != GetSize(inputs[0])) return false; int dec_count = std::max(count_binop_const(ID($sub), 1), count_binop_const(ID($add), -1)); int loop_width = dec_count + 1; - if (loop_width < 4 || loop_width > max_width || loop_width > GetSize(data)) - return false; if (count_cells(ID($mux)) < loop_width) return false; if (has_binop_const_other_than(ID($sub), 1) || has_binop_const_other_than(ID($add), -1)) return false; - if (!bmux_selects_stay_in_range(data, loop_width)) + + Wire *disable = nullptr; + int controlled_width = 0; + for (auto input : inputs) { + int n = output_bits_controlled_by(input, mask); + if (n == 0) + continue; + if (disable != nullptr) + return false; + disable = input; + controlled_width = n; + } + if (disable == nullptr) + return false; + if (controlled_width > 0) + loop_width = controlled_width; + if (loop_width < 4 || loop_width > max_width || loop_width > GetSize(mask)) + return false; + if (dec_count < loop_width - 1) + return false; + Wire *data = (inputs[0] == disable) ? inputs[1] : inputs[0]; + + if (!indexed_reads_stay_in_range(data, loop_width)) return false; if (!eval_sig_is_zero(SigSpec(mask))) return false; diff --git a/tests/silimate/opt_compact_prefix.ys b/tests/silimate/opt_compact_prefix.ys index 94148be0c..4ed9f0044 100644 --- a/tests/silimate/opt_compact_prefix.ys +++ b/tests/silimate/opt_compact_prefix.ys @@ -114,6 +114,23 @@ select -assert-count 32 t:$gt design -reset log -pop +log -header "Renamed ports: forward dense pack" +log -push +design -reset +verific -cfg veri_optimize_wide_selector 1 +verific -cfg db_infer_wide_muxes_post_elaboration 0 +read -sv opt_compact_prefix_renamed.sv +verific -import opt_compact_prefix_pack_renamed +proc; opt_clean +opt_compact_prefix +opt_clean +select -assert-none t:$shl +select -assert-none t:$mux +select -assert-count 7 t:$add +select -assert-count 8 t:$gt +design -reset +log -pop + log -header "Exact regression size: 16-entry reverse suffix read" log -push design -reset @@ -131,6 +148,53 @@ select -assert-min 1 t:$eq design -reset log -pop +log -header "Renamed ports: reverse suffix read" +log -push +design -reset +verific -cfg veri_optimize_wide_selector 1 +verific -cfg db_infer_wide_muxes_post_elaboration 0 +read -sv opt_compact_prefix_renamed.sv +verific -import opt_compact_prefix_sub_renamed +proc; opt_clean +opt_compact_prefix +opt_clean +select -assert-none t:$sub +select -assert-none t:$mux +select -assert-min 1 t:$add +select -assert-min 1 t:$eq +design -reset +log -pop + +log -header "Yosys frontend: forward dense pack" +log -push +design -reset +read_verilog -sv opt_compact_prefix_yosys_frontend.v +hierarchy -top opt_compact_prefix_yosys_pack +proc; opt_clean +opt_compact_prefix +opt_clean +select -assert-none t:$shl +select -assert-none t:$mux +select -assert-count 7 t:$add +select -assert-count 8 t:$gt +design -reset +log -pop + +log -header "Yosys frontend: reverse suffix read" +log -push +design -reset +read_verilog -sv opt_compact_prefix_yosys_frontend.v +hierarchy -top opt_compact_prefix_yosys_sub +proc; opt_clean +opt_compact_prefix +opt_clean +select -assert-none t:$sub +select -assert-none t:$mux +select -assert-min 1 t:$add +select -assert-min 1 t:$eq +design -reset +log -pop + log -header "Reverse suffix read with add-by-minus-one decrement" log -push design -reset diff --git a/tests/silimate/opt_compact_prefix_renamed.sv b/tests/silimate/opt_compact_prefix_renamed.sv new file mode 100644 index 000000000..72e75a60b --- /dev/null +++ b/tests/silimate/opt_compact_prefix_renamed.sv @@ -0,0 +1,32 @@ +module opt_compact_prefix_pack_renamed ( + input logic [7:0] in_bits, + output logic [7:0] packed_bits +); + always_comb begin + packed_bits = '0; + for (int I = 0, indx = 0; I < 8; I++) begin + if (in_bits[I]) begin + packed_bits[indx] = in_bits[I]; + indx += 1; + end + end + end +endmodule + +module opt_compact_prefix_sub_renamed ( + input logic [15:0] stall_vec, + input logic [15:0] payload_vec, + output logic [15:0] allow_mask +); + always_comb begin + allow_mask = '0; + for (int I = 8, indx = 8; I > 0; I--) begin + if (stall_vec[I-1]) begin + allow_mask[I-1] = 1'b0; + end else begin + allow_mask[I-1] = payload_vec[indx-1]; + indx = indx - 1; + end + end + end +endmodule diff --git a/tests/silimate/opt_compact_prefix_yosys_frontend.v b/tests/silimate/opt_compact_prefix_yosys_frontend.v new file mode 100644 index 000000000..3f8968a9a --- /dev/null +++ b/tests/silimate/opt_compact_prefix_yosys_frontend.v @@ -0,0 +1,38 @@ +module opt_compact_prefix_yosys_pack ( + input wire [7:0] in_bits, + output reg [7:0] packed_bits +); + integer I; + integer indx; + always @* begin + packed_bits = 8'b0; + indx = 0; + for (I = 0; I < 8; I = I + 1) begin + if (in_bits[I]) begin + packed_bits[indx] = in_bits[I]; + indx = indx + 1; + end + end + end +endmodule + +module opt_compact_prefix_yosys_sub ( + input wire [15:0] stall_vec, + input wire [15:0] payload_vec, + output reg [15:0] allow_mask +); + integer I; + integer indx; + always @* begin + allow_mask = 16'b0; + indx = 8; + for (I = 8; I > 0; I = I - 1) begin + if (stall_vec[I-1]) begin + allow_mask[I-1] = 1'b0; + end else begin + allow_mask[I-1] = payload_vec[indx-1]; + indx = indx - 1; + end + end + end +endmodule