Implement interrupts for prefixed instructions

This arranges to generate an illegal instruction type program
interrupt for illegal prefixed instructions, that is, those where the
suffix is not a legal value given the prefix, or the prefix has a
reserved value in the subtype field.  This implementation doesn't
generate an interrupt for the invalid 8LS:D and MLS:D instruction
forms where R = 1 and RA != 0.  (In those cases it uses (RA) as the
addend, i.e. it ignores the R bit.)

This detects the case where the address of an instruction prefix is
equal mod 64 to 60, and generates an alignment interrupt in that case.

This also arranges to set bit 34 of SRR1 when an interrupt occurs due
to a prefixed instruction, for those interrupts where that is required
(i.e. trace, alignment, floating-point unavailable, data storage, data
segment, and most cases of program interrupt).

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/419/head
Paul Mackerras 1 year ago
parent 39ca675ce3
commit c4492c843a

@ -266,6 +266,7 @@ package common is
prefixed: std_ulogic; prefixed: std_ulogic;
prefix: std_ulogic_vector(25 downto 0); prefix: std_ulogic_vector(25 downto 0);
illegal_suffix: std_ulogic; illegal_suffix: std_ulogic;
misaligned_prefix: std_ulogic;
insn: std_ulogic_vector(31 downto 0); insn: std_ulogic_vector(31 downto 0);
decode: decode_rom_t; decode: decode_rom_t;
br_pred: std_ulogic; -- Branch was predicted to be taken br_pred: std_ulogic; -- Branch was predicted to be taken
@ -279,7 +280,7 @@ package common is
constant Decode1ToDecode2Init : Decode1ToDecode2Type := constant Decode1ToDecode2Init : Decode1ToDecode2Type :=
(valid => '0', stop_mark => '0', nia => (others => '0'), (valid => '0', stop_mark => '0', nia => (others => '0'),
prefixed => '0', prefix => (others => '0'), insn => (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', decode => decode_rom_init, br_pred => '0', big_endian => '0',
spr_info => spr_id_init, ram_spr => ram_spr_info_init, spr_info => spr_id_init, ram_spr => ram_spr_info_init,
reg_a => (others => '0'), reg_b => (others => '0'), reg_c => (others => '0')); reg_a => (others => '0'), reg_b => (others => '0'), reg_c => (others => '0'));
@ -364,6 +365,9 @@ package common is
ramspr_write_odd : std_ulogic; ramspr_write_odd : std_ulogic;
dbg_spr_access : std_ulogic; dbg_spr_access : std_ulogic;
dec_ctr : std_ulogic; dec_ctr : std_ulogic;
prefixed : std_ulogic;
illegal_suffix : std_ulogic;
misaligned_prefix : std_ulogic;
end record; end record;
constant Decode2ToExecute1Init : Decode2ToExecute1Type := constant Decode2ToExecute1Init : Decode2ToExecute1Type :=
(valid => '0', unit => ALU, fac => NONE, insn_type => OP_ILLEGAL, instr_tag => instr_tag_init, (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', ramspr_wraddr => (others => '0'), ramspr_write_even => '0', ramspr_write_odd => '0',
dbg_spr_access => '0', dbg_spr_access => '0',
dec_ctr => '0', dec_ctr => '0',
prefixed => '0', illegal_suffix => '0', misaligned_prefix => '0',
others => (others => '0')); others => (others => '0'));


type MultiplyInputType is record type MultiplyInputType is record
@ -505,6 +510,7 @@ package common is
priv_mode : std_ulogic; -- privileged mode (MSR[PR] = 0) priv_mode : std_ulogic; -- privileged mode (MSR[PR] = 0)
mode_32bit : std_ulogic; -- trim addresses to 32 bits mode_32bit : std_ulogic; -- trim addresses to 32 bits
is_32bit : std_ulogic; is_32bit : std_ulogic;
prefixed : std_ulogic;
repeat : std_ulogic; repeat : std_ulogic;
second : std_ulogic; second : std_ulogic;
e2stall : std_ulogic; e2stall : std_ulogic;
@ -519,7 +525,7 @@ package common is
addr1 => (others => '0'), addr2 => (others => '0'), data => (others => '0'), addr1 => (others => '0'), addr2 => (others => '0'), data => (others => '0'),
write_reg => (others => '0'), write_reg => (others => '0'),
length => (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', repeat => '0', second => '0', e2stall => '0',
msr => (others => '0')); msr => (others => '0'));



@ -572,7 +572,13 @@ begin
pv.prefixed := '1'; pv.prefixed := '1';
pv.pref_ia := f_in.nia(5 downto 2); pv.pref_ia := f_in.nia(5 downto 2);
pv.prefix := f_in.insn(25 downto 0); 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; end if;
decode_rom_addr <= insn_code'val(to_integer(unsigned(icode_bits))); decode_rom_addr <= insn_code'val(to_integer(unsigned(icode_bits)));

