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 10 months ago
parent 39ca675ce3
commit c4492c843a

@ -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'));


@ -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)));

@ -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.

@ -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;

@ -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#;

Loading…
Cancel
Save