forked from cores/microwatt
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.
114 lines
3.4 KiB
VHDL
114 lines
3.4 KiB
VHDL
5 years ago
|
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;
|