core: Implement CFAR register

This implements the CFAR SPR as a slow SPR stored in 'ctrl'.  Taken
branches and rfid update it to the address of the branch or rfid
instruction.

To simplify the logic, this makes rfid use the branch logic to
generate its redirect (requiring SRR0 to come in to execute1 on
the B input and SRR1 on the A input), and the masking of the bottom
2 bits of NIA is moved to fetch1.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/216/head
Paul Mackerras 4 years ago
parent 57604c1a6e
commit c2da82764f

@ -31,6 +31,7 @@ package common is
constant SPR_DEC : spr_num_t := 22;
constant SPR_SRR0 : spr_num_t := 26;
constant SPR_SRR1 : spr_num_t := 27;
constant SPR_CFAR : spr_num_t := 28;
constant SPR_HSRR0 : spr_num_t := 314;
constant SPR_HSRR1 : spr_num_t := 315;
constant SPR_SPRG0 : spr_num_t := 272;
@ -94,6 +95,7 @@ package common is
tb: std_ulogic_vector(63 downto 0);
dec: std_ulogic_vector(63 downto 0);
msr: std_ulogic_vector(63 downto 0);
cfar: std_ulogic_vector(63 downto 0);
irq_state : irq_state_t;
irq_nia: std_ulogic_vector(63 downto 0);
srr1: std_ulogic_vector(63 downto 0);

@ -473,8 +473,8 @@ begin
end if;
else
-- Could be OP_RFID
v.ispr1 := fast_spr_num(SPR_SRR0);
v.ispr2 := fast_spr_num(SPR_SRR1);
v.ispr1 := fast_spr_num(SPR_SRR1);
v.ispr2 := fast_spr_num(SPR_SRR0);
end if;

elsif majorop = "011110" then

@ -652,26 +652,27 @@ begin
result_en := '1';
v.e.write_reg := fast_spr_num(SPR_CTR);
end if;
if ppc_bc_taken(bo, bi, e_in.cr, a_in) = '1' then
f_out.redirect <= '1';
f_out.redirect_nia <= b_in(63 downto 2) & "00";
end if;
is_branch := '1';
taken_branch := ppc_bc_taken(bo, bi, e_in.cr, a_in);
abs_branch := '1';

when OP_RFID =>
f_out.redirect <= '1';
f_out.virt_mode <= b_in(MSR_IR) or b_in(MSR_PR);
f_out.priv_mode <= not b_in(MSR_PR);
f_out.redirect_nia <= a_in(63 downto 2) & "00"; -- srr0
f_out.virt_mode <= a_in(MSR_IR) or a_in(MSR_PR);
f_out.priv_mode <= not a_in(MSR_PR);
-- Can't use msr_copy here because the partial function MSR
-- bits should be left unchanged, not zeroed.
ctrl_tmp.msr(63 downto 31) <= b_in(63 downto 31);
ctrl_tmp.msr(26 downto 22) <= b_in(26 downto 22);
ctrl_tmp.msr(15 downto 0) <= b_in(15 downto 0);
if b_in(MSR_PR) = '1' then
ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31);
ctrl_tmp.msr(26 downto 22) <= a_in(26 downto 22);
ctrl_tmp.msr(15 downto 0) <= a_in(15 downto 0);
if a_in(MSR_PR) = '1' then
ctrl_tmp.msr(MSR_EE) <= '1';
ctrl_tmp.msr(MSR_IR) <= '1';
ctrl_tmp.msr(MSR_DR) <= '1';
end if;
-- mark this as a branch so CFAR gets updated
is_branch := '1';
taken_branch := '1';
abs_branch := '1';

when OP_CNTZ =>
v.e.valid := '0';
@ -757,6 +758,8 @@ begin
spr_val(31 downto 0) := ctrl.tb(63 downto 32);
when SPR_DEC =>
spr_val := ctrl.dec;
when SPR_CFAR =>
spr_val := ctrl.cfar;
when 724 => -- LOG_ADDR SPR
spr_val := log_wr_addr & r.log_addr_spr;
when 725 => -- LOG_DATA SPR
@ -879,9 +882,9 @@ begin
v.e.rc := e_in.rc and valid_in;

-- Mispredicted branches cause a redirect
if is_branch = '1' and taken_branch /= e_in.br_pred then
f_out.redirect <= '1';
if is_branch = '1' then
if taken_branch = '1' then
ctrl_tmp.cfar <= e_in.nia;
if abs_branch = '1' then
f_out.redirect_nia <= b_in;
else
@ -890,6 +893,9 @@ begin
else
f_out.redirect_nia <= next_nia;
end if;
if taken_branch /= e_in.br_pred then
f_out.redirect <= '1';
end if;
end if;

-- Update LR on the next cycle after a branch link

@ -83,11 +83,11 @@ begin
v.priv_mode := '1';
v_int.stop_state := RUNNING;
elsif e_in.redirect = '1' then
v.nia := e_in.redirect_nia;
v.nia := e_in.redirect_nia(63 downto 2) & "00";
v.virt_mode := e_in.virt_mode;
v.priv_mode := e_in.priv_mode;
elsif d_in.redirect = '1' then
v.nia := d_in.redirect_nia;
v.nia := d_in.redirect_nia(63 downto 2) & "00";
elsif stall_in = '0' then

-- For debug stop/step to work properly we need a little bit of

Loading…
Cancel
Save