diff --git a/tests/fpu/Makefile b/tests/fpu/Makefile new file mode 100644 index 0000000..fd8344e --- /dev/null +++ b/tests/fpu/Makefile @@ -0,0 +1,3 @@ +TEST=fpu + +include ../Makefile.test diff --git a/tests/fpu/fpu.c b/tests/fpu/fpu.c new file mode 100644 index 0000000..d61b36e --- /dev/null +++ b/tests/fpu/fpu.c @@ -0,0 +1,196 @@ +#include +#include +#include + +#include "console.h" + +#define MSR_FP 0x2000 +#define MSR_FE0 0x800 +#define MSR_FE1 0x100 + +extern int trapit(long arg, int (*func)(long)); + +#define SRR0 26 +#define SRR1 27 + +static inline unsigned long mfspr(int sprnum) +{ + long val; + + __asm__ volatile("mfspr %0,%1" : "=r" (val) : "i" (sprnum)); + return val; +} + +static inline void mtspr(int sprnum, unsigned long val) +{ + __asm__ volatile("mtspr %0,%1" : : "i" (sprnum), "r" (val)); +} + +void disable_fp(void) +{ + unsigned long msr; + + __asm__("mfmsr %0" : "=r" (msr)); + msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); + __asm__("mtmsrd %0" : : "r" (msr)); +} + +void enable_fp(void) +{ + unsigned long msr; + + __asm__("mfmsr %0" : "=r" (msr)); + msr |= MSR_FP; + __asm__("mtmsrd %0" : : "r" (msr)); +} + +void print_string(const char *str) +{ + for (; *str; ++str) + putchar(*str); +} + +void print_hex(unsigned long val, int ndigits) +{ + 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'); + } +} + +// i < 100 +void print_test_number(int i) +{ + print_string("test "); + putchar(48 + i/10); + putchar(48 + i%10); + putchar(':'); +} + +unsigned long foo = 0x3ff8000000000000ul; +unsigned long foow; +int fooi = -76543; +int fooiw; + +int do_fp_op(long arg) +{ + switch (arg) { + case 0: + __asm__("lfd 31,0(%0)" : : "b" (&foo)); + break; + case 1: + __asm__("stfd 31,0(%0)" : : "b" (&foow) : "memory"); + break; + case 2: + __asm__("lfd 30,0(%0); stfd 30,0(%1)" + : : "b" (&foo), "b" (&foow) : "memory"); + break; + case 3: + __asm__("lfiwax 29,0,%0; stfd 29,0(%1)" + : : "r" (&fooi), "b" (&foow) : "memory"); + break; + case 4: + __asm__("lfiwzx 28,0,%0; stfd 28,0(%1)" + : : "r" (&fooi), "b" (&foow) : "memory"); + break; + case 5: + __asm__("lfdx 27,0,%0; stfiwx 27,0,%1" + : : "r" (&foow), "r" (&fooiw) : "memory"); + break; + } + return 0; +} + + +int fpu_test_1(void) +{ + int ret; + + disable_fp(); + /* these should give a FP unavailable exception */ + ret = trapit(0, do_fp_op); + if (ret != 0x800) + return 1; + ret = trapit(1, do_fp_op); + if (ret != 0x800) + return 2; + enable_fp(); + /* these should succeed */ + ret = trapit(0, do_fp_op); + if (ret) + return ret | 3; + ret = trapit(1, do_fp_op); + if (ret) + return ret | 4; + if (foow != foo) + return 5; + return 0; +} + +int fpu_test_2(void) +{ + int ret; + + enable_fp(); + foow = ~0; + ret = trapit(2, do_fp_op); + if (ret) + return ret | 1; + if (foow != foo) + return 2; + foow = ~0; + ret = trapit(3, do_fp_op); + if (ret) + return ret | 3; + if (foow != fooi) + return 4; + foow = ~0; + ret = trapit(4, do_fp_op); + if (ret) + return ret | 5; + if (foow != (unsigned int)fooi) + return 6; + ret = trapit(5, do_fp_op); + if (ret) + return ret | 7; + if (fooiw != fooi) + return 8; + return 0; +} + +int fail = 0; + +void do_test(int num, int (*test)(void)) +{ + int ret; + + print_test_number(num); + ret = test(); + if (ret == 0) { + print_string("PASS\r\n"); + } else { + fail = 1; + print_string("FAIL "); + print_hex(ret, 4); + print_string(" SRR0="); + print_hex(mfspr(SRR0), 16); + print_string(" SRR1="); + print_hex(mfspr(SRR1), 16); + print_string("\r\n"); + } +} + +int main(void) +{ + console_init(); + + do_test(1, fpu_test_1); + do_test(2, fpu_test_2); + + return fail; +} diff --git a/tests/fpu/head.S b/tests/fpu/head.S new file mode 100644 index 0000000..498606b --- /dev/null +++ b/tests/fpu/head.S @@ -0,0 +1,120 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Load an immediate 64-bit value into a register */ +#define LOAD_IMM64(r, e) \ + lis r,(e)@highest; \ + ori r,r,(e)@higher; \ + rldicr r,r, 32, 31; \ + oris r,r, (e)@h; \ + ori r,r, (e)@l; + + .section ".head","ax" + + /* + * Microwatt currently enters in LE mode at 0x0, so we don't need to + * do any endian fix ups + */ + . = 0 +.global _start +_start: + LOAD_IMM64(%r10,__bss_start) + LOAD_IMM64(%r11,__bss_end) + subf %r11,%r10,%r11 + addi %r11,%r11,63 + srdi. %r11,%r11,6 + beq 2f + mtctr %r11 +1: dcbz 0,%r10 + addi %r10,%r10,64 + bdnz 1b + +2: LOAD_IMM64(%r1,__stack_top) + li %r0,0 + stdu %r0,-16(%r1) + LOAD_IMM64(%r10, die) + mtsprg0 %r10 + LOAD_IMM64(%r12, main) + mtctr %r12 + bctrl +die: attn // terminate on exit + b . + +.global trapit +trapit: + mflr %r0 + std %r0,16(%r1) + stdu %r1,-256(%r1) + mtsprg1 %r1 + r = 14 + .rept 18 + std r,r*8(%r1) + r = r + 1 + .endr + mfcr %r0 + stw %r0,13*8(%r1) + LOAD_IMM64(%r10, ret) + mtsprg0 %r10 + mr %r12,%r4 + mtctr %r4 + bctrl +ret: + mfsprg1 %r1 + LOAD_IMM64(%r10, die) + mtsprg0 %r10 + r = 14 + .rept 18 + ld r,r*8(%r1) + r = r + 1 + .endr + lwz %r0,13*8(%r1) + mtcr %r0 + ld %r0,256+16(%r1) + addi %r1,%r1,256 + mtlr %r0 + blr + +#define EXCEPTION(nr) \ + .= nr ;\ + mfsprg0 %r0 ;\ + mtctr %r0 ;\ + li %r3,nr ;\ + bctr + + 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) diff --git a/tests/fpu/powerpc.lds b/tests/fpu/powerpc.lds new file mode 100644 index 0000000..99611ab --- /dev/null +++ b/tests/fpu/powerpc.lds @@ -0,0 +1,27 @@ +SECTIONS +{ + . = 0; + _start = .; + .head : { + KEEP(*(.head)) + } + . = ALIGN(0x1000); + .text : { *(.text) *(.text.*) *(.rodata) *(.rodata.*) } + . = ALIGN(0x1000); + .data : { *(.data) *(.data.*) *(.got) *(.toc) } + . = ALIGN(0x80); + __bss_start = .; + .bss : { + *(.dynsbss) + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(.common) + *(.bss.*) + } + . = ALIGN(0x80); + __bss_end = .; + . = . + 0x4000; + __stack_top = .; +} diff --git a/tests/test_fpu.bin b/tests/test_fpu.bin new file mode 100755 index 0000000..885368a Binary files /dev/null and b/tests/test_fpu.bin differ diff --git a/tests/test_fpu.console_out b/tests/test_fpu.console_out new file mode 100644 index 0000000..0c39ae3 --- /dev/null +++ b/tests/test_fpu.console_out @@ -0,0 +1,2 @@ +test 01:PASS +test 02:PASS diff --git a/tests/update_console_tests b/tests/update_console_tests index 906b0cc..a5e6ffc 100755 --- a/tests/update_console_tests +++ b/tests/update_console_tests @@ -3,7 +3,7 @@ # Script to update console related tests from source # -for i in sc illegal decrementer xics privileged mmu misc modes reservation trace ; do +for i in sc illegal decrementer xics privileged mmu misc modes reservation trace fpu ; do cd $i make cd -