// penter_mips.s
//
// Time-stamp: <04/11/01 13:39:57 keuchel@netwave.de>
//
//////////////////////////////////////////////////////////////////////
//
// MIPS assembly is compiled by clmips! There is no standalone assembler!
//
//////////////////////////////////////////////////////////////////////

	.globl __penter
	.globl __handle_penter
#if PROFILE_TIMING
	.globl __handle_return
#endif

//////////////////////////////////////////////////////////////////////

	.data

// function pointer
__preturn: .word __return

//////////////////////////////////////////////////////////////////////

	.text

//////////////////////////////////////////////////////////////////////
// Used for timing function exit. Jumps to original
// return address.

#if PROFILE_TIMING

	.ent __return
__return:
	.set noreorder

	subu sp, 4
	sw v0, 0(sp)			// save return value
	jal __handle_return
	nop	// delay slot
	move ra, v0			// original return address
	lw v0, 0(sp)			// restore return value
	addu sp, 4
	jr ra
	nop	// delay slot
	.end __return

#endif

//////////////////////////////////////////////////////////////////////

// 18011000 03E0C825             or          t9,ra,zero    // save ra in t9
// 18011004 0C0046C7             jal         10011B1C      // penter
// 18011008 00000000             nop
//
// 1801100C 0320F825             or          ra,t9,zero    // restore ra
// 18011010 27BDFFC8             addiu       sp,sp,0xFFC8
// 18011014 AFBF0014             sw          ra,0x14(sp)
// 18011018 AFA40038             sw          a0,0x38(sp)   // arg1
// 1801101C AFA5003C             sw          a1,0x3C(sp)
// 18011020 AFA60040             sw          a2,0x40(sp)
// 18011024 AFA70044             sw          a3,0x44(sp)

// This calls the penter handler with the function start address
// and the original return address of the calling function.
//
// Saving at is not needed.

	.ent __penter

__penter:
	.set noreorder
//	.set noat

// The caller must reserve space for register save in the callee!
	subu sp, 28+8			// add 8 for arg save area (2 args)
	sw ra, 0+8(sp)			// save return address
// All argument registers must be saved as the timing
// code might also trash a2 and a3
	sw a0, 4+8(sp)
	sw a1, 8+8(sp)
	sw a2, 12+8(sp)
	sw a3, 16+8(sp)
#if !PROFILE_TIMING
	sw t9, 20+8(sp)			// t9 has saved ra, might be trashed
#endif
#if PROFILE_TIMING
//	sw $1, 24+8(sp)			// save at register (not needed)
#endif
	move a0, ra
	subu a0, 12			// 3 instructions
#if PROFILE_TIMING
	move a1, t9			// return address of caller
#endif
	jal __handle_penter
	nop	// delay slot
	lw ra, 0+8(sp)			// restore return address
	lw a0, 4+8(sp)			// restore arg regs
	lw a1, 8+8(sp)
	lw a2, 12+8(sp)
	lw a3, 16+8(sp)
#if PROFILE_TIMING
	lw t9, __preturn		// replace with our stuff, uses at!
#else
	lw t9, 20+8(sp)
#endif
#if PROFILE_TIMING
//	lw $1, 24+8(sp)			// restore at
#endif
	addu sp, 28+8
	j ra
	nop	// delay slot
	.end __penter
