end entity zero_counter;
architecture behaviour of zero_counter is
- type intermediate_result is record
- v16: std_ulogic_vector(15 downto 0);
- sel_hi: std_ulogic_vector(1 downto 0);
- is_32bit: std_ulogic;
- count_right: std_ulogic;
- end record;
-
- signal r, r_in : intermediate_result;
+ -- Reverse the order of bits in a word
+ function bit_reverse(a: std_ulogic_vector) return std_ulogic_vector is
+ variable ret: std_ulogic_vector(a'left downto a'right);
+ begin
+ for i in a'right to a'left loop
+ ret(a'left + a'right - i) := a(i);
+ end loop;
+ return ret;
+ end;
- -- Return the index of the leftmost or rightmost 1 in a set of 4 bits.
- -- Assumes v is not "0000"; if it is, return (right ? "11" : "00").
- function encoder(v: std_ulogic_vector(3 downto 0); right: std_ulogic) return std_ulogic_vector is
+ -- If there is only one bit set in a doubleword, return its bit number
+ -- (counting from the right). Each bit of the result is obtained by
+ -- ORing together 32 bits of the input:
+ -- bit 0 = a[1] or a[3] or a[5] or ...
+ -- bit 1 = a[2] or a[3] or a[6] or a[7] or ...
+ -- bit 2 = a[4..7] or a[12..15] or ...
+ -- bit 5 = a[32..63] ORed together
+ function bit_number(a: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
+ variable ret: std_ulogic_vector(5 downto 0);
+ variable stride: natural;
+ variable bit: std_ulogic;
+ variable k: natural;
begin
- if right = '0' then
- if v(3) = '1' then
- return "11";
- elsif v(2) = '1' then
- return "10";
- elsif v(1) = '1' then
- return "01";
- else
- return "00";
- end if;
- else
- if v(0) = '1' then
- return "00";
- elsif v(1) = '1' then
- return "01";
- elsif v(2) = '1' then
- return "10";
- else
- return "11";
- end if;
- end if;
+ stride := 2;
+ for i in 0 to 5 loop
+ bit := '0';
+ for j in 0 to (64 / stride) - 1 loop
+ k := j * stride;
+ bit := bit or (or a(k + stride - 1 downto k + (stride / 2)));
+ end loop;
+ ret(i) := bit;
+ stride := stride * 2;
+ end loop;
+ return ret;
end;
+ signal inp : std_ulogic_vector(63 downto 0);
+ signal sum : std_ulogic_vector(64 downto 0);
+ signal msb_r : std_ulogic;
+ signal onehot : std_ulogic_vector(63 downto 0);
+ signal onehot_r : std_ulogic_vector(63 downto 0);
+ signal bitnum : std_ulogic_vector(5 downto 0);
+
begin
- zerocounter_0: process(clk)
+ countzero_r: process(clk)
begin
- if rising_edge(clk) then
- r <= r_in;
+ if rising_edge(clk) then
+ msb_r <= sum(64);
+ onehot_r <= onehot;
end if;
end process;
- zerocounter_1: process(all)
- variable v: intermediate_result;
- variable y, z: std_ulogic_vector(3 downto 0);
- variable sel: std_ulogic_vector(5 downto 0);
- variable v4: std_ulogic_vector(3 downto 0);
-
+ countzero: process(all)
begin
- -- Test 4 groups of 16 bits each.
- -- The top 2 groups are considered to be zero in 32-bit mode.
- z(0) := or (rs(15 downto 0));
- z(1) := or (rs(31 downto 16));
- z(2) := or (rs(47 downto 32));
- z(3) := or (rs(63 downto 48));
if is_32bit = '0' then
- v.sel_hi := encoder(z, count_right);
+ if count_right = '0' then
+ inp <= bit_reverse(rs);
+ else
+ inp <= rs;
+ end if;
else
- v.sel_hi(1) := '0';
+ inp(63 downto 32) <= x"FFFFFFFF";
if count_right = '0' then
- v.sel_hi(0) := z(1);
+ inp(31 downto 0) <= bit_reverse(rs(31 downto 0));
else
- v.sel_hi(0) := not z(0);
+ inp(31 downto 0) <= rs(31 downto 0);
end if;
end if;
- -- Select the leftmost/rightmost non-zero group of 16 bits
- case v.sel_hi is
- when "00" =>
- v.v16 := rs(15 downto 0);
- when "01" =>
- v.v16 := rs(31 downto 16);
- when "10" =>
- v.v16 := rs(47 downto 32);
- when others =>
- v.v16 := rs(63 downto 48);
- end case;
-
- -- Latch this and do the rest in the next cycle, for the sake of timing
- v.is_32bit := is_32bit;
- v.count_right := count_right;
- r_in <= v;
- sel(5 downto 4) := r.sel_hi;
-
- -- Test 4 groups of 4 bits
- y(0) := or (r.v16(3 downto 0));
- y(1) := or (r.v16(7 downto 4));
- y(2) := or (r.v16(11 downto 8));
- y(3) := or (r.v16(15 downto 12));
- sel(3 downto 2) := encoder(y, r.count_right);
-
- -- Select the leftmost/rightmost non-zero group of 4 bits
- case sel(3 downto 2) is
- when "00" =>
- v4 := r.v16(3 downto 0);
- when "01" =>
- v4 := r.v16(7 downto 4);
- when "10" =>
- v4 := r.v16(11 downto 8);
- when others =>
- v4 := r.v16(15 downto 12);
- end case;
-
- sel(1 downto 0) := encoder(v4, r.count_right);
+ sum <= std_ulogic_vector(unsigned('0' & not inp) + 1);
+ onehot <= sum(63 downto 0) and inp;
- -- sel is now the index of the leftmost/rightmost 1 bit in rs
- if v4 = "0000" then
- -- operand is zero, return 32 for 32-bit, else 64
- result <= x"00000000000000" & '0' & not r.is_32bit & r.is_32bit & "00000";
- elsif r.count_right = '0' then
- -- return (63 - sel), trimmed to 5 bits in 32-bit mode
- result <= x"00000000000000" & "00" & (not sel(5) and not r.is_32bit) & not sel(4 downto 0);
- else
- result <= x"00000000000000" & "00" & sel;
- end if;
+ -- The following occurs after a clock edge
+ bitnum <= bit_number(onehot_r);
+ result <= x"00000000000000" & "0" & msb_r & bitnum;
end process;
end behaviour;