Add Tercel PHY reset synchronization
[microwatt.git] / control.vhdl
index 4f67ad46f21893e52121ece2db54858e656a797e..34c35e28b0c8b548aefde29bc9cc0c88cf70ba2c 100644 (file)
@@ -6,14 +6,16 @@ use work.common.all;
 
 entity control is
     generic (
-        PIPELINE_DEPTH : natural := 2
+        EX1_BYPASS : boolean := true;
+        PIPELINE_DEPTH : natural := 3
         );
     port (
         clk                 : in std_ulogic;
         rst                 : in std_ulogic;
 
-        complete_in         : in std_ulogic;
+        complete_in         : in instr_tag_t;
         valid_in            : in std_ulogic;
+        repeated            : in std_ulogic;
         flush_in            : in std_ulogic;
        busy_in             : in std_ulogic;
         deferred            : in std_ulogic;
@@ -22,10 +24,6 @@ entity control is
 
         gpr_write_valid_in  : in std_ulogic;
         gpr_write_in        : in gspr_index_t;
-        gpr_bypassable      : in std_ulogic;
-
-        update_gpr_write_valid : in std_ulogic;
-        update_gpr_write_reg : in gspr_index_t;
 
         gpr_a_read_valid_in : in std_ulogic;
         gpr_a_read_in       : in gspr_index_t;
@@ -36,9 +34,11 @@ entity control is
         gpr_c_read_valid_in : in std_ulogic;
         gpr_c_read_in       : in gspr_index_t;
 
+        execute_next_tag    : in instr_tag_t;
+        execute_next_cr_tag : in instr_tag_t;
+
         cr_read_in          : in std_ulogic;
         cr_write_in         : in std_ulogic;
-        cr_bypassable       : in std_ulogic;
 
         valid_out           : out std_ulogic;
         stall_out           : out std_ulogic;
@@ -47,7 +47,9 @@ entity control is
         gpr_bypass_a        : out std_ulogic;
         gpr_bypass_b        : out std_ulogic;
         gpr_bypass_c        : out std_ulogic;
-        cr_bypass           : out std_ulogic
+        cr_bypass           : out std_ulogic;
+
+        instr_tag_out       : out instr_tag_t
         );
 end entity control;
 
@@ -62,119 +64,165 @@ architecture rtl of control is
 
     signal r_int, rin_int : reg_internal_type := reg_internal_init;
 
-    signal stall_a_out  : std_ulogic;
-    signal stall_b_out  : std_ulogic;
-    signal stall_c_out  : std_ulogic;
-    signal cr_stall_out : std_ulogic;
-
     signal gpr_write_valid : std_ulogic := '0';
     signal cr_write_valid  : std_ulogic := '0';
 
-begin
-    gpr_hazard0: entity work.gpr_hazard
-        generic map (
-            PIPELINE_DEPTH => PIPELINE_DEPTH
-            )
-        port map (
-            clk                => clk,
-            busy_in            => busy_in,
-           deferred           => deferred,
-            complete_in        => complete_in,
-            flush_in           => flush_in,
-            issuing            => valid_out,
-
-            gpr_write_valid_in => gpr_write_valid,
-            gpr_write_in       => gpr_write_in,
-            bypass_avail       => gpr_bypassable,
-            gpr_read_valid_in  => gpr_a_read_valid_in,
-            gpr_read_in        => gpr_a_read_in,
-
-            ugpr_write_valid   => update_gpr_write_valid,
-            ugpr_write_reg     => update_gpr_write_reg,
-
-            stall_out          => stall_a_out,
-            use_bypass         => gpr_bypass_a
-            );
-
-    gpr_hazard1: entity work.gpr_hazard
-        generic map (
-            PIPELINE_DEPTH => PIPELINE_DEPTH
-            )
-        port map (
-            clk                => clk,
-            busy_in            => busy_in,
-           deferred           => deferred,
-            complete_in        => complete_in,
-            flush_in           => flush_in,
-            issuing            => valid_out,
-
-            gpr_write_valid_in => gpr_write_valid,
-            gpr_write_in       => gpr_write_in,
-            bypass_avail       => gpr_bypassable,
-            gpr_read_valid_in  => gpr_b_read_valid_in,
-            gpr_read_in        => gpr_b_read_in,
-
-            ugpr_write_valid   => update_gpr_write_valid,
-            ugpr_write_reg     => update_gpr_write_reg,
-
-            stall_out          => stall_b_out,
-            use_bypass         => gpr_bypass_b
-            );
-
-    gpr_hazard2: entity work.gpr_hazard
-        generic map (
-            PIPELINE_DEPTH => PIPELINE_DEPTH
-            )
-        port map (
-            clk                => clk,
-            busy_in            => busy_in,
-           deferred           => deferred,
-            complete_in        => complete_in,
-            flush_in           => flush_in,
-            issuing            => valid_out,
-
-            gpr_write_valid_in => gpr_write_valid,
-            gpr_write_in       => gpr_write_in,
-            bypass_avail       => gpr_bypassable,
-            gpr_read_valid_in  => gpr_c_read_valid_in,
-            gpr_read_in        => gpr_c_read_in,
-
-            ugpr_write_valid   => update_gpr_write_valid,
-            ugpr_write_reg     => update_gpr_write_reg,
-
-            stall_out          => stall_c_out,
-            use_bypass         => gpr_bypass_c
-            );
-
-    cr_hazard0: entity work.cr_hazard
-        generic map (
-            PIPELINE_DEPTH => PIPELINE_DEPTH
-            )
-        port map (
-            clk                => clk,
-            busy_in            => busy_in,
-           deferred           => deferred,
-            complete_in        => complete_in,
-            flush_in           => flush_in,
-            issuing            => valid_out,
-
-            cr_read_in         => cr_read_in,
-            cr_write_in        => cr_write_valid,
-            bypassable         => cr_bypassable,
-
-            stall_out          => cr_stall_out,
-            use_bypass         => cr_bypass
-            );
+    type tag_register is record
+        wr_gpr : std_ulogic;
+        reg    : gspr_index_t;
+        recent : std_ulogic;
+        wr_cr  : std_ulogic;
+    end record;
 
