Skip to content

Commit

Permalink
lzc: Handle degenerate case when WIDTH=1 (#57)
Browse files Browse the repository at this point in the history
* lzc: handle degenerate case when WIDTH=1
* lzc: Remove generate..endgenerate region
* lzc: Add retval to $fatal call
* lzc: Add changelog entry
  • Loading branch information
suehtamacv authored and zarubaf committed Dec 3, 2019
1 parent b86af02 commit b786dd2
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 48 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## Unreleased

### Fixed

- Handle degenerated `lzc` with `WIDTH == 1`

## 1.14.0 - 2019-10-08

### Added
Expand Down
107 changes: 59 additions & 48 deletions src/lzc.sv
Original file line number Diff line number Diff line change
Expand Up @@ -26,68 +26,79 @@
module lzc #(
/// The width of the input vector.
parameter int unsigned WIDTH = 2,
parameter bit MODE = 1'b0 // 0 -> trailing zero, 1 -> leading zero
parameter bit MODE = 1'b0, // 0 -> trailing zero, 1 -> leading zero
// Dependent parameters. Do not change!
parameter int unsigned CNT_WIDTH = WIDTH == 1 ? 1 : $clog2(WIDTH)
) (
input logic [WIDTH-1:0] in_i,
output logic [$clog2(WIDTH)-1:0] cnt_o,
output logic empty_o // asserted if all bits in in_i are zero
input logic [WIDTH-1:0] in_i,
output logic [CNT_WIDTH-1:0] cnt_o,
output logic empty_o // asserted if all bits in in_i are zero
);

localparam int unsigned NUM_LEVELS = $clog2(WIDTH);
if (WIDTH == 1) begin: gen_degenerate_lzc

// pragma translate_off
initial begin
assert(WIDTH > 0) else $fatal("input must be at least one bit wide");
end
// pragma translate_on
assign cnt_o[0] = !in_i[0];
assign empty_o = !in_i[0];

logic [WIDTH-1:0][NUM_LEVELS-1:0] index_lut;
logic [2**NUM_LEVELS-1:0] sel_nodes;
logic [2**NUM_LEVELS-1:0][NUM_LEVELS-1:0] index_nodes;
end else begin: gen_lzc

logic [WIDTH-1:0] in_tmp;
localparam int unsigned NUM_LEVELS = $clog2(WIDTH);

// 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];
// pragma translate_off
initial begin
assert(WIDTH > 0) else $fatal(1, "input must be at least one bit wide");
end
end
// pragma translate_on

for (genvar j = 0; unsigned'(j) < WIDTH; j++) begin : g_index_lut
assign index_lut[j] = NUM_LEVELS'(unsigned'(j));
end
logic [WIDTH-1:0][NUM_LEVELS-1:0] index_lut;
logic [2**NUM_LEVELS-1:0] sel_nodes;
logic [2**NUM_LEVELS-1:0][NUM_LEVELS-1:0] index_nodes;

for (genvar level = 0; unsigned'(level) < NUM_LEVELS; level++) begin : g_levels
if (unsigned'(level) == NUM_LEVELS-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
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
assign sel_nodes[2**level-1+k] = in_tmp[k*2];
assign index_nodes[2**level-1+k] = index_lut[k*2];
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] = NUM_LEVELS'(unsigned'(j));
end

for (genvar level = 0; unsigned'(level) < NUM_LEVELS; level++) begin : g_levels
if (unsigned'(level) == NUM_LEVELS-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
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
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
assign sel_nodes[2**level-1+k] = 1'b0;
assign index_nodes[2**level-1+k] = '0;
end
end
// if index is out of range
if (unsigned'(k) * 2 > WIDTH-1) begin
assign sel_nodes[2**level-1+k] = 1'b0;
assign index_nodes[2**level-1+k] = '0;
end else begin
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 else begin
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 = NUM_LEVELS > unsigned'(0) ? index_nodes[0] : {($clog2(WIDTH)){1'b0}};
assign empty_o = NUM_LEVELS > unsigned'(0) ? ~sel_nodes[0] : ~(|in_i);
assign cnt_o = NUM_LEVELS > unsigned'(0) ? index_nodes[0] : {($clog2(WIDTH)){1'b0}};
assign empty_o = NUM_LEVELS > unsigned'(0) ? ~sel_nodes[0] : ~(|in_i);

end : gen_lzc

endmodule : lzc

0 comments on commit b786dd2

Please sign in to comment.