From bcac4b9b2fafe976eb4d2ce2d022cc0cbb33c5de Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 1 Jul 2020 18:03:19 +1000 Subject: [PATCH] tests: Add a test for FP loads and stores This tests that floating-point unavailable exceptions occur as expected on FP loads and stores, and that the simple FP loads and stores appear to give reasonable results. Signed-off-by: Paul Mackerras --- tests/fpu/Makefile | 3 + tests/fpu/fpu.c | 196 +++++++++++++++++++++++++++++++++++++ tests/fpu/head.S | 120 +++++++++++++++++++++++ tests/fpu/powerpc.lds | 27 +++++ tests/test_fpu.bin | Bin 0 -> 8208 bytes tests/test_fpu.console_out | 2 + tests/update_console_tests | 2 +- 7 files changed, 349 insertions(+), 1 deletion(-) create mode 100644 tests/fpu/Makefile create mode 100644 tests/fpu/fpu.c create mode 100644 tests/fpu/head.S create mode 100644 tests/fpu/powerpc.lds create mode 100755 tests/test_fpu.bin create mode 100644 tests/test_fpu.console_out 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 0000000000000000000000000000000000000000..885368a70cc97cc929c62934658553ed4b131143 GIT binary patch literal 8208 zcmeHMU2GKB6+W}O_O2ac9EqxKp~)D<)xa9G0dzDCB}sfBy#!?Wi|$>;6ySi z54-7XcI>(mRF>*ieQ=}%NTseKL{Tg8zyl9<6Gfzb0V#=)XktwKus?>W*%sJmZ=R4<~duQjGNbe;YNPZ9;NaK3MRtJ(qCS)U!jX*YXgu)}q z#EZu=yJ#f#i)$n4O*C%g{6{mlhse@tAXXL>CsKD1h0PCw;S{ciDH%42NV_AHGS&H* zhQC~2B12@u&m{az!q4Op?HiNHoc~lN9I*G352K0p=6oTmjg+z?!sT4wc59So@1|(} zu1!kiB!w$eWK^apSvgB%m3Qf#%AaVqa*5_EGo)0nP`G-PjOuktR&UZ+HBawU7iqRy zrupjkh^(KIGF8uQo8oXwbxc~|VlkIoe7jYT^I`y>0{9fbrwBep@F{{%5qyf^Qv{zP z_!PmX1U@D3DS=N3d`jR`0-qB2l)%MS?`*W%6eUkeSj+iCmP*LOdV8c9$i>?*&rKHj zO-<#xd(6%AZ?Cd{3aoPctL&c|Rww?)Ty77!^XiWp*LeKFH6DLxjmO`#I`Mn!&t7H! z)Vwo-?GNz->}BxZ(TlqZ+)mM==Bx!<_dcIYxIwLJMiM8jVr{z zf?i)iZ?2%XzefM4<5x)EL1*Jy19f!v)0iPdytjLFAa?kh!>M!M?#gUB7|G=Pk&KFO zqjr$#M#qOfy@-AS9Usu#OtQDehzftht>%8Wnp2MK#%&??Neq-zc0A@_KLqx#H?G#{ zLKt&l|Jf|jxf>Uk(S5n!hVEB4rd^%mgUo5zy)bBIFASMk%h5?<{6~DE$8w}*v_vFx zSWz?e-_@)mHIiIT=jDgbAn(jsp>lEl>uFmJ`I-xsNGxl4qKE3&<)sFKOKSh!kgON;>!dhxyM`j{Odp%oUeChaM zYzwdfU_V;Q2l6ZD!&kt0PJ#3;>#`U(8sOK>C#OWQ75s7Mo@4u0Bklb&;t^t|=gxh{ z{*-;IM~LwqKJcf}35{s3s?u2bHP=7x^UQ(IgB0oj-(f2OzL#N(Xczo*UBnA=d?I2k zh;iL7>thUOLUYyc*4g1${IGM$jfLoCX(MF+z9)cj&Gyy;!OmN-!#vo={1*;aj|`(PTxDyAZ~7I(jE} z{;%fFsf*8-YC@sxq-$H}`Mc6UduM%|6EYWS?bOY|qQKddtg(fj)aEy=XWGP&S7#T4 z0yXwD_}bFuC~W@l-iO(p!N?0u)YQF&#`GbI#4ZLqGWUe&dCv8B1^%Lt=WG4qY^`?g zJ-_Tzh*x$r)6Jf%sbS6Y{T+<`q~r>^W7kXR>ob-p=X_A`sx<2gMJU$_?9$tZhgfw)JVWpN%ht~0;u;HJYa#^o`-#AjtG z)T~^0$T4GX0%O}-f0KkfK(>~uex7|B_pHl9_bl#nzSnWKXluW8<%^JSm-3%W`D?Dc z4Ea=T{_5t9`OkxY!Ht>M46k|h_=Lu}^VZNkJa3Tkg|U{%9JgP|a}0H7eTogGH$RMf zOV%WrCwcFr$SJ~nM^U##U4>1U+w%dk&h1w-3Pq0JM!gap%S+i)rnR$i_<3i)>ngOl z*y01M&e#y?qztWOFX&?lE(qlJl^Tl7u&wnKi|v7aIJ|^u~Cny z&Bt)QYibwTyE2?x)Y*>}>suW71rzPh-l%W~5ml{K9!~}W7kt5HX z3*OIJuh;2lhR@!yN6IQb&`Z2a3`8-6-)?VkDp$ICpUblTX4n0)ZX`(;SRH;{b5 z*YykiP0R)Beb}p!Q^~8iR9CR*wi8Ewc0$E{!Z>tjLo?AHVfv&{+3(NVQb>4pCU||?ddHo;-Qiig*MWHr4x1+!NZy^>~ ziN-Si-IV%|5GtfZU1TC83jnAHSrw4#@uJ0O1QLp9~2+o+1E<_u;Ap1#mnXSI>wx2C7PG#LF^6_j)*uW9sM$7Ca#j_ z8RfL^LGqojb*<>-|}BKPb^$->ls+jz`Zx literal 0 HcmV?d00001 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 -