32381fa0dd
copyright. In most cases, this means dropping the 3rd and 4th clauses.
319 lines
9.5 KiB
ArmAsm
319 lines
9.5 KiB
ArmAsm
/* $NetBSD: fpemu.S,v 1.6 2009/11/03 05:07:26 snj 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 <machine/asm.h>
|
|
#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
|
|
|