+    type tag_regs_array is array(tag_number_t) of tag_register;
+    signal tag_regs : tag_regs_array;
+
+    signal instr_tag  : instr_tag_t;
+
+    signal gpr_tag_stall : std_ulogic;
+    signal cr_tag_stall  : std_ulogic;
+
+    signal curr_tag : tag_number_t;
+    signal next_tag : tag_number_t;
+
+    signal curr_cr_tag : tag_number_t;
+
+begin
     control0: process(clk)
     begin
         if rising_edge(clk) then
             assert rin_int.outstanding >= 0 and rin_int.outstanding <= (PIPELINE_DEPTH+1)
                 report "Outstanding bad " & integer'image(rin_int.outstanding) severity failure;
             r_int <= rin_int;
+            for i in tag_number_t loop
+                if rst = '1' or flush_in = '1' then
+                    tag_regs(i).wr_gpr <= '0';
+                    tag_regs(i).wr_cr <= '0';
+                else
+                    if complete_in.valid = '1' and i = complete_in.tag then
+                        tag_regs(i).wr_gpr <= '0';
+                        tag_regs(i).wr_cr <= '0';
+                        report "tag " & integer'image(i) & " not valid";
+                    end if;
+                    if gpr_write_valid = '1' and tag_regs(i).reg = gpr_write_in then
+                        tag_regs(i).recent <= '0';
+                        if tag_regs(i).recent = '1' and tag_regs(i).wr_gpr = '1' then
+                            report "tag " & integer'image(i) & " not recent";
+                        end if;
+                    end if;
+                    if instr_tag.valid = '1' and i = instr_tag.tag then
+                        tag_regs(i).wr_gpr <= gpr_write_valid;
+                        tag_regs(i).reg <= gpr_write_in;
+                        tag_regs(i).recent <= gpr_write_valid;
+                        tag_regs(i).wr_cr <= cr_write_valid;
+                        if gpr_write_valid = '1' then
+                            report "tag " & integer'image(i) & " valid for gpr " & to_hstring(gpr_write_in);
+                        end if;
+                    end if;
+                end if;
+            end loop;
+            if rst = '1' then
+                curr_tag <= 0;
+                curr_cr_tag <= 0;
+            else
+                curr_tag <= next_tag;
+                if cr_write_valid = '1' then
+                    curr_cr_tag <= instr_tag.tag;
+                end if;
+            end if;
         end if;
     end process;
 
