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.
microwatt/control.vhdl

114 lines
3.4 KiB
VHDL

library ieee;
use ieee.std_logic_1164.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;
sgl_pipe_in : in std_ulogic;
stop_mark_in : in std_ulogic;
valid_out : out std_ulogic;
stall_out : out std_ulogic;
stopped_out : 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+1;
end record;
constant reg_internal_init : reg_internal_type := (state => IDLE, outstanding => 0);
signal r_int, rin_int : reg_internal_type := reg_internal_init;
begin
control0: process(clk)
begin
if rising_edge(clk) then
r_int <= rin_int;
end if;
end process;
control1 : process(all)
variable v_int : reg_internal_type;
variable valid_tmp : std_ulogic;
begin
v_int := r_int;
-- asynchronous
valid_tmp := valid_in and not flush_in;
stall_out <= '0';
if complete_in = '1' then
assert r_int.outstanding <= 1 report "Outstanding bad " & integer'image(r_int.outstanding) severity failure;
v_int.outstanding := r_int.outstanding - 1;
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 (flush_in = '0') and (valid_tmp = '1') and (sgl_pipe_in = '1') then
if v_int.outstanding /= 0 then
v_int.state := WAIT_FOR_PREV_TO_COMPLETE;
valid_tmp := '0';
stall_out <= '1';
else
-- send insn out and wait on it to complete
v_int.state := WAIT_FOR_CURR_TO_COMPLETE;
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
valid_tmp := '0';
stall_out <= '1';
end if;
when WAIT_FOR_CURR_TO_COMPLETE =>
if v_int.outstanding = 0 then
v_int.state := IDLE;
else
valid_tmp := '0';
stall_out <= '1';
end if;
end case;
-- track outstanding instructions
if valid_tmp = '1' then
v_int.outstanding := v_int.outstanding + 1;
end if;
if rst = '1' then
v_int.state := IDLE;
v_int.outstanding := 0;
stall_out <= '0';
end if;
-- update outputs
valid_out <= valid_tmp;
-- update registers
rin_int <= v_int;
end process;
end;