From c2da82764f746745ab00d75bba9dd66b4c40c98d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 15 Jun 2020 17:45:55 +1000 Subject: [PATCH] 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 --- common.vhdl | 2 ++ decode1.vhdl | 4 ++-- execute1.vhdl | 34 ++++++++++++++++++++-------------- fetch1.vhdl | 4 ++-- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/common.vhdl b/common.vhdl index d376ac3..15c5c2a 100644 --- a/common.vhdl +++ b/common.vhdl @@ -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); diff --git a/decode1.vhdl b/decode1.vhdl index 2060e64..d215e7e 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -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 diff --git a/execute1.vhdl b/execute1.vhdl index c585f78..0da059a 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -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 diff --git a/fetch1.vhdl b/fetch1.vhdl index 0d9c6f7..a56f33d 100644 --- a/fetch1.vhdl +++ b/fetch1.vhdl @@ -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