mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
Merge pull request #452 from paulusmack/master
SPR and interrupt bug fixes, implement LPCR[EVIRT], plus logic/timing improvements
This commit is contained in:
commit
fabe9a4feb
@ -249,6 +249,7 @@ package common is
|
||||
-- LPCR bit numbers
|
||||
constant LPCR_HAIL : integer := 63 - 37;
|
||||
constant LPCR_UPRT : integer := 63 - 41;
|
||||
constant LPCR_EVIRT : integer := 63 - 42;
|
||||
constant LPCR_HR : integer := 63 - 43;
|
||||
constant LPCR_LD : integer := 63 - 46;
|
||||
constant LPCR_HEIC : integer := 63 - 59;
|
||||
@ -322,6 +323,7 @@ package common is
|
||||
hdexcr_hyp: aspect_bits_t;
|
||||
hdexcr_enf: aspect_bits_t;
|
||||
lpcr_hail: std_ulogic;
|
||||
lpcr_evirt: std_ulogic;
|
||||
lpcr_ld: std_ulogic;
|
||||
lpcr_heic: std_ulogic;
|
||||
lpcr_lpes: std_ulogic;
|
||||
@ -333,7 +335,7 @@ package common is
|
||||
dscr => (others => '0'),
|
||||
dexcr_pnh => aspect_bits_init, dexcr_pro => aspect_bits_init,
|
||||
hdexcr_hyp => aspect_bits_init, hdexcr_enf => aspect_bits_init,
|
||||
lpcr_hail => '0', lpcr_ld => '1', lpcr_heic => '0',
|
||||
lpcr_hail => '0', lpcr_evirt => '0', lpcr_ld => '1', lpcr_heic => '0',
|
||||
lpcr_lpes => '0', lpcr_hvice => '0',
|
||||
others => (others => '0'));
|
||||
|
||||
@ -420,9 +422,11 @@ package common is
|
||||
|
||||
type bypass_data_t is record
|
||||
tag : instr_tag_t;
|
||||
reg : gspr_index_t;
|
||||
data : std_ulogic_vector(63 downto 0);
|
||||
end record;
|
||||
constant bypass_data_init : bypass_data_t := (tag => instr_tag_init, data => (others => '0'));
|
||||
constant bypass_data_init : bypass_data_t :=
|
||||
(tag => instr_tag_init, reg => (others => '0'), data => (others => '0'));
|
||||
|
||||
type cr_bypass_data_t is record
|
||||
tag : instr_tag_t;
|
||||
|
||||
93
control.vhdl
93
control.vhdl
@ -32,9 +32,10 @@ entity control is
|
||||
gpr_c_read_valid_in : in std_ulogic;
|
||||
gpr_c_read_in : in gspr_index_t;
|
||||
|
||||
execute_next_tag : in instr_tag_t;
|
||||
execute_next_bypass : in bypass_data_t;
|
||||
execute2_next_bypass : in bypass_data_t;
|
||||
writeback_bypass : in bypass_data_t;
|
||||
execute_next_cr_tag : in instr_tag_t;
|
||||
execute2_next_tag : in instr_tag_t;
|
||||
execute2_next_cr_tag : in instr_tag_t;
|
||||
|
||||
cr_read_in : in std_ulogic;
|
||||
@ -166,56 +167,78 @@ begin
|
||||
begin
|
||||
tag_a := instr_tag_init;
|
||||
for i in tag_number_t loop
|
||||
if tag_regs(i).wr_gpr = '1' and tag_regs(i).recent = '1' and tag_regs(i).reg = gpr_a_read_in then
|
||||
if tag_regs(i).valid = '1' and tag_regs(i).recent = '1' and
|
||||
tag_regs(i).reg = gpr_a_read_in and gpr_a_read_valid_in = '1' then
|
||||
tag_a.valid := '1';
|
||||
tag_a.tag := i;
|
||||
if (EX1_BYPASS and tag_match(execute_next_bypass.tag, tag_a)) or
|
||||
(EX1_BYPASS and tag_match(execute2_next_bypass.tag, tag_a)) or
|
||||
tag_match(complete_in, tag_a) then
|
||||
tag_a.valid := '0';
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
tag_b := instr_tag_init;
|
||||
for i in tag_number_t loop
|
||||
if tag_regs(i).wr_gpr = '1' and tag_regs(i).recent = '1' and tag_regs(i).reg = gpr_b_read_in then
|
||||
tag_b.valid := '1';
|
||||
tag_b.tag := i;
|
||||
end if;
|
||||
end loop;
|
||||
tag_c := instr_tag_init;
|
||||
for i in tag_number_t loop
|
||||
if tag_regs(i).wr_gpr = '1' and tag_regs(i).recent = '1' and tag_regs(i).reg = gpr_c_read_in then
|
||||
tag_c.valid := '1';
|
||||
tag_c.tag := i;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
byp_a := "0000";
|
||||
if EX1_BYPASS and tag_match(execute_next_tag, tag_a) then
|
||||
if EX1_BYPASS and execute_next_bypass.tag.valid = '1' and
|
||||
execute_next_bypass.reg = gpr_a_read_in then
|
||||
byp_a(1) := '1';
|
||||
end if;
|
||||
if EX1_BYPASS and tag_match(execute2_next_tag, tag_a) then
|
||||
elsif EX1_BYPASS and execute2_next_bypass.tag.valid = '1' and
|
||||
execute2_next_bypass.reg = gpr_a_read_in then
|
||||
byp_a(2) := '1';
|
||||
end if;
|
||||
if tag_match(complete_in, tag_a) then
|
||||
elsif writeback_bypass.tag.valid = '1' and
|
||||
writeback_bypass.reg = gpr_a_read_in then
|
||||
byp_a(3) := '1';
|
||||
end if;
|
||||
byp_a(0) := gpr_a_read_valid_in and (byp_a(1) or byp_a(2) or byp_a(3));
|
||||
|
||||
tag_b := instr_tag_init;
|
||||
for i in tag_number_t loop
|
||||
if tag_regs(i).valid = '1' and tag_regs(i).recent = '1' and
|
||||
tag_regs(i).reg = gpr_b_read_in and gpr_b_read_valid_in = '1' then
|
||||
tag_b.valid := '1';
|
||||
tag_b.tag := i;
|
||||
if (EX1_BYPASS and tag_match(execute_next_bypass.tag, tag_b)) or
|
||||
(EX1_BYPASS and tag_match(execute2_next_bypass.tag, tag_b)) or
|
||||
tag_match(complete_in, tag_b) then
|
||||
tag_b.valid := '0';
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
byp_b := "0000";
|
||||
if EX1_BYPASS and tag_match(execute_next_tag, tag_b) then
|
||||
if EX1_BYPASS and execute_next_bypass.tag.valid = '1' and
|
||||
execute_next_bypass.reg = gpr_b_read_in then
|
||||
byp_b(1) := '1';
|
||||
end if;
|
||||
if EX1_BYPASS and tag_match(execute2_next_tag, tag_b) then
|
||||
elsif EX1_BYPASS and execute2_next_bypass.tag.valid = '1' and
|
||||
execute2_next_bypass.reg = gpr_b_read_in then
|
||||
byp_b(2) := '1';
|
||||
end if;
|
||||
if tag_match(complete_in, tag_b) then
|
||||
elsif writeback_bypass.tag.valid = '1' and
|
||||
writeback_bypass.reg = gpr_b_read_in then
|
||||
byp_b(3) := '1';
|
||||
end if;
|
||||
byp_b(0) := gpr_b_read_valid_in and (byp_b(1) or byp_b(2) or byp_b(3));
|
||||
|
||||
tag_c := instr_tag_init;
|
||||
for i in tag_number_t loop
|
||||
if tag_regs(i).valid = '1' and tag_regs(i).recent = '1' and
|
||||
tag_regs(i).reg = gpr_c_read_in and gpr_c_read_valid_in = '1' then
|
||||
tag_c.valid := '1';
|
||||
tag_c.tag := i;
|
||||
if (EX1_BYPASS and tag_match(execute_next_bypass.tag, tag_c)) or
|
||||
(EX1_BYPASS and tag_match(execute2_next_bypass.tag, tag_c)) or
|
||||
tag_match(complete_in, tag_c) then
|
||||
tag_c.valid := '0';
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
byp_c := "0000";
|
||||
if EX1_BYPASS and tag_match(execute_next_tag, tag_c) then
|
||||
if EX1_BYPASS and execute_next_bypass.tag.valid = '1' and
|
||||
execute_next_bypass.reg = gpr_c_read_in then
|
||||
byp_c(1) := '1';
|
||||
end if;
|
||||
if EX1_BYPASS and tag_match(execute2_next_tag, tag_c) then
|
||||
elsif EX1_BYPASS and execute2_next_bypass.tag.valid = '1' and
|
||||
execute2_next_bypass.reg = gpr_c_read_in then
|
||||
byp_c(2) := '1';
|
||||
end if;
|
||||
if tag_match(complete_in, tag_c) then
|
||||
elsif writeback_bypass.tag.valid = '1' and
|
||||
writeback_bypass.reg = gpr_c_read_in then
|
||||
byp_c(3) := '1';
|
||||
end if;
|
||||
byp_c(0) := gpr_c_read_valid_in and (byp_c(1) or byp_c(2) or byp_c(3));
|
||||
@ -224,9 +247,7 @@ begin
|
||||
gpr_bypass_b <= byp_b;
|
||||
gpr_bypass_c <= byp_c;
|
||||
|
||||
gpr_tag_stall <= (tag_a.valid and gpr_a_read_valid_in and not byp_a(0)) or
|
||||
(tag_b.valid and gpr_b_read_valid_in and not byp_b(0)) or
|
||||
(tag_c.valid and gpr_c_read_valid_in and not byp_c(0));
|
||||
gpr_tag_stall <= tag_a.valid or tag_b.valid or tag_c.valid;
|
||||
|
||||
incr_tag := curr_tag;
|
||||
instr_tag.tag <= curr_tag;
|
||||
|
||||
@ -279,10 +279,11 @@ begin
|
||||
gpr_c_read_valid_in => gpr_c_read_valid,
|
||||
gpr_c_read_in => gpr_c_read,
|
||||
|
||||
execute_next_tag => execute_bypass.tag,
|
||||
execute_next_bypass => execute_bypass,
|
||||
execute_next_cr_tag => execute_cr_bypass.tag,
|
||||
execute2_next_tag => execute2_bypass.tag,
|
||||
execute2_next_bypass => execute2_bypass,
|
||||
execute2_next_cr_tag => execute2_cr_bypass.tag,
|
||||
writeback_bypass => writeback_bypass,
|
||||
|
||||
cr_read_in => cr_read_valid,
|
||||
cr_write_in => cr_write_valid,
|
||||
|
||||
@ -106,7 +106,6 @@ architecture behaviour of execute1 is
|
||||
scv_trap : std_ulogic;
|
||||
write_tbl : std_ulogic;
|
||||
write_tbu : std_ulogic;
|
||||
noop_spr_read : std_ulogic;
|
||||
send_hmsg : std_ulogic_vector(NCPUS-1 downto 0);
|
||||
clr_hmsg : std_ulogic;
|
||||
end record;
|
||||
@ -426,6 +425,7 @@ architecture behaviour of execute1 is
|
||||
begin
|
||||
ret := (others => '0');
|
||||
ret(LPCR_HAIL) := c.lpcr_hail;
|
||||
ret(LPCR_EVIRT) := c.lpcr_evirt;
|
||||
ret(LPCR_UPRT) := '1';
|
||||
ret(LPCR_HR) := '1';
|
||||
ret(LPCR_LD) := c.lpcr_ld;
|
||||
@ -1216,6 +1216,7 @@ begin
|
||||
variable owait : std_ulogic;
|
||||
variable srr1 : std_ulogic_vector(63 downto 0);
|
||||
variable c32, c64 : std_ulogic;
|
||||
variable sprnum : spr_num_t;
|
||||
begin
|
||||
v := actions_type_init;
|
||||
v.e.write_data := alu_result;
|
||||
@ -1224,7 +1225,7 @@ begin
|
||||
v.e.rc := e_in.rc;
|
||||
v.e.write_cr_data := write_cr_data;
|
||||
v.e.write_cr_mask := write_cr_mask;
|
||||
v.e.write_cr_enable := e_in.output_cr;
|
||||
v.e.write_cr_enable := e_in.output_cr or e_in.rc;
|
||||
v.e.write_xerc_enable := e_in.output_xer;
|
||||
v.e.xerc := xerc_in;
|
||||
v.new_msr := ex1.msr;
|
||||
@ -1424,17 +1425,20 @@ begin
|
||||
when OP_DARN =>
|
||||
when OP_MFMSR =>
|
||||
when OP_MFSPR =>
|
||||
sprnum := decode_spr_num(e_in.insn);
|
||||
if e_in.spr_is_ram = '1' then
|
||||
if e_in.valid = '1' and not is_X(e_in.insn) then
|
||||
report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
|
||||
report "MFSPR to SPR " & integer'image(sprnum) &
|
||||
"=" & to_hstring(alu_result);
|
||||
end if;
|
||||
elsif e_in.spr_select.valid = '1' and e_in.spr_select.wonly = '0' then
|
||||
if e_in.valid = '1' and not is_X(e_in.insn) then
|
||||
report "MFSPR to slow SPR " & integer'image(decode_spr_num(e_in.insn));
|
||||
report "MFSPR to slow SPR " & integer'image(sprnum);
|
||||
end if;
|
||||
slow_op := '1';
|
||||
v.se.noop_spr_read := e_in.spr_select.noop;
|
||||
if e_in.spr_select.noop = '1' then
|
||||
v.e.write_enable := '0';
|
||||
end if;
|
||||
if e_in.spr_select.ispmu = '0' then
|
||||
case e_in.spr_select.sel is
|
||||
when SPRSEL_LOGR =>
|
||||
@ -1449,14 +1453,15 @@ begin
|
||||
end if;
|
||||
else
|
||||
-- mfspr from unimplemented SPRs should be a nop in
|
||||
-- supervisor mode and a program interrupt for user mode
|
||||
-- supervisor mode and a program or HEAI interrupt for user mode
|
||||
-- LPCR[EVIRT] = 1 makes it HEAI in privileged mode
|
||||
if e_in.valid = '1' and not is_X(e_in.insn) then
|
||||
report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
|
||||
" invalid";
|
||||
report "MFSPR to SPR " & integer'image(sprnum) & " invalid";
|
||||
end if;
|
||||
slow_op := '1';
|
||||
v.se.noop_spr_read := '1';
|
||||
if ex1.msr(MSR_PR) = '1' then
|
||||
v.e.write_enable := '0';
|
||||
if ex1.msr(MSR_PR) = '1' or ctrl.lpcr_evirt = '1' or
|
||||
sprnum = 0 or sprnum = 4 or sprnum = 5 or sprnum = 6 then
|
||||
illegal := '1';
|
||||
end if;
|
||||
end if;
|
||||
@ -1502,8 +1507,9 @@ begin
|
||||
end if;
|
||||
end if;
|
||||
when OP_MTSPR =>
|
||||
sprnum := decode_spr_num(e_in.insn);
|
||||
if e_in.valid = '1' and not is_X(e_in.insn) then
|
||||
report "MTSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
|
||||
report "MTSPR to SPR " & integer'image(sprnum) &
|
||||
"=" & to_hstring(c_in);
|
||||
end if;
|
||||
v.se.write_pmuspr := e_in.spr_select.ispmu;
|
||||
@ -1543,8 +1549,10 @@ begin
|
||||
end if;
|
||||
if e_in.spr_select.valid = '0' and e_in.spr_is_ram = '0' then
|
||||
-- mtspr to unimplemented SPRs should be a nop in
|
||||
-- supervisor mode and a program interrupt for user mode
|
||||
if ex1.msr(MSR_PR) = '1' then
|
||||
-- supervisor mode and a program interrupt or HEAI for user mode
|
||||
-- LPCR[EVIRT] = 1 makes it HEAI in privileged mode
|
||||
if ex1.msr(MSR_PR) = '1' or ctrl.lpcr_evirt = '1' or
|
||||
sprnum = 0 or sprnum = 4 or sprnum = 5 or sprnum = 6 then
|
||||
illegal := '1';
|
||||
end if;
|
||||
end if;
|
||||
@ -1746,6 +1754,8 @@ begin
|
||||
if valid_in = '1' then
|
||||
v.prev_op := e_in.insn_type;
|
||||
v.prev_prefixed := e_in.prefixed;
|
||||
v.se.set_heir := actions.se.set_heir;
|
||||
v.se.write_ic := actions.se.write_ic;
|
||||
end if;
|
||||
|
||||
-- Determine if there is any interrupt to be taken
|
||||
@ -1935,8 +1945,9 @@ begin
|
||||
v.fp_exception_next := '0';
|
||||
end if;
|
||||
|
||||
bypass_data.tag.valid <= e_in.write_reg_enable and bypass_valid;
|
||||
bypass_data.tag.tag <= e_in.instr_tag.tag;
|
||||
bypass_data.tag.valid <= v.e.write_enable and bypass_valid;
|
||||
bypass_data.tag.tag <= v.e.instr_tag.tag;
|
||||
bypass_data.reg <= v.e.write_reg;
|
||||
bypass_data.data <= alu_result;
|
||||
|
||||
bypass_cr_data.tag.valid <= e_in.output_cr and bypass_valid;
|
||||
@ -2047,16 +2058,22 @@ begin
|
||||
-- Next insn adder used in a couple of places
|
||||
next_nia <= std_ulogic_vector(unsigned(ex1.e.last_nia) + 4);
|
||||
|
||||
v := ex2;
|
||||
if stage2_stall = '0' then
|
||||
v.log_addr_spr := ex2.log_addr_spr;
|
||||
|
||||
v.e := ex1.e;
|
||||
v.se := ex1.se;
|
||||
v.ext_interrupt := ex1.ext_interrupt;
|
||||
v.taken_branch_event := ex1.taken_branch_event;
|
||||
v.br_mispredict := ex1.br_mispredict;
|
||||
if ex1.advance_nia = '1' then
|
||||
v.ext_interrupt := ex1.ext_interrupt and not stage2_stall;
|
||||
v.taken_branch_event := ex1.taken_branch_event and not stage2_stall;
|
||||
v.br_mispredict := ex1.br_mispredict and not stage2_stall;
|
||||
if stage2_stall = '1' then
|
||||
v.e.last_nia := ex2.e.last_nia;
|
||||
elsif ex1.advance_nia = '1' then
|
||||
v.e.last_nia := next_nia;
|
||||
end if;
|
||||
if stage2_stall = '1' then
|
||||
v.e.valid := '0';
|
||||
v.e.interrupt := '0';
|
||||
v.se := side_effect_init;
|
||||
end if;
|
||||
|
||||
if ex1.se.mult_32s = '1' and ex1.oe = '1' then
|
||||
@ -2110,9 +2127,7 @@ begin
|
||||
else
|
||||
rcresult := countbits_result;
|
||||
end if;
|
||||
if ex1.se.noop_spr_read = '1' then
|
||||
sprres := ex1.spr_write_data;
|
||||
elsif ex1.res2_sel(0) = '0' then
|
||||
if ex1.res2_sel(0) = '0' then
|
||||
sprres := spr_result;
|
||||
else
|
||||
sprres := pmu_to_x.spr_val;
|
||||
@ -2144,14 +2159,11 @@ begin
|
||||
cr_mask(7) := '1';
|
||||
end if;
|
||||
|
||||
if stage2_stall = '0' then
|
||||
v.e.write_data := ex_result;
|
||||
v.e.write_cr_data := cr_res;
|
||||
v.e.write_cr_mask := cr_mask;
|
||||
if ex1.e.rc = '1' and ex1.e.write_enable = '1' and v.e.valid = '1' then
|
||||
v.e.write_cr_enable := '1';
|
||||
end if;
|
||||
|
||||
if stage2_stall = '0' then
|
||||
if ex1.se.write_msr = '1' then
|
||||
ctrl_tmp.msr <= ex1.msr;
|
||||
end if;
|
||||
@ -2183,6 +2195,7 @@ begin
|
||||
end if;
|
||||
if ex1.se.write_lpcr = '1' then
|
||||
ctrl_tmp.lpcr_hail <= ex1.spr_write_data(LPCR_HAIL);
|
||||
ctrl_tmp.lpcr_evirt <= ex1.spr_write_data(LPCR_EVIRT);
|
||||
ctrl_tmp.lpcr_ld <= ex1.spr_write_data(LPCR_LD);
|
||||
ctrl_tmp.lpcr_heic <= ex1.spr_write_data(LPCR_HEIC);
|
||||
ctrl_tmp.lpcr_lpes <= ex1.spr_write_data(LPCR_LPES);
|
||||
@ -2240,13 +2253,15 @@ begin
|
||||
end if;
|
||||
end if;
|
||||
|
||||
bypass_valid := ex1.e.valid;
|
||||
if stage2_stall = '1' and ex1.res2_sel(1) = '1' then
|
||||
bypass_valid := '0';
|
||||
end if;
|
||||
-- Don't bypass the result from mfspr to slow SPRs or PMU SPRs,
|
||||
-- because we don't want to send the value while stalled because it
|
||||
-- might change, and we don't want bypass_valid to depend on
|
||||
-- stage2_stall for timing reasons.
|
||||
bypass_valid := ex1.e.valid and not ex1.res2_sel(1);
|
||||
|
||||
bypass2_data.tag.valid <= ex1.e.write_enable and bypass_valid;
|
||||
bypass2_data.tag.tag <= ex1.e.instr_tag.tag;
|
||||
bypass2_data.reg <= ex1.e.write_reg;
|
||||
bypass2_data.data <= ex_result;
|
||||
|
||||
bypass2_cr_data.tag.valid <= (ex1.e.write_cr_enable or (ex1.e.rc and ex1.e.write_enable))
|
||||
|
||||
@ -1795,6 +1795,49 @@ int fpu_test_26(void)
|
||||
return trapit(0, test26);
|
||||
}
|
||||
|
||||
/* Check for enabled invalid exception suppressing write of result */
|
||||
int test27(long arg)
|
||||
{
|
||||
unsigned long operands[4];
|
||||
unsigned long result;
|
||||
|
||||
operands[0] = 0xabcd1234ef895670;
|
||||
operands[1] = 0xbff0000000000000;
|
||||
operands[2] = 0xef895670abcd1234;
|
||||
operands[3] = 0;
|
||||
set_fpscr(FPS_VE);
|
||||
asm("lfd 3,0(%0); isync; lfd 4,8(%0); lfd 3,16(%0); fsqrt 3,4; stfd 3,0(%1)"
|
||||
: : "b" (&operands), "b" (&result) : "memory");
|
||||
if (result != 0xef895670abcd1234) {
|
||||
if (result == 0x7ffc000000000000)
|
||||
return 1;
|
||||
if (result == 0xabcd1234ef895670)
|
||||
return 2;
|
||||
print_hex(result, 16, " ");
|
||||
return 3;
|
||||
}
|
||||
|
||||
set_fpscr(FPS_ZE);
|
||||
asm("lfd 3,0(%0); isync; lfd 4,8(%0); lfd 5,24(%0); lfd 3,16(%0); fdiv 3,4,5; stfd 3,0(%1)"
|
||||
: : "b" (&operands), "b" (&result) : "memory");
|
||||
if (result != 0xef895670abcd1234) {
|
||||
if (result == 0x7ffc000000000000)
|
||||
return 4;
|
||||
if (result == 0xabcd1234ef895670)
|
||||
return 5;
|
||||
print_hex(result, 16, " ");
|
||||
return 6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpu_test_27(void)
|
||||
{
|
||||
enable_fp();
|
||||
return trapit(0, test27);
|
||||
}
|
||||
|
||||
int fail = 0;
|
||||
|
||||
void do_test(int num, int (*test)(void))
|
||||
@ -1846,6 +1889,7 @@ int main(void)
|
||||
do_test(24, fpu_test_24);
|
||||
do_test(25, fpu_test_25);
|
||||
do_test(26, fpu_test_26);
|
||||
do_test(27, fpu_test_27);
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
#define MSR_LE 0x1
|
||||
#define MSR_DR 0x10
|
||||
#define MSR_IR 0x20
|
||||
#define MSR_PR 0x4000
|
||||
#define MSR_EE 0x8000
|
||||
#define MSR_SF 0x8000000000000000ul
|
||||
|
||||
extern unsigned long callit(unsigned long arg1, unsigned long arg2,
|
||||
@ -27,6 +29,7 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs)
|
||||
|
||||
#define DSISR 18
|
||||
#define DAR 19
|
||||
#define DEC 22
|
||||
#define SRR0 26
|
||||
#define SRR1 27
|
||||
#define PID 48
|
||||
@ -35,6 +38,7 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs)
|
||||
#define SPRG3 275
|
||||
#define HSRR0 314
|
||||
#define HSRR1 315
|
||||
#define HEIR 339
|
||||
#define PTCR 464
|
||||
|
||||
static inline unsigned long mfspr(int sprnum)
|
||||
@ -464,6 +468,39 @@ int mode_test_8(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_9_mf(void)
|
||||
{
|
||||
mfspr(2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_9_mt(unsigned long arg)
|
||||
{
|
||||
mtspr(2, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mode_test_9(void)
|
||||
{
|
||||
unsigned long ret, msr;
|
||||
|
||||
/*
|
||||
* Test that mfspr/mtspr to unimplemented SPRs in user mode
|
||||
* causes an HEAI and sets HEIR.
|
||||
*/
|
||||
msr = MSR_SF | MSR_LE | MSR_PR | MSR_EE | MSR_IR | MSR_DR;
|
||||
mtspr(DEC, 0x7fffffff);
|
||||
ret = callit(0, 0, (unsigned long) test_9_mf, msr);
|
||||
if (ret != 0xe40 ||
|
||||
(mfspr(HEIR) & 0xfc1fffff) != ((31ul << 26) | (2 << 16) | (339 << 1)))
|
||||
return 1;
|
||||
ret = callit(0, 0, (unsigned long) test_9_mt, msr);
|
||||
if (ret != 0xe40 ||
|
||||
(mfspr(HEIR) & 0xfc1fffff) != ((31ul << 26) | (2 << 16) | (467 << 1)))
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fail = 0;
|
||||
|
||||
void do_test(int num, int (*test)(void))
|
||||
@ -510,6 +547,7 @@ int main(void)
|
||||
do_test(6, mode_test_6);
|
||||
do_test(7, mode_test_7);
|
||||
do_test(8, mode_test_8);
|
||||
do_test(9, mode_test_9);
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
@ -44,3 +44,91 @@ boot_entry:
|
||||
bctrl
|
||||
attn // terminate on exit
|
||||
b .
|
||||
|
||||
.globl read_sprn
|
||||
read_sprn:
|
||||
nop
|
||||
nop
|
||||
mr %r0,%r3
|
||||
mr %r3,%r4
|
||||
cmpdi %r0,0
|
||||
beq 0f
|
||||
cmpdi %r0,1
|
||||
beq 1f
|
||||
cmpdi %r0,4
|
||||
beq 4f
|
||||
cmpdi %r0,5
|
||||
beq 5f
|
||||
cmpdi %r0,6
|
||||
beq 6f
|
||||
mfspr %r3,179
|
||||
blr
|
||||
0: mfspr %r3,0
|
||||
blr
|
||||
1: mfspr %r3,1
|
||||
blr
|
||||
4: mfspr %r3,4
|
||||
blr
|
||||
5: mfspr %r3,5
|
||||
blr
|
||||
6: mfspr %r3,6
|
||||
blr
|
||||
|
||||
.globl write_sprn
|
||||
write_sprn:
|
||||
nop
|
||||
nop
|
||||
mr %r0,%r3
|
||||
li %r3,0
|
||||
cmpdi %r0,0
|
||||
beq 0f
|
||||
cmpdi %r0,1
|
||||
beq 1f
|
||||
cmpdi %r0,4
|
||||
beq 4f
|
||||
cmpdi %r0,5
|
||||
beq 5f
|
||||
cmpdi %r0,6
|
||||
beq 6f
|
||||
mtspr 179,%r3
|
||||
blr
|
||||
0: mtspr 0,%r3
|
||||
blr
|
||||
1: mtspr 1,%r3
|
||||
blr
|
||||
4: mtspr 4,%r3
|
||||
blr
|
||||
5: mtspr 5,%r3
|
||||
blr
|
||||
6: mtspr 6,%r3
|
||||
blr
|
||||
|
||||
#define EXCEPTION(nr) \
|
||||
.= nr ;\
|
||||
li %r3,nr ;\
|
||||
blr
|
||||
|
||||
EXCEPTION(0x300)
|
||||
EXCEPTION(0x380)
|
||||
EXCEPTION(0x400)
|
||||
EXCEPTION(0x480)
|
||||
EXCEPTION(0x500)
|
||||
EXCEPTION(0x600)
|
||||
EXCEPTION(0x700)
|
||||
EXCEPTION(0x800)
|
||||
EXCEPTION(0x900)
|
||||
EXCEPTION(0x980)
|
||||
EXCEPTION(0xa00)
|
||||
EXCEPTION(0xb00)
|
||||
EXCEPTION(0xc00)
|
||||
EXCEPTION(0xd00)
|
||||
EXCEPTION(0xe00)
|
||||
EXCEPTION(0xe20)
|
||||
EXCEPTION(0xe40)
|
||||
EXCEPTION(0xe60)
|
||||
EXCEPTION(0xe80)
|
||||
EXCEPTION(0xf00)
|
||||
EXCEPTION(0xf20)
|
||||
EXCEPTION(0xf40)
|
||||
EXCEPTION(0xf60)
|
||||
EXCEPTION(0xf80)
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
#define PASS "PASS\n"
|
||||
#define FAIL "FAIL\n"
|
||||
|
||||
extern long read_sprn(long, long);
|
||||
extern long write_sprn(long);
|
||||
|
||||
// i < 100
|
||||
void print_test(char *str)
|
||||
{
|
||||
@ -44,9 +47,24 @@ void print_test(char *str)
|
||||
#define __stringify_1(x...) #x
|
||||
#define __stringify(x...) __stringify_1(x)
|
||||
|
||||
void print_hex(unsigned long val, int ndigits, const char *str)
|
||||
{
|
||||
int i, x;
|
||||
|
||||
for (i = (ndigits - 1) * 4; i >= 0; i -= 4) {
|
||||
x = (val >> i) & 0xf;
|
||||
if (x >= 10)
|
||||
putchar(x + 'a' - 10);
|
||||
else
|
||||
putchar(x + '0');
|
||||
}
|
||||
puts(str);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned long tmp;
|
||||
unsigned long tmp, r;
|
||||
int fail = 0;
|
||||
|
||||
console_init();
|
||||
|
||||
@ -86,7 +104,47 @@ int main(void)
|
||||
DO_ONE(SPR_PTCR);
|
||||
DO_ONE(SPR_PVR);
|
||||
|
||||
/*
|
||||
* Test no-op behaviour of reserved no-op SPRs,
|
||||
* and of accesses to undefined SPRs in privileged mode.
|
||||
*/
|
||||
print_test("reserved no-op");
|
||||
__asm__ __volatile__("mtspr 811,%0" : : "r" (7838));
|
||||
__asm__ __volatile__("li %0,%1; mfspr %0,811" : "=r" (tmp) : "i" (2398));
|
||||
if (tmp == 2398) {
|
||||
puts(PASS);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
puts(FAIL);
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
print_test("undefined SPR");
|
||||
r = write_sprn(179);
|
||||
tmp = read_sprn(179, 2498);
|
||||
if (r == 0 && tmp == 2498) {
|
||||
puts(PASS);
|
||||
} else {
|
||||
puts(FAIL);
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
print_test("read SPR 0/4/5/6");
|
||||
if (read_sprn(0, 1234) == 0xe40 && read_sprn(2, 1234) == 1234 &&
|
||||
read_sprn(4, 1234) == 0xe40 && read_sprn(5, 1234) == 0xe40 &&
|
||||
read_sprn(6, 1234) == 0xe40 &&
|
||||
write_sprn(0) == 0xe40 && write_sprn(2) == 0 &&
|
||||
write_sprn(4) == 0xe40 && write_sprn(5) == 0xe40 &&
|
||||
write_sprn(6) == 0xe40) {
|
||||
puts(PASS);
|
||||
} else {
|
||||
puts(FAIL);
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
if (!fail)
|
||||
puts(PASS);
|
||||
else
|
||||
puts(FAIL);
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
Binary file not shown.
@ -24,3 +24,4 @@ test 23:PASS
|
||||
test 24:PASS
|
||||
test 25:PASS
|
||||
test 26:PASS
|
||||
test 27:PASS
|
||||
|
||||
Binary file not shown.
@ -6,3 +6,4 @@ test 05:PASS
|
||||
test 06:PASS
|
||||
test 07:PASS
|
||||
test 08:PASS
|
||||
test 09:PASS
|
||||
|
||||
Binary file not shown.
@ -22,4 +22,7 @@ Test SPR_HSPRG1:PASS
|
||||
Test SPR_PID:PASS
|
||||
Test SPR_PTCR:PASS
|
||||
Test SPR_PVR:PASS
|
||||
Test reserved no-op:PASS
|
||||
Test undefined SPR:PASS
|
||||
Test read SPR 0/4/5/6:PASS
|
||||
PASS
|
||||
|
||||
@ -203,6 +203,7 @@ begin
|
||||
-- Register write data bypass to decode2
|
||||
wb_bypass.tag.tag <= complete_out.tag;
|
||||
wb_bypass.tag.valid <= complete_out.valid and w_out.write_enable;
|
||||
wb_bypass.reg <= w_out.write_reg;
|
||||
wb_bypass.data <= w_out.write_data;
|
||||
|
||||
end process;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user