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_DEC : spr_num_t := 22;
constant SPR_SRR0 : spr_num_t := 26; constant SPR_SRR0 : spr_num_t := 26;
constant SPR_SRR1 : spr_num_t := 27; constant SPR_SRR1 : spr_num_t := 27;
constant SPR_CFAR : spr_num_t := 28;
constant SPR_HSRR0 : spr_num_t := 314; constant SPR_HSRR0 : spr_num_t := 314;
constant SPR_HSRR1 : spr_num_t := 315; constant SPR_HSRR1 : spr_num_t := 315;
constant SPR_SPRG0 : spr_num_t := 272; constant SPR_SPRG0 : spr_num_t := 272;
@ -94,6 +95,7 @@ package common is
tb: std_ulogic_vector(63 downto 0); tb: std_ulogic_vector(63 downto 0);
dec: std_ulogic_vector(63 downto 0); dec: std_ulogic_vector(63 downto 0);
msr: 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_state : irq_state_t;
irq_nia: std_ulogic_vector(63 downto 0); irq_nia: std_ulogic_vector(63 downto 0);
srr1: std_ulogic_vector(63 downto 0); srr1: std_ulogic_vector(63 downto 0);

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


elsif majorop = "011110" then elsif majorop = "011110" then

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


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


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


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


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

@ -83,11 +83,11 @@ begin
v.priv_mode := '1'; v.priv_mode := '1';
v_int.stop_state := RUNNING; v_int.stop_state := RUNNING;
elsif e_in.redirect = '1' then 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.virt_mode := e_in.virt_mode;
v.priv_mode := e_in.priv_mode; v.priv_mode := e_in.priv_mode;
elsif d_in.redirect = '1' then 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 elsif stall_in = '0' then


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

Loading…
Cancel
Save