File: mainloop_asm.S

package info (click to toggle)
mol 0.9.61-6
  • links: PTS
  • area: contrib
  • in suites: woody
  • size: 6,140 kB
  • ctags: 8,491
  • sloc: ansic: 50,560; asm: 2,826; sh: 458; makefile: 373; perl: 165; lex: 135; yacc: 131
file content (351 lines) | stat: -rw-r--r-- 9,324 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/* 
 *   Creation Date: <2001/01/26 21:21:53 samuel>
 *   Time-stamp: <2001/06/21 14:27:35 samuel>
 *   
 *	<mainloop.S>
 *	
 *	Main loop
 *   
 *   Copyright (C) 2000, 2001 Samuel Rydh (samuel@ibrium.se)
 *   
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation
 *   
 */

#include "mol_config.h"
#include "rvec.h"
#include "multiplexer.h"
#include "processor.h"
	
#include "asm_offsets.h"
#include "asmdefs.h"
#include "mac_registers.h"

//#define DEBUG
//#define DEBUG_REGISTERS		// Always save gprs/fprs

	
	////////////////////////////////////////////////////////////////////////
	//
	//	This file depends upon the register conventions of the platform.
	//	Linux/PPC uses the System V ABI:
	//
	//	Altered by function calls:
	//		r0,r3-r12,(r2 ?)
	//		fr0-fr13
	//		cr[0,1,5,6,7]
	//		ctr
	//		xer
	//		certain bits of fpscr
	//
	//	Not altered by function calls:	
	//		r13-r31
	//		cr[2,3,4]
	//		fr14-fr31
	//		certain bits of fpscr
	//
	//	The AltiVec implementation makes the assumption that *NO*
	//	altivec registers (including VRSAVE) is touched except by us.
	//
	////////////////////////////////////////////////////////////////////////


/************************************************************************/
/*	DEBUG								*/
/************************************************************************/
		
.macro DBG_ASSERT_RVF_BIT bit scr
#ifdef DEBUG
	lwz	\scr,STACK_DBG_RVEC(r1)
	rlwinm	\scr,\scr,0,\bit,\bit
	beq	error_detected
#endif
.endm

#ifdef DEBUG
	.print	"**************** DEBUG ENABLED IN mainloop_asm.S ***************"
error_detected:
	li	r3,RVEC_INTERNAL_ERROR
	lwz	r4,STACK_DBG_RVEC(r1)
	b	do_rvec_jump
#endif

.macro DEBUG_IN_KERNEL val, scr1, scr2
#ifdef DEBUG
	lwz	\scr1,STACK_MREGS(r1)
	li	\scr2,\val
	stw	\scr2,xDBG_IN_MAC_MODE(\scr1)
#endif
.endm

/************************************************************************/
/*	MACROS								*/
/************************************************************************/
	
.macro SETVEC, name, rvec, func, scr, scr2
	bl	1f
	.ascii	"\name\0"
	.balign	4,0
1:
	LOADI	\scr,gRVECtable
	LOADI	\scr2,\func
	stw	\scr2,((\rvec & RVEC_MASK) * RVEC_ESIZE) (\scr)
	mflr	\scr2
	stw	\scr2,((\rvec & RVEC_MASK) * RVEC_ESIZE + 8) (\scr)
.endm
	
/************************************************************************/
/*	mainloop_asm_init						*/
/************************************************************************/

	// This could be done in C, but we do it here for the sake
	// of modularity.
	
GLOBL( mainloop_asm_init ):
	mflr	r5
	SETVEC	"Init -",	   RVEC_INITIALIZE,	rvec_initialize,	/**/ r3,r4
	SETVEC	"NOP -",	   RVEC_NOP,		loop,			/**/ r3,r4
	SETVEC	"Exit -",	   RVEC_EXIT,		mainloop_out,		/**/ r3,r4
	SETVEC	"EnableFPU -",	   RVEC_ENABLE_FPU,	rvec_enable_fpu,	/**/ r3,r4
	SETVEC	"EnableAltivec -", RVEC_ENABLE_ALTIVEC,	rvec_enable_altivec,	/**/ r3,r4
	mtlr	r5
	blr


/************************************************************************/
/*	mainloop							*/
/************************************************************************/

	///////////////////////////////////////////////////////////////
	// mainloop( rvec, mregs, session_magic )
	// The following registers hold mac-values:
	//
	//	r13-r31
	//	fr0-fr12	(if fpu_state == FPU_DIRTY)
	//	fr14-fr31
	//
	// In particular, fr13 and fpscr *never* hold mac values.
	// (We can't touch fpscr since that might trigger a FPU exception)
	
