diff --git a/execute1.vhdl b/execute1.vhdl index 11d81ed..4ea2680 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -53,7 +53,6 @@ end entity execute1; architecture behaviour of execute1 is type reg_type is record e : Execute1ToWritebackType; - f : Execute1ToFetch1Type; busy: std_ulogic; terminate: std_ulogic; fp_exception_next : std_ulogic; @@ -71,15 +70,24 @@ architecture behaviour of execute1 is slow_op_oe : std_ulogic; slow_op_xerc : xer_common_t; last_nia : std_ulogic_vector(63 downto 0); + redirect : std_ulogic; + abs_br : std_ulogic; + do_intr : std_ulogic; + vector : integer range 0 to 16#fff#; + br_offset : std_ulogic_vector(63 downto 0); + redir_mode : std_ulogic_vector(3 downto 0); log_addr_spr : std_ulogic_vector(31 downto 0); end record; constant reg_type_init : reg_type := - (e => Execute1ToWritebackInit, f => Execute1ToFetch1Init, + (e => Execute1ToWritebackInit, busy => '0', lr_update => '0', terminate => '0', fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL, mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', cntz_in_progress => '0', slow_op_insn => OP_ILLEGAL, slow_op_rc => '0', slow_op_oe => '0', slow_op_xerc => xerc_init, - next_lr => (others => '0'), last_nia => (others => '0'), others => (others => '0')); + next_lr => (others => '0'), last_nia => (others => '0'), + redirect => '0', abs_br => '0', do_intr => '0', vector => 0, + br_offset => (others => '0'), redir_mode => "0000", + others => (others => '0')); signal r, rin : reg_type; @@ -340,6 +348,7 @@ begin variable spr_val : std_ulogic_vector(63 downto 0); variable addend : std_ulogic_vector(127 downto 0); variable do_trace : std_ulogic; + variable f : Execute1ToFetch1Type; variable fv : Execute1ToFPUType; begin result := (others => '0'); @@ -352,8 +361,15 @@ begin v := r; v.e := Execute1ToWritebackInit; + v.redirect := '0'; + v.abs_br := '0'; + v.do_intr := '0'; + v.vector := 0; + v.br_offset := (others => '0'); + v.redir_mode := ctrl.msr(MSR_IR) & not ctrl.msr(MSR_PR) & + not ctrl.msr(MSR_LE) & not ctrl.msr(MSR_SF); + lv := Execute1ToLoadstore1Init; - v.f.redirect := '0'; fv := Execute1ToFPUInit; -- XER forwarding. To avoid having to track XER hazards, we use @@ -471,11 +487,11 @@ begin irq_valid := '0'; if ctrl.msr(MSR_EE) = '1' then if ctrl.dec(63) = '1' then - v.f.redirect_nia := std_logic_vector(to_unsigned(16#900#, 64)); + v.vector := 16#900#; report "IRQ valid: DEC"; irq_valid := '1'; elsif ext_irq_in = '1' then - v.f.redirect_nia := std_logic_vector(to_unsigned(16#500#, 64)); + v.vector := 16#500#; report "IRQ valid: External"; irq_valid := '1'; end if; @@ -484,11 +500,6 @@ begin v.terminate := '0'; icache_inval <= '0'; v.busy := '0'; - -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1 - v.f.virt_mode := ctrl.msr(MSR_IR); - v.f.priv_mode := not ctrl.msr(MSR_PR); - v.f.big_endian := not ctrl.msr(MSR_LE); - v.f.mode_32bit := not ctrl.msr(MSR_SF); -- Next insn adder used in a couple of places next_nia := std_ulogic_vector(unsigned(e_in.nia) + 4); @@ -546,13 +557,13 @@ begin if HAS_FPU and r.fp_exception_next = '1' then -- This is used for FP-type program interrupts that -- become pending due to MSR[FE0,FE1] changing from 00 to non-zero. - v.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64)); + v.vector := 16#700#; ctrl_tmp.srr1(63 - 43) <= '1'; ctrl_tmp.srr1(63 - 47) <= '1'; else -- Generate a trace interrupt rather than executing the next instruction -- or taking any asynchronous interrupt - v.f.redirect_nia := std_logic_vector(to_unsigned(16#d00#, 64)); + v.vector := 16#d00#; ctrl_tmp.srr1(63 - 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 @@ -574,7 +585,7 @@ begin instr_is_privileged(e_in.insn_type, e_in.insn) then -- generate a program interrupt exception := '1'; - v.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64)); + v.vector := 16#700#; -- set bit 45 to indicate privileged instruction type interrupt ctrl_tmp.srr1(63 - 45) <= '1'; report "privileged instruction"; @@ -586,7 +597,7 @@ begin elsif HAS_FPU and valid_in = '1' and ctrl.msr(MSR_FP) = '0' and e_in.fac = FPU then -- generate a floating-point unavailable interrupt exception := '1'; - v.f.redirect_nia := std_logic_vector(to_unsigned(16#800#, 64)); + v.vector := 16#800#; report "FP unavailable interrupt"; elsif valid_in = '1' and e_in.unit = ALU then @@ -614,7 +625,7 @@ begin if e_in.insn(1) = '1' then exception := '1'; exception_nextpc := '1'; - v.f.redirect_nia := std_logic_vector(to_unsigned(16#C00#, 64)); + v.vector := 16#C00#; report "sc"; else illegal := '1'; @@ -702,7 +713,7 @@ begin end loop; else -- trap instructions (tw, twi, td, tdi) - v.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64)); + v.vector := 16#700#; -- set bit 46 to say trap occurred ctrl_tmp.srr1(63 - 46) <= '1'; if or (trapval and insn_to(e_in.insn)) = '1' then @@ -785,10 +796,8 @@ begin end if; when OP_RFID => - v.f.virt_mode := a_in(MSR_IR) or a_in(MSR_PR); - v.f.priv_mode := not a_in(MSR_PR); - v.f.big_endian := not a_in(MSR_LE); - v.f.mode_32bit := not a_in(MSR_SF); + v.redir_mode := (a_in(MSR_IR) or a_in(MSR_PR)) & not a_in(MSR_PR) & + not a_in(MSR_LE) & not a_in(MSR_SF); -- Can't use msr_copy here because the partial function MSR -- bits should be left unchanged, not zeroed. ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31); @@ -1032,8 +1041,8 @@ begin end if; when OP_ISYNC => - v.f.redirect := '1'; - v.f.redirect_nia := next_nia; + v.redirect := '1'; + v.br_offset := std_ulogic_vector(to_unsigned(4, 64)); when OP_ICBI => icache_inval <= '1'; @@ -1063,16 +1072,13 @@ begin ctrl_tmp.cfar <= e_in.nia; end if; if e_in.br_pred = '0' then - if abs_branch = '1' then - v.f.redirect_nia := b_in; - else - v.f.redirect_nia := std_ulogic_vector(signed(e_in.nia) + signed(b_in)); - end if; + v.br_offset := b_in; + v.abs_br := abs_branch; else - v.f.redirect_nia := next_nia; + v.br_offset := std_ulogic_vector(to_unsigned(4, 64)); end if; if taken_branch /= e_in.br_pred then - v.f.redirect := '1'; + v.redirect := '1'; end if; end if; @@ -1114,7 +1120,7 @@ begin -- valid_in = 0. Hence they don't happen in the same cycle as any of -- the cases above which depend on valid_in = 1. - if r.f.redirect = '1' then + if r.redirect = '1' then v.e.valid := '1'; end if; if r.lr_update = '1' then @@ -1195,14 +1201,14 @@ begin -- 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.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64)); + v.vector := 16#700#; ctrl_tmp.srr1(63 - 43) <= '1'; exception := '1'; end if; if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then exception := '1'; - v.f.redirect_nia := std_logic_vector(to_unsigned(16#700#, 64)); + v.vector := 16#700#; -- Since we aren't doing Hypervisor emulation assist (0xe40) we -- set bit 44 to indicate we have an illegal ctrl_tmp.srr1(63 - 44) <= '1'; @@ -1226,12 +1232,12 @@ begin -- or ISI or ISegI for instruction fetch exceptions if l_in.exception = '1' then if l_in.alignment = '1' then - v.f.redirect_nia := std_logic_vector(to_unsigned(16#600#, 64)); + v.vector := 16#600#; elsif l_in.instr_fault = '0' then if l_in.segment_fault = '0' then - v.f.redirect_nia := std_logic_vector(to_unsigned(16#300#, 64)); + v.vector := 16#300#; else - v.f.redirect_nia := std_logic_vector(to_unsigned(16#380#, 64)); + v.vector := 16#380#; end if; else if l_in.segment_fault = '0' then @@ -1239,9 +1245,9 @@ begin ctrl_tmp.srr1(63 - 35) <= l_in.perm_error; -- noexec fault ctrl_tmp.srr1(63 - 44) <= l_in.badtree; ctrl_tmp.srr1(63 - 45) <= l_in.rc_error; - v.f.redirect_nia := std_logic_vector(to_unsigned(16#400#, 64)); + v.vector := 16#400#; else - v.f.redirect_nia := std_logic_vector(to_unsigned(16#480#, 64)); + v.vector := 16#480#; end if; end if; v.e.exc_write_enable := '1'; @@ -1251,19 +1257,37 @@ begin if exception = '1' or l_in.exception = '1' then ctrl_tmp.irq_state <= WRITE_SRR1; - v.f.redirect := '1'; - v.f.virt_mode := '0'; - v.f.priv_mode := '1'; - -- XXX need an interrupt LE bit here, e.g. from LPCR - v.f.big_endian := '0'; - v.f.mode_32bit := '0'; + v.redirect := '1'; + v.do_intr := '1'; end if; - if v.f.redirect = '1' then + if v.redirect = '1' then v.busy := '1'; v.e.valid := '0'; end if; + -- Outputs to fetch1 + f.redirect := r.redirect; + if r.do_intr = '1' then + f.redirect_nia := std_ulogic_vector(to_unsigned(r.vector, 64)); + f.virt_mode := '0'; + f.priv_mode := '1'; + -- XXX need an interrupt LE bit here, e.g. from LPCR + f.big_endian := '0'; + f.mode_32bit := '0'; + else + if r.abs_br = '1' then + f.redirect_nia := r.br_offset; + else + f.redirect_nia := std_ulogic_vector(unsigned(r.last_nia) + unsigned(r.br_offset)); + end if; + -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1 + f.virt_mode := r.redir_mode(3); + f.priv_mode := r.redir_mode(2); + f.big_endian := r.redir_mode(1); + f.mode_32bit := r.redir_mode(0); + end if; + -- Outputs to loadstore1 (async) lv.op := e_in.insn_type; lv.nia := e_in.nia; @@ -1309,7 +1333,7 @@ begin rin <= v; -- update outputs - f_out <= r.f; + f_out <= f; l_out <= lv; e_out <= r.e; fp_out <= fv;