diff --git a/common.vhdl b/common.vhdl index 838179b..59c855e 100644 --- a/common.vhdl +++ b/common.vhdl @@ -266,6 +266,7 @@ package common is prefixed: std_ulogic; prefix: std_ulogic_vector(25 downto 0); illegal_suffix: std_ulogic; + misaligned_prefix: std_ulogic; insn: std_ulogic_vector(31 downto 0); decode: decode_rom_t; br_pred: std_ulogic; -- Branch was predicted to be taken @@ -279,7 +280,7 @@ package common is constant Decode1ToDecode2Init : Decode1ToDecode2Type := (valid => '0', stop_mark => '0', nia => (others => '0'), prefixed => '0', prefix => (others => '0'), insn => (others => '0'), - illegal_suffix => '0', + illegal_suffix => '0', misaligned_prefix => '0', decode => decode_rom_init, br_pred => '0', big_endian => '0', spr_info => spr_id_init, ram_spr => ram_spr_info_init, reg_a => (others => '0'), reg_b => (others => '0'), reg_c => (others => '0')); @@ -364,6 +365,9 @@ package common is ramspr_write_odd : std_ulogic; dbg_spr_access : std_ulogic; dec_ctr : std_ulogic; + prefixed : std_ulogic; + illegal_suffix : std_ulogic; + misaligned_prefix : std_ulogic; end record; constant Decode2ToExecute1Init : Decode2ToExecute1Type := (valid => '0', unit => ALU, fac => NONE, insn_type => OP_ILLEGAL, instr_tag => instr_tag_init, @@ -383,6 +387,7 @@ package common is ramspr_wraddr => (others => '0'), ramspr_write_even => '0', ramspr_write_odd => '0', dbg_spr_access => '0', dec_ctr => '0', + prefixed => '0', illegal_suffix => '0', misaligned_prefix => '0', others => (others => '0')); type MultiplyInputType is record @@ -505,6 +510,7 @@ package common is priv_mode : std_ulogic; -- privileged mode (MSR[PR] = 0) mode_32bit : std_ulogic; -- trim addresses to 32 bits is_32bit : std_ulogic; + prefixed : std_ulogic; repeat : std_ulogic; second : std_ulogic; e2stall : std_ulogic; @@ -519,7 +525,7 @@ package common is addr1 => (others => '0'), addr2 => (others => '0'), data => (others => '0'), write_reg => (others => '0'), length => (others => '0'), - mode_32bit => '0', is_32bit => '0', + mode_32bit => '0', is_32bit => '0', prefixed => '0', repeat => '0', second => '0', e2stall => '0', msr => (others => '0')); diff --git a/decode1.vhdl b/decode1.vhdl index 138e483..0aa2fee 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -572,7 +572,13 @@ begin pv.prefixed := '1'; pv.pref_ia := f_in.nia(5 downto 2); pv.prefix := f_in.insn(25 downto 0); - v.valid := '0'; + -- Check if the address of the prefix mod 64 is 60; + -- if so we need to arrange to generate an alignment interrupt + if f_in.nia(5 downto 2) = "1111" then + v.misaligned_prefix := '1'; + else + v.valid := '0'; + end if; end if; decode_rom_addr <= insn_code'val(to_integer(unsigned(icode_bits))); diff --git a/decode2.vhdl b/decode2.vhdl index fa3b54d..338a80a 100644 --- a/decode2.vhdl +++ b/decode2.vhdl @@ -371,21 +371,27 @@ begin c_out.read <= d_in.decode.input_cr; decode2_addrs: process(all) + variable dec_a, dec_b, dec_c : decode_input_reg_t; + variable dec_o : decode_output_reg_t; begin - decoded_reg_a <= decode_input_reg_init; - decoded_reg_b <= decode_input_reg_init; - decoded_reg_c <= decode_input_reg_init; - decoded_reg_o <= decode_output_reg_init; - if d_in.valid = '1' then - decoded_reg_a <= decode_input_reg_a (d_in.decode.input_reg_a, d_in.insn, d_in.prefix, d_in.nia); - decoded_reg_b <= decode_input_reg_b (d_in.decode.input_reg_b, d_in.insn, d_in.prefix); - decoded_reg_c <= decode_input_reg_c (d_in.decode.input_reg_c, d_in.insn); - decoded_reg_o <= decode_output_reg (d_in.decode.output_reg_a, d_in.insn); + dec_a := decode_input_reg_a (d_in.decode.input_reg_a, d_in.insn, d_in.prefix, d_in.nia); + dec_b := decode_input_reg_b (d_in.decode.input_reg_b, d_in.insn, d_in.prefix); + dec_c := decode_input_reg_c (d_in.decode.input_reg_c, d_in.insn); + dec_o := decode_output_reg (d_in.decode.output_reg_a, d_in.insn); + if d_in.valid = '0' or d_in.illegal_suffix = '1' then + dec_a.reg_valid := '0'; + dec_b.reg_valid := '0'; + dec_c.reg_valid := '0'; + dec_o.reg_valid := '0'; end if; - r_out.read1_enable <= decoded_reg_a.reg_valid; - r_out.read2_enable <= decoded_reg_b.reg_valid; - r_out.read3_enable <= decoded_reg_c.reg_valid; + decoded_reg_a <= dec_a; + decoded_reg_b <= dec_b; + decoded_reg_c <= dec_c; + decoded_reg_o <= dec_o; + r_out.read1_enable <= dec_a.reg_valid; + r_out.read2_enable <= dec_b.reg_valid; + r_out.read3_enable <= dec_c.reg_valid; end process; @@ -592,6 +598,9 @@ begin v.e.result_sel := "001"; -- logical_result end if; end if; + v.e.prefixed := d_in.prefixed; + v.e.illegal_suffix := d_in.illegal_suffix; + v.e.misaligned_prefix := d_in.misaligned_prefix; elsif dc2.e.valid = '1' then -- dc2.busy = 1 and dc2.e.valid = 1, thus this must be a repeated instruction. diff --git a/execute1.vhdl b/execute1.vhdl index db1159d..e6cfd3e 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -118,6 +118,7 @@ architecture behaviour of execute1 is fp_exception_next : std_ulogic; trace_next : std_ulogic; prev_op : insn_type_t; + prev_prefixed : std_ulogic; oe : std_ulogic; mul_select : std_ulogic_vector(1 downto 0); res2_sel : std_ulogic_vector(1 downto 0); @@ -141,6 +142,7 @@ architecture behaviour of execute1 is (e => Execute1ToWritebackInit, se => side_effect_init, busy => '0', fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL, + prev_prefixed => '0', oe => '0', mul_select => "00", res2_sel => "00", spr_select => spr_id_init, pmu_spr_num => 5x"0", mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', @@ -978,6 +980,7 @@ begin variable bo, bi : std_ulogic_vector(4 downto 0); variable illegal : std_ulogic; variable privileged : std_ulogic; + variable misaligned : std_ulogic; variable slow_op : std_ulogic; variable owait : std_ulogic; variable srr1 : std_ulogic_vector(63 downto 0); @@ -1021,10 +1024,13 @@ begin illegal := '0'; privileged := '0'; + misaligned := e_in.misaligned_prefix; slow_op := '0'; owait := '0'; - if ex1.msr(MSR_PR) = '1' and instr_is_privileged(e_in.insn_type, e_in.insn) then + if e_in.illegal_suffix = '1' then + illegal := '1'; + elsif ex1.msr(MSR_PR) = '1' and instr_is_privileged(e_in.insn_type, e_in.insn) then privileged := '1'; end if; @@ -1315,9 +1321,22 @@ begin end if; end case; - if privileged = '1' then + if misaligned = '1' then + -- generate an alignment interrupt + -- This is higher priority than illegal because a misaligned + -- prefix will come down as an OP_ILLEGAL instruction. + v.exception := '1'; + v.e.intr_vec := 16#600#; + v.e.srr1(47 - 35) := '1'; + v.e.srr1(47 - 34) := '1'; + if e_in.valid = '1' then + report "misaligned prefixed instruction interrupt"; + end if; + + elsif privileged = '1' then -- generate a program interrupt v.exception := '1'; + v.e.srr1(47 - 34) := e_in.prefixed; -- set bit 45 to indicate privileged instruction type interrupt v.e.srr1(47 - 45) := '1'; if e_in.valid = '1' then @@ -1326,6 +1345,7 @@ begin elsif illegal = '1' then v.exception := '1'; + v.e.srr1(47 - 34) := e_in.prefixed; -- Since we aren't doing Hypervisor emulation assist (0xe40) we -- set bit 44 to indicate we have an illegal v.e.srr1(47 - 44) := '1'; @@ -1336,6 +1356,7 @@ begin elsif HAS_FPU and ex1.msr(MSR_FP) = '0' and e_in.fac = FPU then -- generate a floating-point unavailable interrupt v.exception := '1'; + v.e.srr1(47 - 34) := e_in.prefixed; v.e.intr_vec := 16#800#; if e_in.valid = '1' then report "FP unavailable interrupt"; @@ -1401,6 +1422,7 @@ begin if valid_in = '1' then v.prev_op := e_in.insn_type; + v.prev_prefixed := e_in.prefixed; end if; -- Determine if there is any interrupt to be taken @@ -1422,6 +1444,7 @@ begin v.e.intr_vec := 16#d00#; v.e.srr1 := (others => '0'); v.e.srr1(47 - 33) := '1'; + v.e.srr1(47 - 34) := ex1.prev_prefixed; if ex1.prev_op = OP_LOAD or ex1.prev_op = OP_ICBI or ex1.prev_op = OP_ICBT or ex1.prev_op = OP_DCBT or ex1.prev_op = OP_DCBST or ex1.prev_op = OP_DCBF then v.e.srr1(47 - 35) := '1'; @@ -1584,6 +1607,7 @@ begin lv.priv_mode := not ex1.msr(MSR_PR); lv.mode_32bit := not ex1.msr(MSR_SF); lv.is_32bit := e_in.is_32bit; + lv.prefixed := e_in.prefixed; lv.repeat := e_in.repeat; lv.second := e_in.second; lv.e2stall := fp_in.f2stall; diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 01babc3..fc8c158 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -69,6 +69,7 @@ architecture behave of loadstore1 is instr_fault : std_ulogic; do_update : std_ulogic; mode_32bit : std_ulogic; + prefixed : std_ulogic; addr : std_ulogic_vector(63 downto 0); byte_sel : std_ulogic_vector(7 downto 0); second_bytes : std_ulogic_vector(7 downto 0); @@ -99,7 +100,8 @@ architecture behave of loadstore1 is constant request_init : request_t := (valid => '0', dc_req => '0', load => '0', store => '0', tlbie => '0', dcbz => '0', read_spr => '0', write_spr => '0', mmu_op => '0', instr_fault => '0', do_update => '0', - mode_32bit => '0', addr => (others => '0'), + mode_32bit => '0', prefixed => '0', + addr => (others => '0'), byte_sel => x"00", second_bytes => x"00", store_data => (others => '0'), instr_tag => instr_tag_init, write_reg => 6x"00", length => x"0", @@ -411,6 +413,7 @@ begin v.valid := l_in.valid; v.instr_tag := l_in.instr_tag; v.mode_32bit := l_in.mode_32bit; + v.prefixed := l_in.prefixed; v.write_reg := l_in.write_reg; v.length := l_in.length; v.elt_length := l_in.length; @@ -906,8 +909,10 @@ begin if exception = '1' then if r2.req.align_intr = '1' then v.intr_vec := 16#600#; + v.srr1(47 - 34) := r2.req.prefixed; v.dar := r2.req.addr; elsif r2.req.instr_fault = '0' then + v.srr1(47 - 34) := r2.req.prefixed; v.dar := r2.req.addr; if m_in.segerr = '0' then v.intr_vec := 16#300#;