.set STACK_SPACE,		416
.set STACK_LR,			STACK_SPACE+4
.set STACK_RESERVED,		0		// 8 bytes
.set STACK_DUMMY_FP,		8		// 8 bytes
.set STACK_MREGS,		16		// 4 bytes
#ifdef DEBUG
.set STACK_DBG_RVEC,		20		// 4 bytes
#endif
.set STACK_SESSION_MAGIC,	24		// 4 bytes
.set STACK_FPRS,		32		// 256 bytes
.set STACK_GPRS,		288		// 128 bytes

GLOBL( mainloop ):
	// Push stackframe
	stwu	r1,-STACK_SPACE(r1)
	mflr	r0
	mfxer	r11					// XER (uncertain about this one)
	mfcr	r12					// CR (cr1-cr7 needs to be saved?)
	mffs	fr3
	stfd	fr3,xEMULATOR_FPSCR-4(r1)		// Save emulator fpscr
	STORE_GPR_RANGE r11,r31,STACK_GPRS,r1		// don't touch r13-r31 (and f14-f31)
	STORE_GPR_RANGE r2,r2,STACK_GPRS,r1		// probably not necessary
	STORE_FPR_RANGE fr14,fr31,STACK_FPRS,r1		// don't touch fp14-fp31
	stw	r0,STACK_LR(r1)
	stw	r4,STACK_MREGS(r1)
	stw	r5,STACK_SESSION_MAGIC(r1)
	lwz	r11,xALTIVEC_USED(r4)			// Only touch the AltiVec unit if we know
	cmpwi	r11,0					// we have one.
	beq	1f
	xVEC_LOAD	r4, /**/ r11
1:	xLOAD_FULL_FPU	r4				// loads everything (except fr13 and fpscr)
	xGPR_LOAD_RANGE	13,31,r4			// r4 = mbase
	b	do_rvec_jump
	
loop:
	lwz	r6,STACK_MREGS(r1)
	lwz	r7,xINTERRUPT(r6)
	cmpwi	r7,0
	bne-	mol_interrupt
	li	r4,MOL_ENTRY_R4_MAGIC
	li	r5,MOL_ENTRY_R5_MAGIC
	// Any privileged instruction
switch_magic:
	DEBUG_IN_KERNEL 1, /**/ r10,r11
	lwz	r7,STACK_SESSION_MAGIC(r1)
	MOL_KERNEL_ENTRY_MAGIC				// Only r1, r2 and rvec parameters are valid afterwards
	DEBUG_IN_KERNEL 0, /**/ r10,r11
do_rvec_jump:
#ifdef DEBUG_REGISTERS
	bl	save_fpu
	bl	save_gprs
#endif
	// Return point, r3=rvec#, r4+=arguments
	rlwinm.	r0,r3,0,RVF_fb,RVF_lb			// Any RVEC flags?
	bne-	handle_rvec_flags			// Mod r0,r9-r12
do_rvec_jump_:
	LOADI	r9,gRVECtable				// Jump to return vector
	rlwinm	r10,r3, RVEC_ESIZE_LOG2, 31-(NRVECS_LOG2-1)-RVEC_ESIZE_LOG2, 31-RVEC_ESIZE_LOG2
	lwzx	r0,r9,r10
	mtlr	r0
#ifdef COLLECT_RVEC_STATISTICS
	addi	r10,r10,4
	lwzx	r11,r9,r10
	addi	r0,r11,1
	stwx	r0,r9,r10
#endif
#ifdef DEBUG
	lwz	r9,STACK_MREGS(r1)
	stw	r3,xDBG_LAST_RVEC(r9)
	stw	r3,STACK_DBG_RVEC(r1)
#endif
	blrl
	cmpwi	r3,0
	beq+	loop
	mtcr	r3					// Bit 0-3 (cr0) not used for flags
	lwz	r4,STACK_MREGS(r1)
	btl-	kRVecGPRsModifiedBit, gprs_modified
	btl-	kRVecFPRsModifiedBit, fprs_modified
	bt-	kRVecExitBit, mainloop_out
	b	loop

mol_interrupt:
	li	r3,RVEC_INTERRUPT
	b	do_rvec_jump

mainloop_out:
	bl	save_altivec				// save altivec (for session-save/debug)
	bl	save_fpu				// save fpu registers (if necessary)
	lwz	r4,STACK_MREGS(r1)
	xGPR_SAVE_RANGE	13,31,r4			// save xGPR13-xGPR31
	
	// Pop stackframe
	lwz	r0,STACK_LR(r1)
	LOAD_GPR_RANGE r11,r31,STACK_GPRS,r1
	LOAD_FPR_RANGE fr14,fr31,STACK_FPRS,r1
	mtxer	r11
	mtcr	r12
	mtlr	r0
	addi	r1,r1,STACK_SPACE
	blr

		
	/////////////////////////////////////////////////////////////////
	// kernel_call_return
	//
	//	r3	RVEC number
	//
	// If our low-level asm kernel code calls C-kernel code directly,
	// then the return point is set to kernel_call_return rather than 
	// do_rvec_jump. This allows the C-kernel code to pass parameters 
	// to rvec functions by storing them in xRVEC_PARAM.