@ -371,21 +371,27 @@ begin
c_out.read <= d_in.decode.input_cr; c_out.read <= d_in.decode.input_cr;


decode2_addrs: process(all) decode2_addrs: process(all)
variable dec_a, dec_b, dec_c : decode_input_reg_t;
variable dec_o : decode_output_reg_t;
begin begin
decoded_reg_a <= decode_input_reg_init; dec_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_init; dec_b := decode_input_reg_b (d_in.decode.input_reg_b, d_in.insn, d_in.prefix);
decoded_reg_c <= decode_input_reg_init; dec_c := decode_input_reg_c (d_in.decode.input_reg_c, d_in.insn);
decoded_reg_o <= decode_output_reg_init; dec_o := decode_output_reg (d_in.decode.output_reg_a, d_in.insn);
if d_in.valid = '1' then if d_in.valid = '0' or d_in.illegal_suffix = '1' then
decoded_reg_a <= decode_input_reg_a (d_in.decode.input_reg_a, d_in.insn, d_in.prefix, d_in.nia); dec_a.reg_valid := '0';
decoded_reg_b <= decode_input_reg_b (d_in.decode.input_reg_b, d_in.insn, d_in.prefix); dec_b.reg_valid := '0';
decoded_reg_c <= decode_input_reg_c (d_in.decode.input_reg_c, d_in.insn); dec_c.reg_valid := '0';
decoded_reg_o <= decode_output_reg (d_in.decode.output_reg_a, d_in.insn); dec_o.reg_valid := '0';
end if; end if;


r_out.read1_enable <= decoded_reg_a.reg_valid; decoded_reg_a <= dec_a;
r_out.read2_enable <= decoded_reg_b.reg_valid; decoded_reg_b <= dec_b;
r_out.read3_enable <= decoded_reg_c.reg_valid; 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; end process;


@ -592,6 +598,9 @@ begin
v.e.result_sel := "001"; -- logical_result v.e.result_sel := "001"; -- logical_result
end if; end if;
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 elsif dc2.e.valid = '1' then
-- dc2.busy = 1 and dc2.e.valid = 1, thus this must be a repeated instruction. -- dc2.busy = 1 and dc2.e.valid = 1, thus this must be a repeated instruction.

