mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
control: Use a 1-hot encoding for bypass enables
Instead of creating a 2-bit encoded bypass selector, we now have a 4-bit encoding where bits 1 to 3 enable separate bypass sources, and bit 0 indicates if any bypass should be used. This results in slightly simpler logic and better timing. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
parent
52d8f28d03
commit
f6a839a86b
73
control.vhdl
73
control.vhdl
@ -45,9 +45,13 @@ entity control is
|
||||
valid_out : out std_ulogic;
|
||||
stopped_out : out std_ulogic;
|
||||
|
||||
gpr_bypass_a : out std_ulogic_vector(1 downto 0);
|
||||
gpr_bypass_b : out std_ulogic_vector(1 downto 0);
|
||||
gpr_bypass_c : out std_ulogic_vector(1 downto 0);
|
||||
-- Note on gpr_bypass_*: bits 1 to 3 are a 1-hot encoding of which
|
||||
-- bypass source we may possibly need to use; bit 0 is 1 if the bypass
|
||||
-- value should be used (i.e. any of bits 1-3 are 1 and the
|
||||
-- corresponding gpr_x_read_valid_in is also 1).
|
||||
gpr_bypass_a : out std_ulogic_vector(3 downto 0);
|
||||
gpr_bypass_b : out std_ulogic_vector(3 downto 0);
|
||||
gpr_bypass_c : out std_ulogic_vector(3 downto 0);
|
||||
cr_bypass : out std_ulogic_vector(1 downto 0);
|
||||
|
||||
instr_tag_out : out instr_tag_t
|
||||
@ -152,9 +156,9 @@ begin
|
||||
variable tag_s : instr_tag_t;
|
||||
variable tag_t : instr_tag_t;
|
||||
variable incr_tag : tag_number_t;
|
||||
variable byp_a : std_ulogic_vector(1 downto 0);
|
||||
variable byp_b : std_ulogic_vector(1 downto 0);
|
||||
variable byp_c : std_ulogic_vector(1 downto 0);
|
||||
variable byp_a : std_ulogic_vector(3 downto 0);
|
||||
variable byp_b : std_ulogic_vector(3 downto 0);
|
||||
variable byp_c : std_ulogic_vector(3 downto 0);
|
||||
variable tag_cr : instr_tag_t;
|
||||
variable byp_cr : std_ulogic_vector(1 downto 0);
|
||||
variable tag_ov : instr_tag_t;
|
||||
@ -163,57 +167,66 @@ 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.valid := '1';
|
||||
tag_a.tag := i;
|
||||
end if;
|
||||
end loop;
|
||||
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.valid := '1';
|
||||
tag_b.tag := i;
|
||||
end if;
|
||||
end loop;
|
||||
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.valid := '1';
|
||||
tag_c.tag := i;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
byp_a := "00";
|
||||
byp_a := "0000";
|
||||
if EX1_BYPASS and tag_match(execute_next_tag, tag_a) then
|
||||
byp_a := "01";
|
||||
elsif EX1_BYPASS and tag_match(execute2_next_tag, tag_a) then
|
||||
byp_a := "10";
|
||||
elsif tag_match(complete_in, tag_a) then
|
||||
byp_a := "11";
|
||||
byp_a(1) := '1';
|
||||
end if;
|
||||
byp_b := "00";
|
||||
if EX1_BYPASS and tag_match(execute2_next_tag, tag_a) then
|
||||
byp_a(2) := '1';
|
||||
end if;
|
||||
if tag_match(complete_in, tag_a) then
|
||||
byp_a(3) := '1';
|
||||
end if;
|
||||
byp_a(0) := gpr_a_read_valid_in and (byp_a(1) or byp_a(2) or byp_a(3));
|
||||
byp_b := "0000";
|
||||
if EX1_BYPASS and tag_match(execute_next_tag, tag_b) then
|
||||
byp_b := "01";
|
||||
elsif EX1_BYPASS and tag_match(execute2_next_tag, tag_b) then
|
||||
byp_b := "10";
|
||||
elsif tag_match(complete_in, tag_b) then
|
||||
byp_b := "11";
|
||||
byp_b(1) := '1';
|
||||
end if;
|
||||
byp_c := "00";
|
||||
if EX1_BYPASS and tag_match(execute2_next_tag, tag_b) then
|
||||
byp_b(2) := '1';
|
||||
end if;
|
||||
if tag_match(complete_in, tag_b) then
|
||||
byp_b(3) := '1';
|
||||
end if;
|
||||
byp_b(0) := gpr_b_read_valid_in and (byp_b(1) or byp_b(2) or byp_b(3));
|
||||
byp_c := "0000";
|
||||
if EX1_BYPASS and tag_match(execute_next_tag, tag_c) then
|
||||
byp_c := "01";
|
||||
elsif EX1_BYPASS and tag_match(execute2_next_tag, tag_c) then
|
||||
byp_c := "10";
|
||||
elsif tag_match(complete_in, tag_c) then
|
||||
byp_c := "11";
|
||||
byp_c(1) := '1';
|
||||
end if;
|
||||
if EX1_BYPASS and tag_match(execute2_next_tag, tag_c) then
|
||||
byp_c(2) := '1';
|
||||
end if;
|
||||
if tag_match(complete_in, tag_c) then
|
||||
byp_c(3) := '1';
|
||||
end if;
|
||||
byp_c(0) := gpr_c_read_valid_in and (byp_c(1) or byp_c(2) or byp_c(3));
|
||||
|
||||
gpr_bypass_a <= byp_a;
|
||||
gpr_bypass_b <= byp_b;
|
||||
gpr_bypass_c <= byp_c;
|
||||
|
||||
gpr_tag_stall <= (tag_a.valid and not (or (byp_a))) or
|
||||
(tag_b.valid and not (or (byp_b))) or
|
||||
(tag_c.valid and not (or (byp_c)));
|
||||
gpr_tag_stall <= (tag_a.valid and gpr_a_read_valid_in and not byp_a(0)) or
|
||||
(tag_b.valid and gpr_b_read_valid_in and not byp_b(0)) or
|
||||
(tag_c.valid and gpr_c_read_valid_in and not byp_c(0));
|
||||
|
||||
incr_tag := curr_tag;
|
||||
instr_tag.tag <= curr_tag;
|
||||
|
||||
98
decode2.vhdl
98
decode2.vhdl
@ -201,6 +201,23 @@ architecture behaviour of decode2 is
|
||||
end case;
|
||||
end;
|
||||
|
||||
function andor (mask_a : std_ulogic; val_a : std_ulogic_vector(63 downto 0);
|
||||
mask_b : std_ulogic; val_b : std_ulogic_vector(63 downto 0);
|
||||
mask_c : std_ulogic; val_c : std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
|
||||
variable t : std_ulogic_vector(63 downto 0) := (others => '0');
|
||||
begin
|
||||
if mask_a = '1' then
|
||||
t := val_a;
|
||||
end if;
|
||||
if mask_b = '1' then
|
||||
t := t or val_b;
|
||||
end if;
|
||||
if mask_c = '1' then
|
||||
t := t or val_c;
|
||||
end if;
|
||||
return t;
|
||||
end;
|
||||
|
||||
-- control signals that are derived from insn_type
|
||||
type mux_select_array_t is array(insn_type_t) of std_ulogic_vector(2 downto 0);
|
||||
|
||||
@ -269,15 +286,15 @@ architecture behaviour of decode2 is
|
||||
|
||||
signal gpr_a_read_valid : std_ulogic;
|
||||
signal gpr_a_read : gspr_index_t;
|
||||
signal gpr_a_bypass : std_ulogic_vector(1 downto 0);
|
||||
signal gpr_a_bypass : std_ulogic_vector(3 downto 0);
|
||||
|
||||
signal gpr_b_read_valid : std_ulogic;
|
||||
signal gpr_b_read : gspr_index_t;
|
||||
signal gpr_b_bypass : std_ulogic_vector(1 downto 0);
|
||||
signal gpr_b_bypass : std_ulogic_vector(3 downto 0);
|
||||
|
||||
signal gpr_c_read_valid : std_ulogic;
|
||||
signal gpr_c_read : gspr_index_t;
|
||||
signal gpr_c_bypass : std_ulogic_vector(1 downto 0);
|
||||
signal gpr_c_bypass : std_ulogic_vector(3 downto 0);
|
||||
|
||||
signal cr_read_valid : std_ulogic;
|
||||
signal cr_write_valid : std_ulogic;
|
||||
@ -694,53 +711,38 @@ begin
|
||||
ov_write_valid <= v.output_ov;
|
||||
|
||||
-- See if any of the operands can get their value via the bypass path.
|
||||
if dc2.busy = '0' or gpr_a_bypass /= "00" then
|
||||
case gpr_a_bypass is
|
||||
when "01" =>
|
||||
v.e.read_data1 := execute_bypass.data;
|
||||
when "10" =>
|
||||
v.e.read_data1 := execute2_bypass.data;
|
||||
when "11" =>
|
||||
v.e.read_data1 := writeback_bypass.data;
|
||||
when others =>
|
||||
if decoded_reg_a.reg_valid = '1' then
|
||||
v.e.read_data1 := r_in.read1_data;
|
||||
else
|
||||
v.e.read_data1 := decoded_reg_a.data;
|
||||
end if;
|
||||
end case;
|
||||
if gpr_a_bypass(0) = '1' then
|
||||
v.e.read_data1 := andor(gpr_a_bypass(1), execute_bypass.data,
|
||||
gpr_a_bypass(2), execute2_bypass.data,
|
||||
gpr_a_bypass(3), writeback_bypass.data);
|
||||
elsif dc2.busy = '0' then
|
||||
if decoded_reg_a.reg_valid = '1' then
|
||||
v.e.read_data1 := r_in.read1_data;
|
||||
else
|
||||
v.e.read_data1 := decoded_reg_a.data;
|
||||
end if;
|
||||
end if;
|
||||
if dc2.busy = '0' or gpr_b_bypass /= "00" then
|
||||
case gpr_b_bypass is
|
||||
when "01" =>
|
||||
v.e.read_data2 := execute_bypass.data;
|
||||
when "10" =>
|
||||
v.e.read_data2 := execute2_bypass.data;
|
||||
when "11" =>
|
||||
v.e.read_data2 := writeback_bypass.data;
|
||||
when others =>
|
||||
if decoded_reg_b.reg_valid = '1' then
|
||||
v.e.read_data2 := r_in.read2_data;
|
||||
else
|
||||
v.e.read_data2 := decoded_reg_b.data;
|
||||
end if;
|
||||
end case;
|
||||
if gpr_b_bypass(0) = '1' then
|
||||
v.e.read_data2 := andor(gpr_b_bypass(1), execute_bypass.data,
|
||||
gpr_b_bypass(2), execute2_bypass.data,
|
||||
gpr_b_bypass(3), writeback_bypass.data);
|
||||
elsif dc2.busy = '0' then
|
||||
if decoded_reg_b.reg_valid = '1' then
|
||||
v.e.read_data2 := r_in.read2_data;
|
||||
else
|
||||
v.e.read_data2 := decoded_reg_b.data;
|
||||
end if;
|
||||
end if;
|
||||
if dc2.busy = '0' or gpr_c_bypass /= "00" then
|
||||
case gpr_c_bypass is
|
||||
when "01" =>
|
||||
v.e.read_data3 := execute_bypass.data;
|
||||
when "10" =>
|
||||
v.e.read_data3 := execute2_bypass.data;
|
||||
when "11" =>
|
||||
v.e.read_data3 := writeback_bypass.data;
|
||||
when others =>
|
||||
if decoded_reg_c.reg_valid = '1' then
|
||||
v.e.read_data3 := r_in.read3_data;
|
||||
else
|
||||
v.e.read_data3 := decoded_reg_c.data;
|
||||
end if;
|
||||
end case;
|
||||
if gpr_c_bypass(0) = '1' then
|
||||
v.e.read_data3 := andor(gpr_c_bypass(1), execute_bypass.data,
|
||||
gpr_c_bypass(2), execute2_bypass.data,
|
||||
gpr_c_bypass(3), writeback_bypass.data);
|
||||
elsif dc2.busy = '0' then
|
||||
if decoded_reg_c.reg_valid = '1' then
|
||||
v.e.read_data3 := r_in.read3_data;
|
||||
else
|
||||
v.e.read_data3 := decoded_reg_c.data;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
case cr_bypass is
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user