diff --git a/common.vhdl b/common.vhdl index b92b87a..4843c3d 100644 --- a/common.vhdl +++ b/common.vhdl @@ -56,6 +56,7 @@ package common is constant SPR_HSPRG1 : spr_num_t := 305; constant SPR_PID : spr_num_t := 48; constant SPR_PTCR : spr_num_t := 464; + constant SPR_LPCR : spr_num_t := 318; constant SPR_PVR : spr_num_t := 287; constant SPR_FSCR : spr_num_t := 153; constant SPR_HFSCR : spr_num_t := 190; @@ -189,6 +190,7 @@ package common is constant SPRSEL_LOGD : spr_selector := 4x"5"; constant SPRSEL_CFAR : spr_selector := 4x"6"; constant SPRSEL_FSCR : spr_selector := 4x"7"; + constant SPRSEL_LPCR : spr_selector := 4x"8"; constant SPRSEL_HEIR : spr_selector := 4x"9"; constant SPRSEL_CTRL : spr_selector := 4x"a"; constant SPRSEL_DSCR : spr_selector := 4x"b"; @@ -235,6 +237,15 @@ package common is constant FPSCR_NI : integer := 63 - 61; constant FPSCR_RN : integer := 63 - 63; + -- LPCR bit numbers + constant LPCR_HAIL : integer := 63 - 37; + constant LPCR_UPRT : integer := 63 - 41; + constant LPCR_HR : integer := 63 - 43; + constant LPCR_LD : integer := 63 - 46; + constant LPCR_HEIC : integer := 63 - 59; + constant LPCR_LPES : integer := 63 - 60; + constant LPCR_HVICE : integer := 63 - 62; + -- Real addresses -- REAL_ADDR_BITS is the number of real address bits that we store constant REAL_ADDR_BITS : positive := 56; @@ -301,6 +312,11 @@ package common is dexcr_pro: aspect_bits_t; hdexcr_hyp: aspect_bits_t; hdexcr_enf: aspect_bits_t; + lpcr_hail: std_ulogic; + lpcr_ld: std_ulogic; + lpcr_heic: std_ulogic; + lpcr_lpes: std_ulogic; + lpcr_hvice: std_ulogic; end record; constant ctrl_t_init : ctrl_t := (wait_state => '0', run => '1', xer_low => 18x"0", @@ -308,6 +324,8 @@ package common is dscr => (others => '0'), dexcr_pnh => aspect_bits_init, dexcr_pro => aspect_bits_init, hdexcr_hyp => aspect_bits_init, hdexcr_enf => aspect_bits_init, + lpcr_hail => '0', lpcr_ld => '1', lpcr_heic => '0', + lpcr_lpes => '0', lpcr_hvice => '0', others => (others => '0')); type timebase_ctrl is record @@ -778,6 +796,7 @@ package common is write_xerc_enable : std_ulogic; xerc : xer_common_t; interrupt : std_ulogic; + alt_intr : std_ulogic; hv_intr : std_ulogic; is_scv : std_ulogic; intr_vec : intr_vector_t; @@ -788,7 +807,6 @@ package common is br_taken: std_ulogic; abs_br: std_ulogic; srr1: std_ulogic_vector(15 downto 0); - msr: std_ulogic_vector(63 downto 0); end record; constant Execute1ToWritebackInit : Execute1ToWritebackType := (valid => '0', instr_tag => instr_tag_init, rc => '0', mode_32bit => '0', @@ -796,11 +814,11 @@ package common is write_xerc_enable => '0', xerc => xerc_init, write_data => (others => '0'), write_cr_mask => (others => '0'), write_cr_data => (others => '0'), write_reg => (others => '0'), - interrupt => '0', hv_intr => '0', is_scv => '0', intr_vec => 0, + interrupt => '0', alt_intr => '0', hv_intr => '0', is_scv => '0', intr_vec => 0, redirect => '0', redir_mode => "0000", last_nia => (others => '0'), br_last => '0', br_taken => '0', abs_br => '0', - srr1 => (others => '0'), msr => (others => '0')); + srr1 => (others => '0')); type Execute1ToFPUType is record valid : std_ulogic; @@ -885,13 +903,14 @@ package common is br_last : std_ulogic; br_taken : std_ulogic; interrupt : std_ulogic; - intr_vec : std_ulogic_vector(16 downto 0); + alt_intr : std_ulogic; + intr_vec : std_ulogic_vector(63 downto 0); end record; constant WritebackToFetch1Init : WritebackToFetch1Type := (redirect => '0', virt_mode => '0', priv_mode => '0', big_endian => '0', mode_32bit => '0', redirect_nia => (others => '0'), br_last => '0', br_taken => '0', br_nia => (others => '0'), - interrupt => '0', intr_vec => 17x"0"); + interrupt => '0', alt_intr => '0', intr_vec => 64x"0"); type WritebackToRegisterFileType is record write_reg : gspr_index_t; @@ -917,6 +936,7 @@ package common is intr : std_ulogic; hv_intr : std_ulogic; scv_int : std_ulogic; + alt_int : std_ulogic; srr1 : std_ulogic_vector(15 downto 0); end record; diff --git a/core_debug.vhdl b/core_debug.vhdl index e839832..b1abe83 100644 --- a/core_debug.vhdl +++ b/core_debug.vhdl @@ -327,6 +327,9 @@ begin when 5x"0e" => isram := '0'; sel := SPRSEL_FSCR; + when 5x"0f" => + isram := '0'; + sel := SPRSEL_LPCR; when 5x"10" => isram := '0'; sel := SPRSEL_HEIR; diff --git a/decode1.vhdl b/decode1.vhdl index c3f215d..c684d72 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -490,6 +490,8 @@ architecture behaviour of decode1 is i.sel := SPRSEL_XER; when SPR_FSCR => i.sel := SPRSEL_FSCR; + when SPR_LPCR => + i.sel := SPRSEL_LPCR; when SPR_HEIR => i.sel := SPRSEL_HEIR; when SPR_CTRL => diff --git a/execute1.vhdl b/execute1.vhdl index cea2f37..fcf1df7 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -92,6 +92,7 @@ architecture behaviour of execute1 is mult_32s : std_ulogic; write_fscr : std_ulogic; write_ic : std_ulogic; + write_lpcr : std_ulogic; write_heir : std_ulogic; set_heir : std_ulogic; write_ctrl : std_ulogic; @@ -210,6 +211,7 @@ architecture behaviour of execute1 is signal valid_in : std_ulogic; signal ctrl: ctrl_t := ctrl_t_init; signal ctrl_tmp: ctrl_t := ctrl_t_init; + signal dec_sign: std_ulogic; signal rotator_result: std_ulogic_vector(63 downto 0); signal rotator_carry: std_ulogic; signal logical_result: std_ulogic_vector(63 downto 0); @@ -408,6 +410,20 @@ architecture behaviour of execute1 is return ret; end; + function assemble_lpcr(c: ctrl_t) return std_ulogic_vector is + variable ret : std_ulogic_vector(63 downto 0); + begin + ret := (others => '0'); + ret(LPCR_HAIL) := c.lpcr_hail; + ret(LPCR_UPRT) := '1'; + ret(LPCR_HR) := '1'; + ret(LPCR_LD) := c.lpcr_ld; + ret(LPCR_HEIC) := c.lpcr_heic; + ret(LPCR_LPES) := c.lpcr_lpes; + ret(LPCR_HVICE) := c.lpcr_hvice; + return ret; + end; + function assemble_ctrl(c: ctrl_t; msrpr: std_ulogic) return std_ulogic_vector is variable ret : std_ulogic_vector(63 downto 0); begin @@ -443,6 +459,15 @@ architecture behaviour of execute1 is return ret; end; + function assemble_dec(c: ctrl_t) return std_ulogic_vector is + begin + if c.lpcr_ld = '1' then + return c.dec; + else + return 32x"0" & c.dec(31 downto 0); + end if; + end; + -- Tell vivado to keep the hierarchy for the random module so that the -- net names in the xdc file match. attribute keep_hierarchy : string; @@ -582,6 +607,8 @@ begin tb_next <= thi & tlo; end process; + dec_sign <= (ctrl.dec(63) and ctrl.lpcr_ld) or (ctrl.dec(31) and not ctrl.lpcr_ld); + dbg_ctrl_out <= ctrl; log_rd_addr <= ex2.log_addr_spr; @@ -782,6 +809,8 @@ begin case dbg_spr_addr(3 downto 0) is when SPRSEL_FSCR => dbg_spr_data <= assemble_fscr(ctrl); + when SPRSEL_LPCR => + dbg_spr_data <= assemble_lpcr(ctrl); when SPRSEL_HEIR => dbg_spr_data <= ctrl.heir; when SPRSEL_CFAR => @@ -1173,6 +1202,7 @@ begin v.e.redir_mode := ex1.msr(MSR_IR) & not ex1.msr(MSR_PR) & not ex1.msr(MSR_LE) & not ex1.msr(MSR_SF); v.e.intr_vec := 16#700#; + v.e.alt_intr := ctrl.lpcr_hail and ex1.msr(MSR_IR) and ex1.msr(MSR_DR); v.e.mode_32bit := not ex1.msr(MSR_SF); v.e.instr_tag := e_in.instr_tag; v.e.last_nia := e_in.nia; @@ -1441,6 +1471,8 @@ begin v.se.write_cfar := '1'; when SPRSEL_FSCR => v.se.write_fscr := '1'; + when SPRSEL_LPCR => + v.se.write_lpcr := '1'; when SPRSEL_HEIR => v.se.write_heir := '1'; when SPRSEL_CTRL => @@ -1659,7 +1691,8 @@ begin v.busy := '0'; bypass_valid := actions.bypass_valid; - irq_valid := ex1.msr(MSR_EE) and (pmu_to_x.intr or ctrl.dec(63) or ext_irq_in); + irq_valid := ex1.msr(MSR_EE) and (pmu_to_x.intr or dec_sign or + (ext_irq_in and not ctrl.lpcr_heic)); if valid_in = '1' then v.prev_op := e_in.insn_type; @@ -1701,14 +1734,14 @@ begin if pmu_to_x.intr = '1' then v.e.intr_vec := 16#f00#; report "IRQ valid: PMU"; - elsif ctrl.dec(63) = '1' then + elsif dec_sign = '1' then v.e.intr_vec := 16#900#; report "IRQ valid: DEC"; elsif ext_irq_in = '1' then v.e.intr_vec := 16#500#; report "IRQ valid: External"; v.ext_interrupt := '1'; - v.e.hv_intr := '1'; + v.e.hv_intr := not ctrl.lpcr_lpes; end if; v.e.srr1 := (others => '0'); exception := '1'; @@ -1925,12 +1958,13 @@ begin with ex1.spr_select.sel select spr_result <= timebase when SPRSEL_TB, 32x"0" & timebase(63 downto 32) when SPRSEL_TBU, - ctrl.dec when SPRSEL_DEC, + assemble_dec(ctrl) when SPRSEL_DEC, 32x"0" & PVR_MICROWATT when SPRSEL_PVR, log_wr_addr & ex2.log_addr_spr when SPRSEL_LOGA, log_rd_data when SPRSEL_LOGD, ctrl.cfar when SPRSEL_CFAR, assemble_fscr(ctrl) when SPRSEL_FSCR, + assemble_lpcr(ctrl) when SPRSEL_LPCR, ctrl.heir when SPRSEL_HEIR, assemble_ctrl(ctrl, ex1.msr(MSR_PR)) when SPRSEL_CTRL, 39x"0" & ctrl.dscr when SPRSEL_DSCR, @@ -2089,6 +2123,13 @@ begin elsif ex1.se.write_ic = '1' then ctrl_tmp.fscr_ic <= ex1.ic; end if; + if ex1.se.write_lpcr = '1' then + ctrl_tmp.lpcr_hail <= ex1.e.write_data(LPCR_HAIL); + ctrl_tmp.lpcr_ld <= ex1.e.write_data(LPCR_LD); + ctrl_tmp.lpcr_heic <= ex1.e.write_data(LPCR_HEIC); + ctrl_tmp.lpcr_lpes <= ex1.e.write_data(LPCR_LPES); + ctrl_tmp.lpcr_hvice <= ex1.e.write_data(LPCR_HVICE); + end if; if ex1.se.write_heir = '1' then ctrl_tmp.heir <= ex1.e.write_data; elsif ex1.se.set_heir = '1' then @@ -2117,7 +2158,7 @@ begin -- pending exceptions clear any wait state -- ex1.fp_exception_next is not tested because it is not possible to -- get into wait state with a pending FP exception. - irq_exc := pmu_to_x.intr or ctrl.dec(63) or ext_irq_in; + irq_exc := pmu_to_x.intr or dec_sign or ext_irq_in; if ex1.trace_next = '1' or irq_exc = '1' or interrupt_in.intr = '1' then ctrl_tmp.wait_state <= '0'; end if; @@ -2130,11 +2171,13 @@ begin ctrl_tmp.msr(MSR_FP) <= '0'; ctrl_tmp.msr(MSR_FE0) <= '0'; ctrl_tmp.msr(MSR_FE1) <= '0'; - ctrl_tmp.msr(MSR_IR) <= '0'; - ctrl_tmp.msr(MSR_DR) <= '0'; + ctrl_tmp.msr(MSR_IR) <= interrupt_in.alt_int; + ctrl_tmp.msr(MSR_DR) <= interrupt_in.alt_int; ctrl_tmp.msr(MSR_LE) <= '1'; if interrupt_in.scv_int = '0' then ctrl_tmp.msr(MSR_EE) <= '0'; + end if; + if interrupt_in.scv_int = '0' and interrupt_in.hv_intr = '0' then ctrl_tmp.msr(MSR_RI) <= '0'; end if; end if; @@ -2158,7 +2201,6 @@ begin -- update outputs e_out <= ex2.e; - e_out.msr <= msr_copy(ctrl.msr); run_out <= ctrl.run; terminate_out <= ex2.se.terminate; diff --git a/fetch1.vhdl b/fetch1.vhdl index f07188d..bd5ca1a 100644 --- a/fetch1.vhdl +++ b/fetch1.vhdl @@ -391,11 +391,11 @@ begin v_int.next_nia := RESET_ADDRESS; end if; elsif w_in.interrupt = '1' then - v_int.next_nia := 47x"0" & w_in.intr_vec(16 downto 2) & "00"; + v_int.next_nia := w_in.intr_vec(63 downto 2) & "00"; end if; if rst /= '0' or w_in.interrupt = '1' then v.req := '0'; - v.virt_mode := '0'; + v.virt_mode := w_in.alt_intr and not rst; v.priv_mode := '1'; v.big_endian := '0'; v_int.mode_32bit := '0'; diff --git a/scripts/mw_debug/mw_debug.c b/scripts/mw_debug/mw_debug.c index 6b82943..06822ec 100644 --- a/scripts/mw_debug/mw_debug.c +++ b/scripts/mw_debug/mw_debug.c @@ -552,7 +552,7 @@ static const char *fast_spr_names[] = "lr", "ctr", "srr0", "srr1", "hsrr0", "hsrr1", "sprg0", "sprg1", "sprg2", "sprg3", "hsprg0", "hsprg1", "xer", "tar", - "fscr", "unused", "heir", "cfar", + "fscr", "lpcr", "heir", "cfar", }; static const char *ldst_spr_names[] = { diff --git a/writeback.vhdl b/writeback.vhdl index d7690a5..49a53cc 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -75,6 +75,7 @@ begin variable hvi : std_ulogic; variable scv : std_ulogic; variable intr_page : std_ulogic_vector(4 downto 0); + variable intr_seg : std_ulogic_vector(1 downto 0); begin w_out <= WritebackToRegisterFileInit; c_out <= WritebackToCrFileInit; @@ -98,6 +99,10 @@ begin srr1 := (others => '0'); intr_page := 5x"0"; + if e_in.alt_intr = '1' then + intr_page := 5x"4"; + end if; + intr_seg := e_in.alt_intr & e_in.alt_intr; scv := '0'; if e_in.interrupt = '1' then vec := e_in.intr_vec; @@ -105,7 +110,11 @@ begin hvi := e_in.hv_intr; scv := e_in.is_scv; if e_in.is_scv = '1' then - intr_page := 5x"17"; + if e_in.alt_intr = '0' then + intr_page := 5x"17"; + else + intr_page := 5x"3"; + end if; end if; elsif l_in.interrupt = '1' then vec := l_in.intr_vec; @@ -117,6 +126,7 @@ begin interrupt_out.hv_intr <= hvi; interrupt_out.srr1 <= srr1; interrupt_out.scv_int <= scv; + interrupt_out.alt_int <= e_in.alt_intr; if intr = '0' then if e_in.write_enable = '1' then @@ -174,7 +184,8 @@ begin -- Outputs to fetch1 f.interrupt := intr; - f.intr_vec := intr_page & std_ulogic_vector(to_unsigned(vec, 12)); + f.alt_intr := e_in.alt_intr; + f.intr_vec := intr_seg & 45x"0" & intr_page & std_ulogic_vector(to_unsigned(vec, 12)); f.redirect := e_in.redirect; f.redirect_nia := e_in.write_data; f.br_nia := e_in.last_nia;