1/*
2    NetWinder Floating Point Emulator
3    (c) Rebel.COM, 1998
4    (c) 1998, 1999 Philip Blundell
5
6    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/* This is the kernel's entry point into the floating point emulator.
24It is called from the kernel with code similar to this:
25
26	adrsvc	al, r9, ret_from_exception	@ r9  = normal FP return
27	adrsvc	al, lr, fpundefinstr		@ lr  = undefined instr return
28
29	get_current_task r10
30	mov	r8, #1
31	strb	r8, [r10, #TSK_USED_MATH]	@ set current->used_math
32	add	r10, r10, #TSS_FPESAVE		@ r10 = workspace
33	ldr	r4, .LC2
34	ldr	pc, [r4]			@ Call FP emulator entry point
35
36The kernel expects the emulator to return via one of two possible
37points of return it passes to the emulator.  The emulator, if
38successful in its emulation, jumps to ret_from_exception (passed in
39r9) and the kernel takes care of returning control from the trap to
40the user code.  If the emulator is unable to emulate the instruction,
41it returns via _fpundefinstr (passed via lr) and the kernel halts the
42user program with a core dump.
43
44On entry to the emulator r10 points to an area of private FP workspace
45reserved in the thread structure for this process.  This is where the
46emulator saves its registers across calls.  The first word of this area
47is used as a flag to detect the first time a process uses floating point,
48so that the emulator startup cost can be avoided for tasks that don't
49want it.
50
51This routine does three things:
52
531) The kernel has created a struct pt_regs on the stack and saved the
54user registers into it.  See inclue/asm-arm/proc/ptrace.h for details.
55
562) It calls EmulateAll to emulate a floating point instruction.
57EmulateAll returns 1 if the emulation was successful, or 0 if not.
58
593) If an instruction has been emulated successfully, it looks ahead at
60the next instruction.  If it is a floating point instruction, it
61executes the instruction, without returning to user space.  In this
62way it repeatedly looks ahead and executes floating point instructions
63until it encounters a non floating point instruction, at which time it
64returns via _fpreturn.
65
66This is done to reduce the effect of the trap overhead on each
67floating point instructions.  GCC attempts to group floating point
68instructions to allow the emulator to spread the cost of the trap over
69several floating point instructions.  */
70
71	.globl	nwfpe_enter
72nwfpe_enter:
73	mov	r4, lr			@ save the failure-return addresses
74	ldr	ip, [r10, #112]		@ get init_flag
75	mov	sl, sp			@ we access the registers via 'sl'
76
77	ldr	r5, [sp, #60]		@ get contents of PC;
78	cmp	ip, #0
79	bleq	nwfpe_init_fpa
80	sub	r8, r5, #4
81.Lx1:	ldrt	r0, [r8]		@ get actual instruction into r0
82emulate:
83	bl	EmulateAll		@ emulate the instruction
84	cmp	r0, #0			@ was emulation successful
85	moveq	pc, r4			@ no, return failure
86
87next:
88.Lx2:	ldrt	r6, [r5], #4		@ get the next instruction and
89					@ increment PC
90
91	and	r2, r6, #0x0F000000	@ test for FP insns
92	teq	r2, #0x0C000000
93	teqne	r2, #0x0D000000
94	teqne	r2, #0x0E000000
95	movne	pc, r9			@ return ok if not a fp insn
96
97	str	r5, [sp, #60]		@ update PC copy in regs
98
99	mov	r0, r6			@ save a copy
100	ldr	r1, [sp, #64]		@ fetch the condition codes
101	bl	checkCondition		@ check the condition
102	cmp	r0, #0			@ r0 = 0 ==> condition failed
103
104	@ if condition code failed to match, next insn
105	beq	next			@ get the next instruction;
106
107	mov	r0, r6			@ prepare for EmulateAll()
108	b	emulate			@ if r0 != 0, goto EmulateAll
109
110	@ We need to be prepared for the instructions at .Lx1 and .Lx2
111	@ to fault.  Emit the appropriate exception gunk to fix things up.
112	@ ??? For some reason, faults can happen at .Lx2 even with a
113	@ plain LDR instruction.  Weird, but it seems harmless.
114	.section .fixup,"ax"
115	.align	2
116.Lfix:	mov	pc, r9			@ let the user eat segfaults
117	.previous
118
119	.section __ex_table,"a"
120	.align	3
121	.long	.Lx1, .Lfix
122	.long	.Lx2, .Lfix
123	.previous
124