You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			280 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			VHDL
		
	
			
		
		
	
	
			280 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			VHDL
		
	
| library ieee;
 | |
| use ieee.std_logic_1164.all;
 | |
| 
 | |
| library work;
 | |
| use work.common.all;
 | |
| 
 | |
| entity control is
 | |
|     generic (
 | |
|         PIPELINE_DEPTH : natural := 2
 | |
|         );
 | |
|     port (
 | |
|         clk                 : in std_ulogic;
 | |
|         rst                 : in std_ulogic;
 | |
| 
 | |
|         complete_in         : in std_ulogic;
 | |
|         valid_in            : in std_ulogic;
 | |
|         flush_in            : in std_ulogic;
 | |
| 	busy_in             : in std_ulogic;
 | |
|         deferred            : in std_ulogic;
 | |
|         sgl_pipe_in         : in std_ulogic;
 | |
|         stop_mark_in        : in std_ulogic;
 | |
| 
 | |
|         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;
 | |
| 
 | |
|         gpr_b_read_valid_in : in std_ulogic;
 | |
|         gpr_b_read_in       : in gspr_index_t;
 | |
| 
 | |
|         gpr_c_read_valid_in : in std_ulogic;
 | |
|         gpr_c_read_in       : in gspr_index_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;
 | |
|         stopped_out         : out std_ulogic;
 | |
| 
 | |
|         gpr_bypass_a        : out std_ulogic;
 | |
|         gpr_bypass_b        : out std_ulogic;
 | |
|         gpr_bypass_c        : out std_ulogic;
 | |
|         cr_bypass           : out std_ulogic
 | |
|         );
 | |
| end entity control;
 | |
| 
 | |
| architecture rtl of control is
 | |
|     type state_type is (IDLE, WAIT_FOR_PREV_TO_COMPLETE, WAIT_FOR_CURR_TO_COMPLETE);
 | |
| 
 | |
|     type reg_internal_type is record
 | |
|         state : state_type;
 | |
|         outstanding : integer range -1 to PIPELINE_DEPTH+2;
 | |
|     end record;
 | |
|     constant reg_internal_init : reg_internal_type := (state => IDLE, outstanding => 0);
 | |
| 
 | |
|     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
 | |
|             );
 | |
| 
 | |
|     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;
 | |
|         end if;
 | |
|     end process;
 | |
| 
 | |
|     control1 : process(all)
 | |
|         variable v_int : reg_internal_type;
 | |
|         variable valid_tmp : std_ulogic;
 | |
|         variable stall_tmp : std_ulogic;
 | |
|     begin
 | |
|         v_int := r_int;
 | |
| 
 | |
|         -- asynchronous
 | |
|         valid_tmp := valid_in and not flush_in;
 | |
|         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 := r_int.outstanding - 1;
 | |
|         end if;
 | |
| 
 | |
|         if rst = '1' then
 | |
|             v_int := reg_internal_init;
 | |
|             valid_tmp := '0';
 | |
|         end if;
 | |
| 
 | |
|         -- Handle debugger stop
 | |
|         stopped_out <= '0';
 | |
|         if stop_mark_in = '1' and v_int.outstanding = 0 then
 | |
|             stopped_out <= '1';
 | |
|         end if;
 | |
| 
 | |
|         -- state machine to handle instructions that must be single
 | |
|         -- through the pipeline.
 | |
|         case r_int.state is
 | |
|             when IDLE =>
 | |
|                 if valid_tmp = '1' then
 | |
|                     if (sgl_pipe_in = '1') then
 | |
|                         if v_int.outstanding /= 0 then
 | |
|                             v_int.state := WAIT_FOR_PREV_TO_COMPLETE;
 | |
|                             stall_tmp := '1';
 | |
|                         else
 | |
|                             -- send insn out and wait on it to complete
 | |
|                             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;
 | |
|                     end if;
 | |
|                 end if;
 | |
| 
 | |
|             when WAIT_FOR_PREV_TO_COMPLETE =>
 | |
|                 if v_int.outstanding = 0 then
 | |
|                     -- send insn out and wait on it to complete
 | |
|                     v_int.state := WAIT_FOR_CURR_TO_COMPLETE;
 | |
|                 else
 | |
|                     stall_tmp := '1';
 | |
|                 end if;
 | |
| 
 | |
|             when WAIT_FOR_CURR_TO_COMPLETE =>
 | |
|                 if v_int.outstanding = 0 then
 | |
|                     v_int.state := IDLE;
 | |
|                     -- XXX Don't replicate this
 | |
|                     if valid_tmp = '1' then
 | |
|                         if (sgl_pipe_in = '1') then
 | |
|                             if v_int.outstanding /= 0 then
 | |
|                                 v_int.state := WAIT_FOR_PREV_TO_COMPLETE;
 | |
|                                 stall_tmp := '1';
 | |
|                             else
 | |
|                                 -- send insn out and wait on it to complete
 | |
|                                 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;
 | |
|                         end if;
 | |
|                     end if;
 | |
|                 else
 | |
|                     stall_tmp := '1';
 | |
|                 end if;
 | |
|         end case;
 | |
| 
 | |
|         if stall_tmp = '1' then
 | |
|             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';
 | |
|         end if;
 | |
| 
 | |
|         -- update outputs
 | |
|         valid_out <= valid_tmp;
 | |
|         stall_out <= stall_tmp or deferred;
 | |
| 
 | |
|         -- update registers
 | |
|         rin_int <= v_int;
 | |
|     end process;
 | |
| end;
 |