diff --git a/decode1.vhdl b/decode1.vhdl index 5d6a557..6624a53 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -313,6 +313,7 @@ architecture behaviour of decode1 is 2#1100001001# => (ALU, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0'), -- modsd 2#1100001011# => (ALU, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', NONE, '0', '0'), -- modsw 2#0010010000# => (ALU, OP_MTCRF, NONE, NONE, RS, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- mtcrf/mtocrf + 2#0010010010# => (ALU, OP_MTMSRD, NONE, NONE, RS, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '1'), -- mtmsr 2#0010110010# => (ALU, OP_MTMSRD, NONE, NONE, RS, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- mtmsrd # ignore top bits and d 2#0111010011# => (ALU, OP_MTSPR, NONE, NONE, RS, SPR, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- mtspr 2#0001001001# => (ALU, OP_MUL_H64, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0'), -- mulhd diff --git a/execute1.vhdl b/execute1.vhdl index 29713b2..4f85f3d 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -993,8 +993,11 @@ begin else -- Architecture says to leave out bits 3 (HV), 51 (ME) -- and 63 (LE) (IBM bit numbering) - ctrl_tmp.msr(63 downto 61) <= c_in(63 downto 61); - ctrl_tmp.msr(59 downto 13) <= c_in(59 downto 13); + if e_in.is_32bit = '0' then + ctrl_tmp.msr(63 downto 61) <= c_in(63 downto 61); + ctrl_tmp.msr(59 downto 32) <= c_in(59 downto 32); + end if; + ctrl_tmp.msr(31 downto 13) <= c_in(31 downto 13); ctrl_tmp.msr(11 downto 1) <= c_in(11 downto 1); if c_in(MSR_PR) = '1' then ctrl_tmp.msr(MSR_EE) <= '1'; @@ -1124,14 +1127,27 @@ begin elsif HAS_FPU and e_in.unit = FPU then fv.valid := '1'; end if; + -- Handling an ITLB miss doesn't count as having executed an instruction + if e_in.insn_type = OP_FETCH_FAILED then + do_trace := '0'; + end if; + end if; - elsif r.f.redirect = '1' then + -- The following cases all occur when r.busy = 1 and therefore + -- valid_in = 0. Hence they don't happen in the same cycle as any of + -- the cases above which depend on valid_in = 1. + + if r.f.redirect = '1' then v.e.valid := '1'; - elsif r.lr_update = '1' then + end if; + if r.lr_update = '1' then v.e.exc_write_enable := '1'; v.e.exc_write_data := r.next_lr; v.e.exc_write_reg := fast_spr_num(SPR_LR); v.e.valid := '1'; + -- Keep r.e.write_data unchanged next cycle in case it is needed + -- for a forwarded result (e.g. for CTR). + result := r.e.write_data; elsif r.cntz_in_progress = '1' then -- cnt[lt]z always takes two cycles result := countzero_result; diff --git a/tests/misc/head.S b/tests/misc/head.S index b0acb7f..d490a61 100644 --- a/tests/misc/head.S +++ b/tests/misc/head.S @@ -137,3 +137,28 @@ test_mtpvr: mtlr %r0 blr + +/* Test that bdnz and bdnzl update CTR and LR correctly */ + .global test_bdnzl +test_bdnzl: + mflr %r10 + mfcr %r11 + li %r0,0xf8 + mtctr %r0 + lis %r0,0x2000 + mtcr %r0 + addpcis %r9,0 +1: bdnztl 27,3f +2: bdnzt 14,4f +3: nop +4: li %r3,1 + addi %r9,%r9,2b-1b + mflr %r8 + cmpd %r8,%r9 + bne 9f + mfctr %r7 + cmpdi %r7,0xf6 + bne 9f + li %r3,0 +9: mtlr %r10 + blr diff --git a/tests/misc/misc.c b/tests/misc/misc.c index 283ca7f..73745d9 100644 --- a/tests/misc/misc.c +++ b/tests/misc/misc.c @@ -14,6 +14,7 @@ extern long test_addpcis_1(void); extern long test_addpcis_2(void); extern long test_mfpvr(void); extern long test_mtpvr(void); +extern long test_bdnzl(void); // i < 100 void print_test_number(int i) @@ -58,5 +59,12 @@ int main(void) } else puts(PASS); + print_test_number(5); + if (test_bdnzl() != 0) { + fail = 1; + puts(FAIL); + } else + puts(PASS); + return fail; } diff --git a/tests/test_misc.bin b/tests/test_misc.bin index 7e68e1c..2264686 100755 Binary files a/tests/test_misc.bin and b/tests/test_misc.bin differ diff --git a/tests/test_misc.console_out b/tests/test_misc.console_out index 2ff5a99..e59c03f 100644 --- a/tests/test_misc.console_out +++ b/tests/test_misc.console_out @@ -2,3 +2,4 @@ Test 01:PASS Test 02:PASS Test 03:PASS Test 04:PASS +Test 05:PASS diff --git a/tests/test_trace.bin b/tests/test_trace.bin index b9a612d..61fa48b 100755 Binary files a/tests/test_trace.bin and b/tests/test_trace.bin differ diff --git a/tests/test_trace.console_out b/tests/test_trace.console_out index 340756c..25e791c 100644 --- a/tests/test_trace.console_out +++ b/tests/test_trace.console_out @@ -5,3 +5,4 @@ test 04:PASS test 05:PASS test 06:PASS test 07:PASS +test 08:PASS diff --git a/tests/trace/head.S b/tests/trace/head.S index d23aeb7..778baaa 100644 --- a/tests/trace/head.S +++ b/tests/trace/head.S @@ -214,3 +214,8 @@ test7: bne 1f li %r3,-1 1: blr + + .global test8 +test8: + lfd %f0,0(%r3) + blr diff --git a/tests/trace/trace.c b/tests/trace/trace.c index 5f7ae9f..a859f4e 100644 --- a/tests/trace/trace.c +++ b/tests/trace/trace.c @@ -8,6 +8,7 @@ extern unsigned long callit(unsigned long arg1, unsigned long arg2, unsigned long (*fn)(unsigned long, unsigned long), unsigned long msr, unsigned long *regs); +#define MSR_FP 0x2000 #define MSR_SE 0x400 #define MSR_BE 0x200 @@ -188,6 +189,22 @@ int trace_test_7(void) return 0; } +extern unsigned long test8(unsigned long, unsigned long); + +int trace_test_8(void) +{ + unsigned long ret; + unsigned long regs[2]; + + ret = callit(0, 0, test8, (mfmsr() & ~MSR_FP) | MSR_SE, regs); + if (ret != 0x800) + return ret + 1; + ret = callit(0, 0, test8, mfmsr() | MSR_FP | MSR_SE, regs); + if (ret != 0xd00) + return ret + 2; + return 0; +} + int fail = 0; void do_test(int num, int (*test)(void)) @@ -217,6 +234,7 @@ int main(void) do_test(5, trace_test_5); do_test(6, trace_test_6); do_test(7, trace_test_7); + do_test(8, trace_test_8); return fail; }