@ -118,6 +118,7 @@ architecture behaviour of execute1 is
fp_exception_next : std_ulogic; fp_exception_next : std_ulogic;
trace_next : std_ulogic; trace_next : std_ulogic;
prev_op : insn_type_t; prev_op : insn_type_t;
prev_prefixed : std_ulogic;
oe : std_ulogic; oe : std_ulogic;
mul_select : std_ulogic_vector(1 downto 0); mul_select : std_ulogic_vector(1 downto 0);
res2_sel : 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, (e => Execute1ToWritebackInit, se => side_effect_init,
busy => '0', busy => '0',
fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL, fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL,
prev_prefixed => '0',
oe => '0', mul_select => "00", res2_sel => "00", oe => '0', mul_select => "00", res2_sel => "00",
spr_select => spr_id_init, pmu_spr_num => 5x"0", spr_select => spr_id_init, pmu_spr_num => 5x"0",
mul_in_progress => '0', mul_finish => '0', div_in_progress => '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 bo, bi : std_ulogic_vector(4 downto 0);
variable illegal : std_ulogic; variable illegal : std_ulogic;
variable privileged : std_ulogic; variable privileged : std_ulogic;
variable misaligned : std_ulogic;
variable slow_op : std_ulogic; variable slow_op : std_ulogic;
variable owait : std_ulogic; variable owait : std_ulogic;
variable srr1 : std_ulogic_vector(63 downto 0); variable srr1 : std_ulogic_vector(63 downto 0);
@ -1021,10 +1024,13 @@ begin


illegal := '0'; illegal := '0';
privileged := '0'; privileged := '0';
misaligned := e_in.misaligned_prefix;
slow_op := '0'; slow_op := '0';
owait := '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'; privileged := '1';
end if; end if;


@ -1315,9 +1321,22 @@ begin
end if; end if;
end case; 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 -- generate a program interrupt
v.exception := '1'; v.exception := '1';
v.e.srr1(47 - 34) := e_in.prefixed;
-- set bit 45 to indicate privileged instruction type interrupt -- set bit 45 to indicate privileged instruction type interrupt
v.e.srr1(47 - 45) := '1'; v.e.srr1(47 - 45) := '1';
if e_in.valid = '1' then if e_in.valid = '1' then
@ -1326,6 +1345,7 @@ begin


elsif illegal = '1' then elsif illegal = '1' then
v.exception := '1'; v.exception := '1';
v.e.srr1(47 - 34) := e_in.prefixed;
-- Since we aren't doing Hypervisor emulation assist (0xe40) we -- Since we aren't doing Hypervisor emulation assist (0xe40) we
-- set bit 44 to indicate we have an illegal -- set bit 44 to indicate we have an illegal
v.e.srr1(47 - 44) := '1'; 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 elsif HAS_FPU and ex1.msr(MSR_FP) = '0' and e_in.fac = FPU then
-- generate a floating-point unavailable interrupt -- generate a floating-point unavailable interrupt
v.exception := '1'; v.exception := '1';
v.e.srr1(47 - 34) := e_in.prefixed;
v.e.intr_vec := 16#800#; v.e.intr_vec := 16#800#;
if e_in.valid = '1' then if e_in.valid = '1' then
report "FP unavailable interrupt"; report "FP unavailable interrupt";
@ -1401,6 +1422,7 @@ begin


if valid_in = '1' then if valid_in = '1' then
v.prev_op := e_in.insn_type; v.prev_op := e_in.insn_type;
v.prev_prefixed := e_in.prefixed;
end if; end if;


-- Determine if there is any interrupt to be taken -- Determine if there is any interrupt to be taken
@ -1422,6 +1444,7 @@ begin
v.e.intr_vec := 16#d00#; v.e.intr_vec := 16#d00#;
v.e.srr1 := (others => '0'); v.e.srr1 := (others => '0');
v.e.srr1(47 - 33) := '1'; 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 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 ex1.prev_op = OP_DCBT or ex1.prev_op = OP_DCBST or ex1.prev_op = OP_DCBF then
v.e.srr1(47 - 35) := '1'; v.e.srr1(47 - 35) := '1';
@ -1584,6 +1607,7 @@ begin
lv.priv_mode := not ex1.msr(MSR_PR); lv.priv_mode := not ex1.msr(MSR_PR);
lv.mode_32bit := not ex1.msr(MSR_SF); lv.mode_32bit := not ex1.msr(MSR_SF);
lv.is_32bit := e_in.is_32bit; lv.is_32bit := e_in.is_32bit;
lv.prefixed := e_in.prefixed;
lv.repeat := e_in.repeat; lv.repeat := e_in.repeat;
lv.second := e_in.second; lv.second := e_in.second;
lv.e2stall := fp_in.f2stall; lv.e2stall := fp_in.f2stall;

@ -69,6 +69,7 @@ architecture behave of loadstore1 is
instr_fault : std_ulogic; instr_fault : std_ulogic;
do_update : std_ulogic; do_update : std_ulogic;
mode_32bit : std_ulogic; mode_32bit : std_ulogic;
prefixed : std_ulogic;
addr : std_ulogic_vector(63 downto 0); addr : std_ulogic_vector(63 downto 0);
byte_sel : std_ulogic_vector(7 downto 0); byte_sel : std_ulogic_vector(7 downto 0);
second_bytes : 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', 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', dcbz => '0', read_spr => '0', write_spr => '0', mmu_op => '0',
instr_fault => '0', do_update => '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", byte_sel => x"00", second_bytes => x"00",
store_data => (others => '0'), instr_tag => instr_tag_init, store_data => (others => '0'), instr_tag => instr_tag_init,
write_reg => 6x"00", length => x"0", write_reg => 6x"00", length => x"0",
@ -411,6 +413,7 @@ begin
v.valid := l_in.valid; v.valid := l_in.valid;
v.instr_tag := l_in.instr_tag; v.instr_tag := l_in.instr_tag;
v.mode_32bit := l_in.mode_32bit; v.mode_32bit := l_in.mode_32bit;
v.prefixed := l_in.prefixed;
v.write_reg := l_in.write_reg; v.write_reg := l_in.write_reg;
v.length := l_in.length; v.length := l_in.length;
v.elt_length := l_in.length; v.elt_length := l_in.length;
@ -906,8 +909,10 @@ begin
if exception = '1' then if exception = '1' then
if r2.req.align_intr = '1' then if r2.req.align_intr = '1' then
v.intr_vec := 16#600#; v.intr_vec := 16#600#;
v.srr1(47 - 34) := r2.req.prefixed;
v.dar := r2.req.addr; v.dar := r2.req.addr;
elsif r2.req.instr_fault = '0' then elsif r2.req.instr_fault = '0' then
v.srr1(47 - 34) := r2.req.prefixed;
v.dar := r2.req.addr; v.dar := r2.req.addr;
if m_in.segerr = '0' then if m_in.segerr = '0' then
v.intr_vec := 16#300#; v.intr_vec := 16#300#;

Loading…
Cancel
Save