+    control_hazards : process(all)
+        variable gpr_stall : std_ulogic;
+        variable tag_a : instr_tag_t;
+        variable tag_b : instr_tag_t;
+        variable tag_c : instr_tag_t;
+        variable tag_s : instr_tag_t;
+        variable tag_t : instr_tag_t;
+        variable incr_tag : tag_number_t;
+        variable byp_a : std_ulogic;
+        variable byp_b : std_ulogic;
+        variable byp_c : std_ulogic;
+        variable tag_cr : instr_tag_t;
+        variable byp_cr : std_ulogic;
+    begin
+        tag_a := instr_tag_init;
+        for i in tag_number_t loop
+            if tag_regs(i).wr_gpr = '1' and tag_regs(i).recent = '1' and tag_regs(i).reg = gpr_a_read_in then
+                tag_a.valid := gpr_a_read_valid_in;
+                tag_a.tag := i;
+            end if;
+        end loop;
+        if tag_match(tag_a, complete_in) then
+            tag_a.valid := '0';
+        end if;
+        tag_b := instr_tag_init;
+        for i in tag_number_t loop
+            if tag_regs(i).wr_gpr = '1' and tag_regs(i).recent = '1' and tag_regs(i).reg = gpr_b_read_in then
+                tag_b.valid := gpr_b_read_valid_in;
+                tag_b.tag := i;
+            end if;
+        end loop;
+        if tag_match(tag_b, complete_in) then
+            tag_b.valid := '0';
+        end if;
+        tag_c := instr_tag_init;
+        for i in tag_number_t loop
+            if tag_regs(i).wr_gpr = '1' and tag_regs(i).recent = '1' and tag_regs(i).reg = gpr_c_read_in then
+                tag_c.valid := gpr_c_read_valid_in;
+                tag_c.tag := i;
+            end if;
+        end loop;
+        if tag_match(tag_c, complete_in) then
+            tag_c.valid := '0';
+        end if;
+
+        byp_a := '0';
+        if EX1_BYPASS and tag_match(execute_next_tag, tag_a) then
+            byp_a := '1';
+        end if;
+        byp_b := '0';
+        if EX1_BYPASS and tag_match(execute_next_tag, tag_b) then
+            byp_b := '1';
+        end if;
+        byp_c := '0';
+        if EX1_BYPASS and tag_match(execute_next_tag, tag_c) then
+            byp_c := '1';
+        end if;
+
+        gpr_bypass_a <= byp_a;
+        gpr_bypass_b <= byp_b;
+        gpr_bypass_c <= byp_c;
+
+        gpr_tag_stall <= (tag_a.valid and not byp_a) or
+                         (tag_b.valid and not byp_b) or
+                         (tag_c.valid and not byp_c);
+
+        incr_tag := curr_tag;
+        instr_tag.tag <= curr_tag;
+        instr_tag.valid <= valid_out and not deferred;
+        if instr_tag.valid = '1' then
+            incr_tag := (curr_tag + 1) mod TAG_COUNT;
+        end if;
+        next_tag <= incr_tag;
+        instr_tag_out <= instr_tag;
+
+        -- CR hazards
+        tag_cr.tag := curr_cr_tag;
+        tag_cr.valid := cr_read_in and tag_regs(curr_cr_tag).wr_cr;
+        if tag_match(tag_cr, complete_in) then
+            tag_cr.valid := '0';
+        end if;
+        byp_cr := '0';
+        if EX1_BYPASS and tag_match(execute_next_cr_tag, tag_cr) then
+            byp_cr := '1';
+        end if;
+
+        cr_bypass <= byp_cr;
+        cr_tag_stall <= tag_cr.valid and not byp_cr;
+    end process;
+
     control1 : process(all)
         variable v_int : reg_internal_type;
         variable valid_tmp : std_ulogic;
@@ -187,11 +235,14 @@ begin
         stall_tmp := '0';
 
         if flush_in = '1' then
-            -- expect to see complete_in next cycle
-            v_int.outstanding := 1;
-        elsif complete_in = '1' then
+            v_int.outstanding := 0;
+        elsif complete_in.valid = '1' then
             v_int.outstanding := r_int.outstanding - 1;
         end if;
+        if r_int.outstanding >= PIPELINE_DEPTH + 1 then
+            valid_tmp := '0';
+            stall_tmp := '1';
+        end if;
 
         if rst = '1' then
             v_int := reg_internal_init;
@@ -218,8 +269,8 @@ begin
                             v_int.state := WAIT_FOR_CURR_TO_COMPLETE;
                         end if;
                     else
-                        -- let it go out if there are no GPR hazards
-                        stall_tmp := stall_a_out or stall_b_out or stall_c_out or cr_stall_out;
+                        -- let it go out if there are no GPR or CR hazards
+                        stall_tmp := gpr_tag_stall or cr_tag_stall;
                     end if;
                 end if;
 
@@ -245,8 +296,8 @@ begin
                                 v_int.state := WAIT_FOR_CURR_TO_COMPLETE;
                             end if;
                         else
-                            -- let it go out if there are no GPR hazards
-                            stall_tmp := stall_a_out or stall_b_out or stall_c_out or cr_stall_out;
+                            -- let it go out if there are no GPR or CR hazards
+                            stall_tmp := gpr_tag_stall or cr_tag_stall;
                         end if;
                     end if;
                 else
@@ -258,15 +309,11 @@ begin
             valid_tmp := '0';
         end if;
 
-        if valid_tmp = '1' then
-            if deferred = '0' then
-                v_int.outstanding := v_int.outstanding + 1;
-            end if;
-            gpr_write_valid <= gpr_write_valid_in;
-            cr_write_valid <= cr_write_in;
-        else
-            gpr_write_valid <= '0';
-            cr_write_valid <= '0';
+        gpr_write_valid <= gpr_write_valid_in and valid_tmp;
+        cr_write_valid <= cr_write_in and valid_tmp;
+
+        if valid_tmp = '1' and deferred = '0' then
+            v_int.outstanding := v_int.outstanding + 1;
         end if;
 
         -- update outputs