/* $NetBSD: fpemu.S,v 1.7 2019/04/15 20:45:08 skrll Exp $ */ /* $OpenBSD: fpemu.S,v 1.4 2001/03/29 02:18:45 mickey Exp $ */ /* * Copyright (c) 2000-2004 Michael Shalayeff * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "assym.h" #define FPEMU_VERSION (1 << 11) #define FP_TABLE2(name, ep0, ep1, ep2, ep3) \ ldil L%L$fpemu_tbl$name, %t1 ! \ ldo R%L$fpemu_tbl$name(%t1), %t1 ! \ ldwx,s %r1(%t1), %t2 ! \ bv %r0(%t2) ! \ nop ! \ .label L$fpemu_tbl$name ! \ .import __CONCAT(__CONCAT(ep0,_),name), code ! \ .import __CONCAT(__CONCAT(ep1,_),name), code ! \ .import __CONCAT(__CONCAT(ep2,_),name), code ! \ .import __CONCAT(__CONCAT(ep3,_),name), code ! \ .word __CONCAT(__CONCAT(ep0,_),name), __CONCAT(__CONCAT(ep1,_),name), __CONCAT(__CONCAT(ep2,_),name), __CONCAT(__CONCAT(ep3,_),name) #define FP_TABLE3(name,ep0,ep1,ep2,ep3,ep4,ep5,ep6,ep7,ep8,ep9,epa,epb,epc,epd,epe,epf) \ ldil L%L$fpemu_tbl$name, %t1 ! \ ldo R%L$fpemu_tbl$name(%t1), %t1 ! \ ldwx,s %r1(%t1), %t2 ! \ bv %r0(%t2) ! \ nop ! \ .label L$fpemu_tbl$name ! \ .import __CONCAT(__CONCAT(ep0,_),name), code ! \ .import __CONCAT(__CONCAT(ep1,_),name), code ! \ .import __CONCAT(__CONCAT(ep2,_),name), code ! \ .import __CONCAT(__CONCAT(ep3,_),name), code ! \ .import __CONCAT(__CONCAT(ep4,_),name), code ! \ .import __CONCAT(__CONCAT(ep5,_),name), code ! \ .import __CONCAT(__CONCAT(ep6,_),name), code ! \ .import __CONCAT(__CONCAT(ep7,_),name), code ! \ .import __CONCAT(__CONCAT(ep8,_),name), code ! \ .import __CONCAT(__CONCAT(ep9,_),name), code ! \ .import __CONCAT(__CONCAT(epa,_),name), code ! \ .import __CONCAT(__CONCAT(epb,_),name), code ! \ .import __CONCAT(__CONCAT(epc,_),name), code ! \ .import __CONCAT(__CONCAT(epd,_),name), code ! \ .import __CONCAT(__CONCAT(epe,_),name), code ! \ .import __CONCAT(__CONCAT(epf,_),name), code ! \ .word __CONCAT(__CONCAT(ep0,_),name), __CONCAT(__CONCAT(ep1,_),name), __CONCAT(__CONCAT(ep2,_),name), __CONCAT(__CONCAT(ep3,_),name), __CONCAT(__CONCAT(ep4,_),name), __CONCAT(__CONCAT(ep5,_),name), __CONCAT(__CONCAT(ep6,_),name), __CONCAT(__CONCAT(ep7,_),name), __CONCAT(__CONCAT(ep8,_),name), __CONCAT(__CONCAT(ep9,_),name), __CONCAT(__CONCAT(epa,_),name), __CONCAT(__CONCAT(epb,_),name), __CONCAT(__CONCAT(epc,_),name), __CONCAT(__CONCAT(epd,_),name), __CONCAT(__CONCAT(epe,_),name), __CONCAT(__CONCAT(epf,_),name) .section .bss .export L$fpemu_stack, data L$fpemu_stack: .comm NBPG .text /* * fpu_emulate(iir) */ LEAF_ENTRY_NOPROFILE(fpu_emulate) extru %arg0, 22, 2, %arg3 extru %arg0, 18, 3, %r31 comib,= 1, %arg3, L$fpu_cln1 nop extru %arg0, 16, 2, %r31 L$fpu_cln1: /* * theoreticaly we would need to determine the fpu instruction * exception type (there could be 4 of those, but stick w/ * non-timex fpus for now. */ ldi 1, %ret0 extru,<> %arg0, 10, 5, %r1 ldi 32, %r1 /* fpemu zero reg */ extru,<> %arg0, 31, 5, %t1 b,n L$fpemu_nzt comib,=,n 2, %arg3, L$fpemu_exit L$fpemu_nzt: copy %arg0, %t4 sh3add %r1, %arg2, %arg0 extru %arg1, 20, 2, %r1 sh3add %t1, %arg2, %arg1 /* * arg0 -- source register (address) * arg1 -- target register (address) * arg2 -- fpregs context * arg3 -- class * r31 -- subop * r1 -- format specifier * (t4 -- copy or arg0, ie iir) */ comib,=,n 0, %arg3, L$fpemu0c_0 comib,=,n 1, %arg3, L$fpemu0c_1 comib,=,n 2, %arg3, L$fpemu0c_2 comib,=,n 3, %arg3, L$fpemu0c_3 L$fpemu0c_0: comib,=,n 0, %r31, L$fpemu0c_0_0 comib,=,n 1, %r31, L$fpemu_exit comib,=,n 2, %r31, L$fpemu0c_0_2 comib,=,n 3, %r31, L$fpemu0c_0_3 comib,=,n 4, %r31, L$fpemu0c_0_4 comib,=,n 5, %r31, L$fpemu0c_0_5 comib,=,n 6, %r31, L$fpemu_exit comib,=,n 7, %r31, L$fpemu_exit L$fpemu0c_0_0: ldi FPEMU_VERSION, %t4 stw %t4, 0(%arg2) bv 0(%rp) copy %r0, %ret0 L$fpemu0c_0_2: /* fcpy */ comib,=,n 2, %r1, L$fpemu_exit subi 3, %r1, %r1 ldw 0*4(%arg0), %t1 ldw 1*4(%arg0), %t2 ldw 2*4(%arg0), %t3 ldw 3*4(%arg0), %t4 blr,n %r1, %r0 nop stw %t3, 2*4(%arg1) stw %t4, 3*4(%arg1) stw %t2, 1*4(%arg1) nop nop nop stw %t1, 0*4(%arg1) bv 0(%rp) copy %r0, %ret0 L$fpemu0c_0_3: /* fabs */ comib,=,n 2, %r1, L$fpemu_exit subi 3, %r1, %r1 ldw 0*4(%arg0), %t1 ldw 1*4(%arg0), %t2 ldw 2*4(%arg0), %t3 ldw 3*4(%arg0), %t4 depi 0, 0, 1, %t1 blr,n %r1, %r0 nop stw %t3, 2*4(%arg1) stw %t4, 3*4(%arg1) stw %t2, 1*4(%arg1) nop nop nop stw %t1, 0*4(%arg1) bv 0(%rp) copy %r0, %ret0 L$fpemu0c_0_4: /* fsqrt */ /* quad not implemented */ FP_TABLE2(fsqrt,sgl,dbl,invalid,invalid) L$fpemu0c_0_5: /* frnd */ /* quad not implemented */ FP_TABLE2(frnd,sgl,dbl,invalid,quad) L$fpemu0c_1: extru %t4, 18, 2, %t2 sh2add %r1, %t2, %r1 comib,=,n 0, %r31, L$fpemu0c_1_0 comib,=,n 1, %r31, L$fpemu0c_1_1 comib,=,n 2, %r31, L$fpemu0c_1_2 comib,=,n 3, %r31, L$fpemu0c_1_3 L$fpemu0c_1_0: /* fcnvff */ #define sgl_to_quad_fcnvff invalid_fcnvff #define dbl_to_quad_fcnvff invalid_fcnvff #define quad_to_sgl_fcnvff invalid_fcnvff #define quad_to_dbl_fcnvff invalid_fcnvff FP_TABLE3(fcnvff, invalid, sgl_to_dbl, invalid, sgl_to_quad, dbl_to_sgl, invalid, invalid, dbl_to_quad, invalid, invalid, invalid, invalid, quad_to_sgl, quad_to_dbl, invalid, invalid) L$fpemu0c_1_1: /* fcnvxf */ #define sgl_to_quad_fcnvxf invalid_fcnvxf #define dbl_to_quad_fcnvxf invalid_fcnvxf #define quad_to_sgl_fcnvxf invalid_fcnvxf #define quad_to_dbl_fcnvxf invalid_fcnvxf #define quad_to_quad_fcnvxf invalid_fcnvxf FP_TABLE3(fcnvxf, sgl_to_sgl, sgl_to_dbl, invalid, sgl_to_quad, dbl_to_sgl, dbl_to_dbl, invalid, dbl_to_quad, invalid, invalid, invalid, invalid, quad_to_sgl, quad_to_dbl, invalid, quad_to_quad) L$fpemu0c_1_2: /* fcnvfx */ #define sgl_to_quad_fcnvfx invalid_fcnvfx #define dbl_to_quad_fcnvfx invalid_fcnvfx #define quad_to_sgl_fcnvfx invalid_fcnvfx #define quad_to_dbl_fcnvfx invalid_fcnvfx #define quad_to_quad_fcnvfx invalid_fcnvfx FP_TABLE3(fcnvfx, sgl_to_sgl, sgl_to_dbl, invalid, sgl_to_quad, dbl_to_sgl, dbl_to_dbl, invalid, dbl_to_quad, invalid, invalid, invalid, invalid, quad_to_sgl, quad_to_dbl, invalid, quad_to_quad) L$fpemu0c_1_3: /* fcnvfxt */ #define sgl_to_quad_fcnvfxt invalid_fcnvfxt #define dbl_to_quad_fcnvfxt invalid_fcnvfxt #define quad_to_sgl_fcnvfxt invalid_fcnvfxt #define quad_to_dbl_fcnvfxt invalid_fcnvfxt #define quad_to_quad_fcnvfxt invalid_fcnvfxt FP_TABLE3(fcnvfxt, sgl_to_sgl, sgl_to_dbl, invalid, sgl_to_quad, dbl_to_sgl, dbl_to_dbl, invalid, dbl_to_quad, invalid, invalid, invalid, invalid, quad_to_sgl, quad_to_dbl, invalid, quad_to_quad) L$fpemu0c_2: comib,=,n 0, %r31, L$fpemu0c_2_0 comib,=,n 1, %r31, L$fpemu0c_2_1 comib,=,n 2, %r31, L$fpemu_exit comib,=,n 3, %r31, L$fpemu_exit comib,=,n 4, %r31, L$fpemu_exit comib,=,n 5, %r31, L$fpemu_exit comib,=,n 6, %r31, L$fpemu_exit comib,=,n 7, %r31, L$fpemu_exit L$fpemu0c_2_0: copy %arg2, %arg3 extru,<> %t4, 15, 5, %t1 ldi 32, %t1 sh3add %t1, %arg3, %arg1 extru %t4, 31, 5, %arg2 FP_TABLE2(fcmp,sgl,dbl,invalid,invalid) L$fpemu0c_2_1: comib,<>,n 0, %r1, L$fpemu_exit /* extru %t4, 31, 5, %arg1 */ /* XXX timex is much more compilicated */ ldw 0(%arg2), %t1 ldi 0, %ret0 extru,<> %t1, 5, 1, %r0 bv,n %r0(%rp) /* advance the pcqueue */ mtctl %r0, %pcsq mfctl %pcsq, %t2 mtctl %t2, %pcsq mtctl %t2, %pcsq mtctl %r0, %pcoq mfctl %pcoq, %t2 mtctl %t2, %pcoq ldo 4(%t2), %t2 bv %r0(%rp) mtctl %t2, %pcoq L$fpemu0c_3: copy %arg2, %arg3 extru,<> %t4, 31, 5, %t1 ldi 32, %t1 sh3add %t1, %arg3, %arg2 comib,=,n 0, %r31, L$fpemu0c_3_0 comib,=,n 1, %r31, L$fpemu0c_3_1 comib,=,n 2, %r31, L$fpemu0c_3_2 comib,=,n 3, %r31, L$fpemu0c_3_3 comib,=,n 4, %r31, L$fpemu0c_3_4 comib,=,n 5, %r31, L$fpemu_exit comib,=,n 6, %r31, L$fpemu_exit comib,=,n 7, %r31, L$fpemu_exit L$fpemu0c_3_0: /* fadd */ FP_TABLE2(fadd,sgl,dbl,invalid,invalid) L$fpemu0c_3_1: /* fsub */ FP_TABLE2(fsub,sgl,dbl,invalid,invalid) L$fpemu0c_3_2: /* fmpy */ FP_TABLE2(fmpy,sgl,dbl,invalid,invalid) L$fpemu0c_3_3: /* fdiv */ FP_TABLE2(fdiv,sgl,dbl,invalid,invalid) L$fpemu0c_3_4: /* frem */ FP_TABLE2(frem,sgl,dbl,invalid,invalid) .export L$fpemu_exit, code L$fpemu_exit: /* these look very ugly, but we don't want to mess up w/ m4 just * for the sake of overall world prettieness value growth XXX */ invalid_fsqrt: invalid_frnd: invalid_fcnvff: invalid_fcnvxf: invalid_fcnvfx: invalid_fcnvfxt: invalid_fcmp: invalid_fadd: invalid_fsub: invalid_fmpy: invalid_fdiv: invalid_frem: bv,n 0(%rp) EXIT(fpu_emulate) .end