kernel_call_return:
	lwz	r8,STACK_MREGS(r1)
	lwz	r4,xRVEC_PARAM0(r8)
	lwz	r5,xRVEC_PARAM1(r8)
	lwz	r6,xRVEC_PARAM2(r8)
	b	do_rvec_jump

	
	////////////////////////////////////////////////////////////////
	// handle_rvec_flags
	//
	//	r0	flags (upper 16 bits; top 4 bits unused)
	//	r3-rX	rvec call
	//
	// safe to modify: r0, r9-r12
	
handle_rvec_flags:
	mtcr	r0
	btl	RVF_USES_FPRS_BIT, save_fpu		// should go before RVF_FPU_UNSAFE_VECTOR
	btl	RVF_FPU_UNSAFE_BIT, save_low_fpu
	btl	RVF_USES_GPRS_BIT, save_gprs
	b	do_rvec_jump_

	// Make sure the complete FPU is stored in mregs
	// Modifies r9-r11
save_fpu:
	lwz	r10,STACK_MREGS(r1)
	lwz	r9,xFPU_STATE(r10)
	cmpwi	r9,FPU_STATE_SAVED			// If the FPU is already saved, do nothing
	beqlr+
	li	r11,FPU_STATE_SAVED
	stw	r11,xFPU_STATE(r10)
	crclr	RVF_FPU_UNSAFE_BIT
	xSAVE_TOPHALF_FPU r10				// Save top half of the FPU
	cmpwi	r9,FPU_STATE_DIRTY			// and the lower half of FPU if its dirty
	bnelr
	xSAVE_LOW_FPU r10				// save all of the FPU
	blr
	
	// Save low FPU registers (if the FPU is dirty). We must do this before
	// taking a vector that might touch the FPU.
	// Modifies r9-r11
save_low_fpu:
	lwz	r10,STACK_MREGS(r1)
	lwz	r9,xFPU_STATE(r10)
	cmpwi	r9,FPU_STATE_DIRTY			// Save FPU if its dirty
	bnelr+
	li	r11,FPU_STATE_HALF_SAVED
	xSAVE_LOW_FPU	r10				// r10 = mregs
	stw	r11,xFPU_STATE(r10)
	blr

	// Make sure all GPRs are stored in mregs
save_gprs:
	lwz	r10,STACK_MREGS(r1)	
	xGPR_SAVE_RANGE	13,31,r10			// r10=mregs, save xGPR13-xGPR31	
	blr

save_altivec:
	lwz	r10,STACK_MREGS(r1)
	lwz	r9,xALTIVEC_USED(r10)
	cmpwi	r9,0
	beqlr
	xVEC_SAVE r10, /**/ r9
	blr

	///////////////////////////////////////////////////////////////////
	// rvec return flags
	//
	//	r3:	return code
	//	r4:	mregs
	//
	// Safe to modify: r0,r5-r12, lr, ctr

	// called if kRVecGPRsModified was return by the rvector
gprs_modified:
	DBG_ASSERT_RVF_BIT RVF_USES_GPRS_BIT, /**/ r12
	xGPR_LOAD_RANGE	13,31,r4		// r4 = mbase
	blr

	// called kRVecFPRsModified was return by the rvector
fprs_modified:
	DBG_ASSERT_RVF_BIT RVF_USES_FPRS_BIT, /**/ r12
	xLOAD_TOPHALF_FPU r4			// we only need to reload the top half of the fpu.
	blr

	
/************************************************************************/
/*	Miscellaneous rvecs						*/
/************************************************************************/
	
rvec_initialize:
	LOADI	r6,kernel_call_return
	li	r4,MOL_INITIALIZE_R4_MAGIC
	li	r5,MOL_INITIALIZE_R5_MAGIC
	b	switch_magic
	
rvec_enable_fpu:
	stfd	fr0,STACK_DUMMY_FP(r1)		// enable the fpu
	b	loop

rvec_enable_altivec:
	li	r3,1
	lwz	r4,STACK_MREGS(r1)
	stw	r3,xALTIVEC_USED(r4)		// Useful for AltiVec detection
	.long	0x10000484			// vor	v0,v0,v0
	b	loop