From: Paul Mackerras Date: Tue, 7 Apr 2020 10:07:33 +0000 (+1000) Subject: execute1: Implement trap instructions properly X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f5f17c24fd64fc950d5a0ca1f57bb086567c14be;p=microwatt.git execute1: Implement trap instructions properly This implements the trap instructions (tw, twi, td, tdi) using much of the same code as is used for the cmp/cmpl instructions. A 5-bit comparison value is generated, and for cmp/cmpl, the appropriate 3 bits are used to update the destination CR, and for trap instructions, the comparison value is ANDed with the TO field, and an exception is generated if any bit of the result is 1. Signed-off-by: Paul Mackerras --- diff --git a/execute1.vhdl b/execute1.vhdl index 15635ab..d6ba3f6 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -238,6 +238,7 @@ begin variable irq_valid : std_ulogic; variable exception : std_ulogic; variable exception_nextpc : std_ulogic; + variable trapval : std_ulogic_vector(4 downto 0); begin result := (others => '0'); result_with_carry := (others => '0'); @@ -446,7 +447,7 @@ begin report "ATTN"; when OP_NOP => -- Do nothing - when OP_ADD | OP_CMP => + when OP_ADD | OP_CMP | OP_TRAP => if e_in.invert_a = '0' then a_inv := a_in; else @@ -468,18 +469,18 @@ begin end if; result_en := '1'; else - -- CMP and CMPL instructions + -- trap, CMP and CMPL instructions -- Note, we have done RB - RA, not RA - RB - bf := insn_bf(e_in.insn); - l := insn_l(e_in.insn); - v.e.write_cr_enable := '1'; - crnum := to_integer(unsigned(bf)); - v.e.write_cr_mask := num_to_fxm(crnum); + if e_in.insn_type = OP_CMP then + l := insn_l(e_in.insn); + else + l := not e_in.is_32bit; + end if; zerolo := not (or (a_in(31 downto 0) xor b_in(31 downto 0))); zerohi := not (or (a_in(63 downto 32) xor b_in(63 downto 32))); if zerolo = '1' and (l = '0' or zerohi = '1') then -- values are equal - newcrf := "001" & v.e.xerc.so; + trapval := "00100"; else if l = '1' then -- 64-bit comparison @@ -494,19 +495,41 @@ begin -- Subtraction might overflow, but -- comparison is clear from MSB difference. -- for signed, 0 is greater; for unsigned, 1 is greater - a_lt := msb_a xnor e_in.is_signed; + trapval := msb_a & msb_b & '0' & msb_b & msb_a; else -- Subtraction cannot overflow since MSBs are equal. -- carry = 1 indicates RA is smaller (signed or unsigned) a_lt := (not l and carry_32) or (l and carry_64); + trapval := a_lt & not a_lt & '0' & a_lt & not a_lt; + end if; + end if; + if e_in.insn_type = OP_CMP then + if e_in.is_signed = '1' then + newcrf := trapval(4 downto 2) & v.e.xerc.so; + else + newcrf := trapval(1 downto 0) & trapval(2) & v.e.xerc.so; + end if; + bf := insn_bf(e_in.insn); + crnum := to_integer(unsigned(bf)); + v.e.write_cr_enable := '1'; + v.e.write_cr_mask := num_to_fxm(crnum); + for i in 0 to 7 loop + lo := i*4; + hi := lo + 3; + v.e.write_cr_data(hi downto lo) := newcrf; + end loop; + else + -- trap instructions (tw, twi, td, tdi) + if or (trapval and insn_to(e_in.insn)) = '1' then + -- generate trap-type program interrupt + exception := '1'; + ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#700#, 64)); + ctrl_tmp.srr1 <= msr_copy(ctrl.msr); + -- set bit 46 to say trap occurred + ctrl_tmp.srr1(63 - 46) <= '1'; + report "trap"; end if; - newcrf := a_lt & not a_lt & '0' & v.e.xerc.so; end if; - for i in 0 to 7 loop - lo := i*4; - hi := lo + 3; - v.e.write_cr_data(hi downto lo) := newcrf; - end loop; end if; when OP_AND | OP_OR | OP_XOR => result := logical_result; @@ -726,17 +749,6 @@ begin result := x"0000000000000000"; result_en := '1'; - when OP_TRAP => - -- For now, generate a program interrupt if the TO field is all 1s - if insn_to(e_in.insn) = "11111" then - exception := '1'; - ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#700#, 64)); - ctrl_tmp.srr1 <= msr_copy(ctrl.msr); - -- set bit 46 to say a trap occurred - ctrl_tmp.srr1(63 - 46) <= '1'; - report "trap"; - end if; - when OP_ISYNC => f_out.redirect <= '1'; f_out.redirect_nia <= next_nia;