mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-03-06 11:03:25 +00:00
core: Send FPU interrupts to writeback rather than execute1
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
26
common.vhdl
26
common.vhdl
@@ -139,6 +139,8 @@ package common is
|
||||
constant instr_tag_init : instr_tag_t := (tag => 0, valid => '0');
|
||||
function tag_match(tag1 : instr_tag_t; tag2 : instr_tag_t) return boolean;
|
||||
|
||||
subtype intr_vector_t is integer range 0 to 16#fff#;
|
||||
|
||||
-- For now, fixed 16 sources, make this either a parametric
|
||||
-- package of some sort or an unconstrainted array.
|
||||
type ics_to_icp_t is record
|
||||
@@ -449,9 +451,9 @@ package common is
|
||||
rc : std_ulogic;
|
||||
store_done : std_ulogic;
|
||||
interrupt : std_ulogic;
|
||||
intr_vec : integer range 0 to 16#fff#;
|
||||
intr_vec : intr_vector_t;
|
||||
srr0: std_ulogic_vector(63 downto 0);
|
||||
srr1: std_ulogic_vector(31 downto 0);
|
||||
srr1: std_ulogic_vector(15 downto 0);
|
||||
end record;
|
||||
constant Loadstore1ToWritebackInit : Loadstore1ToWritebackType :=
|
||||
(valid => '0', instr_tag => instr_tag_init, write_enable => '0',
|
||||
@@ -474,7 +476,7 @@ package common is
|
||||
write_xerc_enable : std_ulogic;
|
||||
xerc : xer_common_t;
|
||||
interrupt : std_ulogic;
|
||||
intr_vec : integer range 0 to 16#fff#;
|
||||
intr_vec : intr_vector_t;
|
||||
redirect: std_ulogic;
|
||||
redir_mode: std_ulogic_vector(3 downto 0);
|
||||
last_nia: std_ulogic_vector(63 downto 0);
|
||||
@@ -482,7 +484,7 @@ package common is
|
||||
br_last: std_ulogic;
|
||||
br_taken: std_ulogic;
|
||||
abs_br: std_ulogic;
|
||||
srr1: std_ulogic_vector(31 downto 0);
|
||||
srr1: std_ulogic_vector(15 downto 0);
|
||||
msr: std_ulogic_vector(63 downto 0);
|
||||
end record;
|
||||
constant Execute1ToWritebackInit : Execute1ToWritebackType :=
|
||||
@@ -521,13 +523,12 @@ package common is
|
||||
type FPUToExecute1Type is record
|
||||
busy : std_ulogic;
|
||||
exception : std_ulogic;
|
||||
interrupt : std_ulogic;
|
||||
illegal : std_ulogic;
|
||||
end record;
|
||||
constant FPUToExecute1Init : FPUToExecute1Type := (others => '0');
|
||||
|
||||
type FPUToWritebackType is record
|
||||
valid : std_ulogic;
|
||||
interrupt : std_ulogic;
|
||||
instr_tag : instr_tag_t;
|
||||
write_enable : std_ulogic;
|
||||
write_reg : gspr_index_t;
|
||||
@@ -535,10 +536,17 @@ package common is
|
||||
write_cr_enable : std_ulogic;
|
||||
write_cr_mask : std_ulogic_vector(7 downto 0);
|
||||
write_cr_data : std_ulogic_vector(31 downto 0);
|
||||
intr_vec : intr_vector_t;
|
||||
srr0 : std_ulogic_vector(63 downto 0);
|
||||
srr1 : std_ulogic_vector(15 downto 0);
|
||||
end record;
|
||||
constant FPUToWritebackInit : FPUToWritebackType := (valid => '0', instr_tag => instr_tag_init,
|
||||
write_enable => '0', write_cr_enable => '0',
|
||||
others => (others => '0'));
|
||||
constant FPUToWritebackInit : FPUToWritebackType :=
|
||||
(valid => '0', interrupt => '0', instr_tag => instr_tag_init,
|
||||
write_enable => '0', write_reg => (others => '0'),
|
||||
write_cr_enable => '0', write_cr_mask => (others => '0'),
|
||||
write_cr_data => (others => '0'),
|
||||
intr_vec => 0, srr1 => (others => '0'),
|
||||
others => (others => '0'));
|
||||
|
||||
type DividerToExecute1Type is record
|
||||
valid: std_ulogic;
|
||||
|
||||
@@ -750,19 +750,19 @@ begin
|
||||
-- become pending due to MSR[FE0,FE1] changing from 00 to non-zero.
|
||||
exception := '1';
|
||||
v.e.intr_vec := 16#700#;
|
||||
v.e.srr1(63 - 43) := '1';
|
||||
v.e.srr1(63 - 47) := '1';
|
||||
v.e.srr1(47 - 43) := '1';
|
||||
v.e.srr1(47 - 47) := '1';
|
||||
elsif r.trace_next = '1' then
|
||||
-- Generate a trace interrupt rather than executing the next instruction
|
||||
-- or taking any asynchronous interrupt
|
||||
exception := '1';
|
||||
v.e.intr_vec := 16#d00#;
|
||||
v.e.srr1(63 - 33) := '1';
|
||||
v.e.srr1(47 - 33) := '1';
|
||||
if r.prev_op = OP_LOAD or r.prev_op = OP_ICBI or r.prev_op = OP_ICBT or
|
||||
r.prev_op = OP_DCBT or r.prev_op = OP_DCBST or r.prev_op = OP_DCBF then
|
||||
v.e.srr1(63 - 35) := '1';
|
||||
v.e.srr1(47 - 35) := '1';
|
||||
elsif r.prev_op = OP_STORE or r.prev_op = OP_DCBZ or r.prev_op = OP_DCBTST then
|
||||
v.e.srr1(63 - 36) := '1';
|
||||
v.e.srr1(47 - 36) := '1';
|
||||
end if;
|
||||
|
||||
elsif irq_valid = '1' then
|
||||
@@ -775,7 +775,7 @@ begin
|
||||
exception := '1';
|
||||
v.e.intr_vec := 16#700#;
|
||||
-- set bit 45 to indicate privileged instruction type interrupt
|
||||
v.e.srr1(63 - 45) := '1';
|
||||
v.e.srr1(47 - 45) := '1';
|
||||
report "privileged instruction";
|
||||
|
||||
elsif not HAS_FPU and e_in.fac = FPU then
|
||||
@@ -840,7 +840,7 @@ begin
|
||||
-- trap instructions (tw, twi, td, tdi)
|
||||
v.e.intr_vec := 16#700#;
|
||||
-- set bit 46 to say trap occurred
|
||||
v.e.srr1(63 - 46) := '1';
|
||||
v.e.srr1(47 - 46) := '1';
|
||||
if or (trapval and insn_to(e_in.insn)) = '1' then
|
||||
-- generate trap-type program interrupt
|
||||
exception := '1';
|
||||
@@ -1124,22 +1124,12 @@ begin
|
||||
v.e.valid := '1';
|
||||
end if;
|
||||
|
||||
-- Generate FP-type program interrupt. fp_in.interrupt will only
|
||||
-- be set during the execution of a FP instruction.
|
||||
-- The case where MSR[FE0,FE1] goes from zero to non-zero is
|
||||
-- handled above by mtmsrd and rfid setting v.fp_exception_next.
|
||||
if HAS_FPU and fp_in.interrupt = '1' then
|
||||
v.e.intr_vec := 16#700#;
|
||||
v.e.srr1(63 - 43) := '1';
|
||||
exception := '1';
|
||||
end if;
|
||||
|
||||
if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then
|
||||
if illegal = '1' then
|
||||
exception := '1';
|
||||
v.e.intr_vec := 16#700#;
|
||||
-- Since we aren't doing Hypervisor emulation assist (0xe40) we
|
||||
-- set bit 44 to indicate we have an illegal
|
||||
v.e.srr1(63 - 44) := '1';
|
||||
v.e.srr1(47 - 44) := '1';
|
||||
report "illegal";
|
||||
end if;
|
||||
|
||||
|
||||
12
fpu.vhdl
12
fpu.vhdl
@@ -73,8 +73,10 @@ architecture behaviour of fpu is
|
||||
busy : std_ulogic;
|
||||
instr_done : std_ulogic;
|
||||
do_intr : std_ulogic;
|
||||
illegal : std_ulogic;
|
||||
op : insn_type_t;
|
||||
insn : std_ulogic_vector(31 downto 0);
|
||||
nia : std_ulogic_vector(63 downto 0);
|
||||
instr_tag : instr_tag_t;
|
||||
dest_fpr : gspr_index_t;
|
||||
fe_mode : std_ulogic;
|
||||
@@ -572,7 +574,6 @@ begin
|
||||
|
||||
e_out.busy <= r.busy;
|
||||
e_out.exception <= r.fpscr(FPSCR_FEX);
|
||||
e_out.interrupt <= r.do_intr;
|
||||
|
||||
w_out.valid <= r.instr_done and not r.do_intr;
|
||||
w_out.instr_tag <= r.instr_tag;
|
||||
@@ -583,6 +584,10 @@ begin
|
||||
w_out.write_cr_mask <= r.cr_mask;
|
||||
w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result &
|
||||
r.cr_result & r.cr_result & r.cr_result & r.cr_result;
|
||||
w_out.interrupt <= r.do_intr;
|
||||
w_out.intr_vec <= 16#700#;
|
||||
w_out.srr0 <= r.nia;
|
||||
w_out.srr1 <= (47-44 => r.illegal, 47-43 => not r.illegal, others => '0');
|
||||
|
||||
fpu_1: process(all)
|
||||
variable v : reg_type;
|
||||
@@ -644,6 +649,7 @@ begin
|
||||
-- capture incoming instruction
|
||||
if e_in.valid = '1' then
|
||||
v.insn := e_in.insn;
|
||||
v.nia := e_in.nia;
|
||||
v.op := e_in.op;
|
||||
v.instr_tag := e_in.itag;
|
||||
v.fe_mode := or (e_in.fe_mode);
|
||||
@@ -2543,9 +2549,10 @@ begin
|
||||
v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
|
||||
end if;
|
||||
|
||||
v.illegal := illegal;
|
||||
if illegal = '1' then
|
||||
v.instr_done := '0';
|
||||
v.do_intr := '0';
|
||||
v.do_intr := '1';
|
||||
v.writing_back := '0';
|
||||
v.busy := '0';
|
||||
v.state := IDLE;
|
||||
@@ -2557,7 +2564,6 @@ begin
|
||||
end if;
|
||||
|
||||
rin <= v;
|
||||
e_out.illegal <= illegal;
|
||||
end process;
|
||||
|
||||
end architecture behaviour;
|
||||
|
||||
@@ -108,7 +108,7 @@ architecture behave of loadstore1 is
|
||||
interrupt : std_ulogic;
|
||||
intr_vec : integer range 0 to 16#fff#;
|
||||
nia : std_ulogic_vector(63 downto 0);
|
||||
srr1 : std_ulogic_vector(31 downto 0);
|
||||
srr1 : std_ulogic_vector(15 downto 0);
|
||||
end record;
|
||||
|
||||
signal r, rin : reg_stage_t;
|
||||
@@ -721,10 +721,10 @@ begin
|
||||
end if;
|
||||
else
|
||||
if m_in.segerr = '0' then
|
||||
v.srr1(63 - 33) := m_in.invalid;
|
||||
v.srr1(63 - 35) := m_in.perm_error; -- noexec fault
|
||||
v.srr1(63 - 44) := m_in.badtree;
|
||||
v.srr1(63 - 45) := m_in.rc_error;
|
||||
v.srr1(47 - 33) := m_in.invalid;
|
||||
v.srr1(47 - 35) := m_in.perm_error; -- noexec fault
|
||||
v.srr1(47 - 44) := m_in.badtree;
|
||||
v.srr1(47 - 45) := m_in.rc_error;
|
||||
v.intr_vec := 16#400#;
|
||||
else
|
||||
v.intr_vec := 16#480#;
|
||||
|
||||
@@ -82,6 +82,8 @@ begin
|
||||
variable sign : std_ulogic;
|
||||
variable scf : std_ulogic_vector(3 downto 0);
|
||||
variable vec : integer range 0 to 16#fff#;
|
||||
variable srr1 : std_ulogic_vector(15 downto 0);
|
||||
variable intr : std_ulogic;
|
||||
begin
|
||||
w_out <= WritebackToRegisterFileInit;
|
||||
c_out <= WritebackToCrFileInit;
|
||||
@@ -99,6 +101,8 @@ begin
|
||||
complete_out <= fp_in.instr_tag;
|
||||
end if;
|
||||
|
||||
intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt;
|
||||
|
||||
if r.state = WRITE_SRR1 then
|
||||
w_out.write_reg <= fast_spr_num(SPR_SRR1);
|
||||
w_out.write_data <= r.srr1;
|
||||
@@ -106,23 +110,29 @@ begin
|
||||
interrupt_out <= '1';
|
||||
v.state := WRITE_SRR0;
|
||||
|
||||
elsif e_in.interrupt = '1' then
|
||||
elsif intr = '1' then
|
||||
w_out.write_reg <= fast_spr_num(SPR_SRR0);
|
||||
w_out.write_data <= e_in.last_nia;
|
||||
w_out.write_enable <= '1';
|
||||
v.state := WRITE_SRR1;
|
||||
v.srr1(63 downto 32) := e_in.msr(63 downto 32);
|
||||
v.srr1(31 downto 0) := e_in.msr(31 downto 0) or e_in.srr1;
|
||||
vec := e_in.intr_vec;
|
||||
|
||||
elsif l_in.interrupt = '1' then
|
||||
w_out.write_reg <= fast_spr_num(SPR_SRR0);
|
||||
w_out.write_data <= l_in.srr0;
|
||||
w_out.write_enable <= '1';
|
||||
v.state := WRITE_SRR1;
|
||||
v.srr1(63 downto 32) := e_in.msr(63 downto 32);
|
||||
v.srr1(31 downto 0) := e_in.msr(31 downto 0) or l_in.srr1;
|
||||
vec := l_in.intr_vec;
|
||||
srr1 := (others => '0');
|
||||
if e_in.interrupt = '1' then
|
||||
vec := e_in.intr_vec;
|
||||
w_out.write_data <= e_in.last_nia;
|
||||
srr1 := e_in.srr1;
|
||||
elsif l_in.interrupt = '1' then
|
||||
vec := l_in.intr_vec;
|
||||
w_out.write_data <= l_in.srr0;
|
||||
srr1 := l_in.srr1;
|
||||
elsif fp_in.interrupt = '1' then
|
||||
vec := fp_in.intr_vec;
|
||||
w_out.write_data <= fp_in.srr0;
|
||||
srr1 := fp_in.srr1;
|
||||
end if;
|
||||
v.srr1(63 downto 31) := e_in.msr(63 downto 31);
|
||||
v.srr1(30 downto 27) := srr1(14 downto 11);
|
||||
v.srr1(26 downto 22) := e_in.msr(26 downto 22);
|
||||
v.srr1(21 downto 16) := srr1(5 downto 0);
|
||||
v.srr1(15 downto 0) := e_in.msr(15 downto 0);
|
||||
|
||||
else
|
||||
if e_in.write_enable = '1' then
|
||||
@@ -196,7 +206,7 @@ begin
|
||||
f.br_nia := e_in.last_nia;
|
||||
f.br_last := e_in.br_last;
|
||||
f.br_taken := e_in.br_taken;
|
||||
if e_in.interrupt = '1' or l_in.interrupt = '1' then
|
||||
if intr = '1' then
|
||||
f.redirect := '1';
|
||||
f.br_last := '0';
|
||||
f.redirect_nia := std_ulogic_vector(to_unsigned(vec, 64));
|
||||
|
||||
Reference in New Issue
Block a user