| // Copyright (c) 2018 - 2019 ETH Zurich, University of Bologna |
| // All rights reserved. |
| // |
| // This code is under development and not yet released to the public. |
| // Until it is released, the code is under the copyright of ETH Zurich and |
| // the University of Bologna, and may contain confidential and/or unpublished |
| // work. Any reuse/redistribution is strictly forbidden without written |
| // permission from ETH Zurich. |
| // |
| // Bug fixes and contributions will eventually be released under the |
| // SolderPad open hardware license in the context of the PULP platform |
| // (http://www.pulp-platform.org), under the copyright of ETH Zurich and the |
| // University of Bologna. |
| |
| /// A trailing zero counter / leading zero counter. |
| /// Set MODE to 0 for trailing zero counter => cnt_o is the number of trailing zeros (from the LSB) |
| /// Set MODE to 1 for leading zero counter => cnt_o is the number of leading zeros (from the MSB) |
| /// If the input does not contain a zero, `empty_o` is asserted. Additionally `cnt_o` contains |
| /// the maximum number of zeros - 1. For example: |
| /// in_i = 000_0000, empty_o = 1, cnt_o = 6 (mode = 0) |
| /// in_i = 000_0001, empty_o = 0, cnt_o = 0 (mode = 0) |
| /// in_i = 000_1000, empty_o = 0, cnt_o = 3 (mode = 0) |
| /// Furthermore, this unit contains a more efficient implementation for Verilator (simulation only). |
| /// This speeds up simulation significantly. |
| module lzc #( |
| /// The width of the input vector. |
| parameter int unsigned WIDTH = 2, |
| /// Mode selection: 0 -> trailing zero, 1 -> leading zero |
| parameter bit MODE = 1'b0, |
| /// Dependent parameter. Do **not** change! |
| /// |
| /// Width of the output signal with the zero count. |
| parameter int unsigned CNT_WIDTH = cf_math_pkg::idx_width(WIDTH) |
| ) ( |
| /// Input vector to be counted. |
| input logic [WIDTH-1:0] in_i, |
| /// Count of the leading / trailing zeros. |
| output logic [CNT_WIDTH-1:0] cnt_o, |
| /// Counter is empty: Asserted if all bits in in_i are zero. |
| output logic empty_o |
| ); |
| |
| if (WIDTH == 1) begin : gen_degenerate_lzc |
| |
| assign cnt_o[0] = !in_i[0]; |
| assign empty_o = !in_i[0]; |
| |
| end else begin : gen_lzc |
| |
| localparam int unsigned NumLevels = $clog2(WIDTH); |
| |
| // pragma translate_off |
| initial begin |
| assert(WIDTH > 0) else $fatal(1, "input must be at least one bit wide"); |
| end |
| // pragma translate_on |
| |
| logic [WIDTH-1:0][NumLevels-1:0] index_lut; |
| logic [2**NumLevels-1:0] sel_nodes; |
| logic [2**NumLevels-1:0][NumLevels-1:0] index_nodes; |
| |
| logic [WIDTH-1:0] in_tmp; |
| |
| // reverse vector if required |
| always_comb begin : flip_vector |
| for (int unsigned i = 0; i < WIDTH; i++) begin |
| in_tmp[i] = (MODE) ? in_i[WIDTH-1-i] : in_i[i]; |
| end |
| end |
| |
| for (genvar j = 0; unsigned'(j) < WIDTH; j++) begin : g_index_lut |
| assign index_lut[j] = (NumLevels)'(unsigned'(j)); |
| end |
| |
| for (genvar level = 0; unsigned'(level) < NumLevels; level++) begin : g_levels |
| if (unsigned'(level) == NumLevels - 1) begin : g_last_level |
| for (genvar k = 0; k < 2 ** level; k++) begin : g_level |
| // if two successive indices are still in the vector... |
| if (unsigned'(k) * 2 < WIDTH - 1) begin : g_reduce |
| assign sel_nodes[2 ** level - 1 + k] = in_tmp[k * 2] | in_tmp[k * 2 + 1]; |
| assign index_nodes[2 ** level - 1 + k] = (in_tmp[k * 2] == 1'b1) |
| ? index_lut[k * 2] : |
| index_lut[k * 2 + 1]; |
| end |
| // if only the first index is still in the vector... |
| if (unsigned'(k) * 2 == WIDTH - 1) begin : g_base |
| assign sel_nodes[2 ** level - 1 + k] = in_tmp[k * 2]; |
| assign index_nodes[2 ** level - 1 + k] = index_lut[k * 2]; |
| end |
| // if index is out of range |
| if (unsigned'(k) * 2 > WIDTH - 1) begin : g_out_of_range |
| assign sel_nodes[2 ** level - 1 + k] = 1'b0; |
| assign index_nodes[2 ** level - 1 + k] = '0; |
| end |
| end |
| end else begin : g_not_last_level |
| for (genvar l = 0; l < 2 ** level; l++) begin : g_level |
| assign sel_nodes[2 ** level - 1 + l] = |
| sel_nodes[2 ** (level + 1) - 1 + l * 2] | sel_nodes[2 ** (level + 1) - 1 + l * 2 + 1]; |
| assign index_nodes[2 ** level - 1 + l] = (sel_nodes[2 ** (level + 1) - 1 + l * 2] == 1'b1) |
| ? index_nodes[2 ** (level + 1) - 1 + l * 2] : |
| index_nodes[2 ** (level + 1) - 1 + l * 2 + 1]; |
| end |
| end |
| end |
| |
| assign cnt_o = NumLevels > unsigned'(0) ? index_nodes[0] : {($clog2(WIDTH)) {1'b0}}; |
| assign empty_o = NumLevels > unsigned'(0) ? ~sel_nodes[0] : ~(|in_i); |
| |
| end : gen_lzc |
| |
| endmodule : lzc |