From acb3d2d7455dfb9b1813f406f45cb314fba2e34e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 23 Dec 2020 13:57:40 +1100 Subject: [PATCH] core: Send FPU interrupts to writeback rather than execute1 Signed-off-by: Paul Mackerras --- common.vhdl | 28 ++++++++++++++++++---------- execute1.vhdl | 28 +++++++++------------------- fpu.vhdl | 12 +++++++++--- loadstore1.vhdl | 10 +++++----- writeback.vhdl | 40 +++++++++++++++++++++++++--------------- 5 files changed, 66 insertions(+), 52 deletions(-) diff --git a/common.vhdl b/common.vhdl index 48ba46f..e79bcb5 100644 --- a/common.vhdl +++ b/common.vhdl @@ -139,6 +139,8 @@ package common is constant instr_tag_init : instr_tag_t := (tag => 0, valid => '0'); function tag_match(tag1 : instr_tag_t; tag2 : instr_tag_t) return boolean; + subtype intr_vector_t is integer range 0 to 16#fff#; + -- For now, fixed 16 sources, make this either a parametric -- package of some sort or an unconstrainted array. type ics_to_icp_t is record @@ -449,9 +451,9 @@ package common is rc : std_ulogic; store_done : std_ulogic; interrupt : std_ulogic; - intr_vec : integer range 0 to 16#fff#; + intr_vec : intr_vector_t; srr0: std_ulogic_vector(63 downto 0); - srr1: std_ulogic_vector(31 downto 0); + srr1: std_ulogic_vector(15 downto 0); end record; constant Loadstore1ToWritebackInit : Loadstore1ToWritebackType := (valid => '0', instr_tag => instr_tag_init, write_enable => '0', @@ -474,7 +476,7 @@ package common is write_xerc_enable : std_ulogic; xerc : xer_common_t; interrupt : std_ulogic; - intr_vec : integer range 0 to 16#fff#; + intr_vec : intr_vector_t; redirect: std_ulogic; redir_mode: std_ulogic_vector(3 downto 0); last_nia: std_ulogic_vector(63 downto 0); @@ -482,7 +484,7 @@ package common is br_last: std_ulogic; br_taken: std_ulogic; abs_br: std_ulogic; - srr1: std_ulogic_vector(31 downto 0); + srr1: std_ulogic_vector(15 downto 0); msr: std_ulogic_vector(63 downto 0); end record; constant Execute1ToWritebackInit : Execute1ToWritebackType := @@ -521,13 +523,12 @@ package common is type FPUToExecute1Type is record busy : std_ulogic; exception : std_ulogic; - interrupt : std_ulogic; - illegal : std_ulogic; end record; constant FPUToExecute1Init : FPUToExecute1Type := (others => '0'); type FPUToWritebackType is record valid : std_ulogic; + interrupt : std_ulogic; instr_tag : instr_tag_t; write_enable : std_ulogic; write_reg : gspr_index_t; @@ -535,10 +536,17 @@ package common is write_cr_enable : std_ulogic; write_cr_mask : std_ulogic_vector(7 downto 0); write_cr_data : std_ulogic_vector(31 downto 0); - end record; - constant FPUToWritebackInit : FPUToWritebackType := (valid => '0', instr_tag => instr_tag_init, - write_enable => '0', write_cr_enable => '0', - others => (others => '0')); + intr_vec : intr_vector_t; + srr0 : std_ulogic_vector(63 downto 0); + srr1 : std_ulogic_vector(15 downto 0); + end record; + constant FPUToWritebackInit : FPUToWritebackType := + (valid => '0', interrupt => '0', instr_tag => instr_tag_init, + write_enable => '0', write_reg => (others => '0'), + write_cr_enable => '0', write_cr_mask => (others => '0'), + write_cr_data => (others => '0'), + intr_vec => 0, srr1 => (others => '0'), + others => (others => '0')); type DividerToExecute1Type is record valid: std_ulogic; diff --git a/execute1.vhdl b/execute1.vhdl index f8507bb..0eaf55a 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -750,19 +750,19 @@ begin -- become pending due to MSR[FE0,FE1] changing from 00 to non-zero. exception := '1'; v.e.intr_vec := 16#700#; - v.e.srr1(63 - 43) := '1'; - v.e.srr1(63 - 47) := '1'; + v.e.srr1(47 - 43) := '1'; + v.e.srr1(47 - 47) := '1'; elsif r.trace_next = '1' then -- Generate a trace interrupt rather than executing the next instruction -- or taking any asynchronous interrupt exception := '1'; v.e.intr_vec := 16#d00#; - v.e.srr1(63 - 33) := '1'; + v.e.srr1(47 - 33) := '1'; if r.prev_op = OP_LOAD or r.prev_op = OP_ICBI or r.prev_op = OP_ICBT or r.prev_op = OP_DCBT or r.prev_op = OP_DCBST or r.prev_op = OP_DCBF then - v.e.srr1(63 - 35) := '1'; + v.e.srr1(47 - 35) := '1'; elsif r.prev_op = OP_STORE or r.prev_op = OP_DCBZ or r.prev_op = OP_DCBTST then - v.e.srr1(63 - 36) := '1'; + v.e.srr1(47 - 36) := '1'; end if; elsif irq_valid = '1' then @@ -775,7 +775,7 @@ begin exception := '1'; v.e.intr_vec := 16#700#; -- set bit 45 to indicate privileged instruction type interrupt - v.e.srr1(63 - 45) := '1'; + v.e.srr1(47 - 45) := '1'; report "privileged instruction"; elsif not HAS_FPU and e_in.fac = FPU then @@ -840,7 +840,7 @@ begin -- trap instructions (tw, twi, td, tdi) v.e.intr_vec := 16#700#; -- set bit 46 to say trap occurred - v.e.srr1(63 - 46) := '1'; + v.e.srr1(47 - 46) := '1'; if or (trapval and insn_to(e_in.insn)) = '1' then -- generate trap-type program interrupt exception := '1'; @@ -1124,22 +1124,12 @@ begin v.e.valid := '1'; end if; - -- Generate FP-type program interrupt. fp_in.interrupt will only - -- be set during the execution of a FP instruction. - -- The case where MSR[FE0,FE1] goes from zero to non-zero is - -- handled above by mtmsrd and rfid setting v.fp_exception_next. - if HAS_FPU and fp_in.interrupt = '1' then - v.e.intr_vec := 16#700#; - v.e.srr1(63 - 43) := '1'; - exception := '1'; - end if; - - if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then + if illegal = '1' then exception := '1'; v.e.intr_vec := 16#700#; -- Since we aren't doing Hypervisor emulation assist (0xe40) we -- set bit 44 to indicate we have an illegal - v.e.srr1(63 - 44) := '1'; + v.e.srr1(47 - 44) := '1'; report "illegal"; end if; diff --git a/fpu.vhdl b/fpu.vhdl index 5e5c7d6..93fa9d6 100644 --- a/fpu.vhdl +++ b/fpu.vhdl @@ -73,8 +73,10 @@ architecture behaviour of fpu is busy : std_ulogic; instr_done : std_ulogic; do_intr : std_ulogic; + illegal : std_ulogic; op : insn_type_t; insn : std_ulogic_vector(31 downto 0); + nia : std_ulogic_vector(63 downto 0); instr_tag : instr_tag_t; dest_fpr : gspr_index_t; fe_mode : std_ulogic; @@ -572,7 +574,6 @@ begin e_out.busy <= r.busy; e_out.exception <= r.fpscr(FPSCR_FEX); - e_out.interrupt <= r.do_intr; w_out.valid <= r.instr_done and not r.do_intr; w_out.instr_tag <= r.instr_tag; @@ -583,6 +584,10 @@ begin w_out.write_cr_mask <= r.cr_mask; w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result & r.cr_result & r.cr_result & r.cr_result & r.cr_result; + w_out.interrupt <= r.do_intr; + w_out.intr_vec <= 16#700#; + w_out.srr0 <= r.nia; + w_out.srr1 <= (47-44 => r.illegal, 47-43 => not r.illegal, others => '0'); fpu_1: process(all) variable v : reg_type; @@ -644,6 +649,7 @@ begin -- capture incoming instruction if e_in.valid = '1' then v.insn := e_in.insn; + v.nia := e_in.nia; v.op := e_in.op; v.instr_tag := e_in.itag; v.fe_mode := or (e_in.fe_mode); @@ -2543,9 +2549,10 @@ begin v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX); end if; + v.illegal := illegal; if illegal = '1' then v.instr_done := '0'; - v.do_intr := '0'; + v.do_intr := '1'; v.writing_back := '0'; v.busy := '0'; v.state := IDLE; @@ -2557,7 +2564,6 @@ begin end if; rin <= v; - e_out.illegal <= illegal; end process; end architecture behaviour; diff --git a/loadstore1.vhdl b/loadstore1.vhdl index f4f4f4a..a754cc4 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -108,7 +108,7 @@ architecture behave of loadstore1 is interrupt : std_ulogic; intr_vec : integer range 0 to 16#fff#; nia : std_ulogic_vector(63 downto 0); - srr1 : std_ulogic_vector(31 downto 0); + srr1 : std_ulogic_vector(15 downto 0); end record; signal r, rin : reg_stage_t; @@ -721,10 +721,10 @@ begin end if; else if m_in.segerr = '0' then - v.srr1(63 - 33) := m_in.invalid; - v.srr1(63 - 35) := m_in.perm_error; -- noexec fault - v.srr1(63 - 44) := m_in.badtree; - v.srr1(63 - 45) := m_in.rc_error; + v.srr1(47 - 33) := m_in.invalid; + v.srr1(47 - 35) := m_in.perm_error; -- noexec fault + v.srr1(47 - 44) := m_in.badtree; + v.srr1(47 - 45) := m_in.rc_error; v.intr_vec := 16#400#; else v.intr_vec := 16#480#; diff --git a/writeback.vhdl b/writeback.vhdl index 40cd5b4..65da537 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -82,6 +82,8 @@ begin variable sign : std_ulogic; variable scf : std_ulogic_vector(3 downto 0); variable vec : integer range 0 to 16#fff#; + variable srr1 : std_ulogic_vector(15 downto 0); + variable intr : std_ulogic; begin w_out <= WritebackToRegisterFileInit; c_out <= WritebackToCrFileInit; @@ -99,6 +101,8 @@ begin complete_out <= fp_in.instr_tag; end if; + intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt; + if r.state = WRITE_SRR1 then w_out.write_reg <= fast_spr_num(SPR_SRR1); w_out.write_data <= r.srr1; @@ -106,23 +110,29 @@ begin interrupt_out <= '1'; v.state := WRITE_SRR0; - elsif e_in.interrupt = '1' then - w_out.write_reg <= fast_spr_num(SPR_SRR0); - w_out.write_data <= e_in.last_nia; - w_out.write_enable <= '1'; - v.state := WRITE_SRR1; - v.srr1(63 downto 32) := e_in.msr(63 downto 32); - v.srr1(31 downto 0) := e_in.msr(31 downto 0) or e_in.srr1; - vec := e_in.intr_vec; - - elsif l_in.interrupt = '1' then + elsif intr = '1' then w_out.write_reg <= fast_spr_num(SPR_SRR0); - w_out.write_data <= l_in.srr0; w_out.write_enable <= '1'; v.state := WRITE_SRR1; - v.srr1(63 downto 32) := e_in.msr(63 downto 32); - v.srr1(31 downto 0) := e_in.msr(31 downto 0) or l_in.srr1; - vec := l_in.intr_vec; + srr1 := (others => '0'); + if e_in.interrupt = '1' then + vec := e_in.intr_vec; + w_out.write_data <= e_in.last_nia; + srr1 := e_in.srr1; + elsif l_in.interrupt = '1' then + vec := l_in.intr_vec; + w_out.write_data <= l_in.srr0; + srr1 := l_in.srr1; + elsif fp_in.interrupt = '1' then + vec := fp_in.intr_vec; + w_out.write_data <= fp_in.srr0; + srr1 := fp_in.srr1; + end if; + v.srr1(63 downto 31) := e_in.msr(63 downto 31); + v.srr1(30 downto 27) := srr1(14 downto 11); + v.srr1(26 downto 22) := e_in.msr(26 downto 22); + v.srr1(21 downto 16) := srr1(5 downto 0); + v.srr1(15 downto 0) := e_in.msr(15 downto 0); else if e_in.write_enable = '1' then @@ -196,7 +206,7 @@ begin f.br_nia := e_in.last_nia; f.br_last := e_in.br_last; f.br_taken := e_in.br_taken; - if e_in.interrupt = '1' or l_in.interrupt = '1' then + if intr = '1' then f.redirect := '1'; f.br_last := '0'; f.redirect_nia := std_ulogic_vector(to_unsigned(vec, 64));