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.
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;
|