Add Tercel PHY reset synchronization
[microwatt.git] / countzero.vhdl
index 50e6ead2a5a7e6694f2f59bde1e0a3eef898655a..b46f10863138cd02035893e7f0949c599bc16cab 100644 (file)
@@ -3,6 +3,7 @@ use ieee.std_logic_1164.all;
 use ieee.numeric_std.all;
 
 library work;
+use work.helpers.all;
 
 entity zero_counter is
     port (
@@ -15,123 +16,45 @@ entity zero_counter is
 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;
-
-    -- 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
-    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;
-    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;