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;
- stall_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;
gpr_a_read_valid_in : in std_ulogic;
gpr_a_read_in : in gspr_index_t;
gpr_b_read_in : in gspr_index_t;
gpr_c_read_valid_in : in std_ulogic;
- gpr_c_read_in : in gpr_index_t;
+ 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;
gpr_bypass_a : out std_ulogic;
gpr_bypass_b : out std_ulogic;
- gpr_bypass_c : out std_ulogic
+ gpr_bypass_c : out std_ulogic;
+ cr_bypass : out std_ulogic;
+
+ instr_tag_out : out instr_tag_t
);
end entity control;
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';
- signal gpr_c_read_in_fmt : std_ulogic_vector(5 downto 0);
-begin
- gpr_hazard0: entity work.gpr_hazard
- generic map (
- PIPELINE_DEPTH => PIPELINE_DEPTH
- )
- port map (
- clk => clk,
- stall_in => stall_in,
-
- 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,
-
- 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,
- stall_in => stall_in,
-
- 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,
-
- stall_out => stall_b_out,
- use_bypass => gpr_bypass_b
- );
-
- gpr_c_read_in_fmt <= "0" & gpr_c_read_in;
-
- gpr_hazard2: entity work.gpr_hazard
- generic map (
- PIPELINE_DEPTH => PIPELINE_DEPTH
- )
- port map (
- clk => clk,
- stall_in => stall_in,
-
- 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_fmt,
-
- 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,
- stall_in => stall_in,
-
- cr_read_in => cr_read_in,
- cr_write_in => cr_write_valid,
-
- stall_out => cr_stall_out
- );
+ 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 r_int.outstanding >= 0 and r_int.outstanding <= (PIPELINE_DEPTH+1) report "Outstanding bad " & integer'image(r_int.outstanding) severity failure;
+ 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)
v_int := r_int;
-- asynchronous
- valid_tmp := valid_in and not flush_in and not stall_in;
- stall_tmp := stall_in;
+ valid_tmp := valid_in and not flush_in;
+ stall_tmp := '0';
- if complete_in = '1' then
+ if flush_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;
+ valid_tmp := '0';
+ end if;
-- Handle debugger stop
stopped_out <= '0';
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;
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
valid_tmp := '0';
end if;
- if valid_tmp = '1' then
- v_int.outstanding := v_int.outstanding + 1;
- gpr_write_valid <= gpr_write_valid_in;
- cr_write_valid <= cr_write_in;
- else
- gpr_write_valid <= '0';
- cr_write_valid <= '0';
- end if;
+ gpr_write_valid <= gpr_write_valid_in and valid_tmp;
+ cr_write_valid <= cr_write_in and valid_tmp;
- if rst = '1' then
- v_int.state := IDLE;
- v_int.outstanding := 0;
- stall_tmp := '0';
+ if valid_tmp = '1' and deferred = '0' then
+ v_int.outstanding := v_int.outstanding + 1;
end if;
-- update outputs
valid_out <= valid_tmp;
- stall_out <= stall_tmp;
+ stall_out <= stall_tmp or deferred;
-- update registers
rin_int <= v_int;