mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-04-17 16:03:03 +00:00
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>
This commit is contained in:
10
common.vhdl
10
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'));
|
||||
|
||||
|
||||
@@ -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)));
|
||||
|
||||
33
decode2.vhdl
33
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.
|
||||
|
||||
@@ -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#;
|
||||
|
||||
Reference in New Issue
Block a user