/*
    LWThreads.S, Copyright  (c) by George Fankhauser, Claudio Jeker
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.

    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.

    For further information, please visit http://www.tik.ee.ethz.ch/~topsy

    This software is provided under the terms of the GNU General Public Licence.

    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/
/*
	
	File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/ThreadsLight/mips/LWThreads.S,v $
	Author(s):             George Fankhauser, Claudio Jeker
	Affiliation:           ETH Zuerich, TIK
	Version:               $Revision: 2911 $
	Creation Date:         
	Last Date of Change:   $Date: 2007-03-07 14:27:12 +0100 (Mit, 07 Mär 2007) $  by: $Author: rnatau $
	
*/

#include "asm.h"

/* Define the offsets for accessing the LWThreadContext, 
   if LWThreads.h changes this needs to be modified too */
/* struct LWThreadArrayDesc (LWTAD) */
#define	NNUM		0	// unsigned int N
#define nNUM		4	// unsigned int n
#define CUR			8	// ThreadId     current
#define STACK		12	// char*        stack
#define ARY			16	// LWThread     a
/* struct LWThreadDesc */
#define MSG			0
#define FROM		4
#define STATE		8
#define NEXT		12
#define PREV		16
#define STACKP		20
#define FRAMEP		24
#define	PROGC		28
#define SIZE		0x5	/* the size is 32 Byte or 1 << 0x5 */
/* THE SIZE_OF LWThreadDesc HAS TO BE 2^N */

// now the magic
// extern lwSwitchTo(LWPool lw, ThreadId to);
	FRAME(lwSwitchTo)

	.set noreorder
	lw		v0, CUR(a0)		// lw->current
	lw		v1, ARY(a0)		// lw->a
	sll		v0, v0, SIZE	// Offset = current << SIZE
	addu	v0, v0, v1		// lw->a[lw->current]
	/* push all save register on the stack */
	addiu	sp, sp, -32		// make place for save register */
	/* XXX there is a possible problem with this stack movement.
	   It seems that functions with va_arg (like printf) modify the stack
	   layout when used with more then 4 arguments. This needs to be debugged
	   --cjeker 20010315 */
	sw		s0,  0(sp)
	sw		s1,  4(sp)
	sw		s2,  8(sp)
	sw		s3, 12(sp)
	sw		s4, 16(sp)
	sw		s5, 20(sp)
	sw		s6, 24(sp)
	sw		s7, 28(sp)
	sw		sp, STACKP(v0)	// save stack pointer
	sw		fp, FRAMEP(v0)	// save frame pointer
	sw		ra,	PROGC(v0)	// save return address (program counter)
	/* old context saved, now restore new context */
	sw		a1, CUR(a0)		// lw->current = to
	sll		a1, a1, SIZE	// new offset
	addu	v0, a1, v1		// lw->a[to]
	lw		sp, STACKP(v0)	// get stack pointer
	nop                     // load instructions have a latency of one (I realized this after
	                        // a week of debugging on a MIPS Board CJ 20010608)
	/* pop all save register from the stack */
	lw		s7, 28(sp)
	lw		s6, 24(sp)
	lw		s5, 20(sp)
	lw		s4, 16(sp)
	lw		s3, 12(sp)
	lw		s2,  8(sp)
	lw		s1,  4(sp)
	lw		s0,  0(sp)
	lw		ra, PROGC(v0)	// get retrun address
	lw		fp, FRAMEP(v0)	// get frame pointer
	j		ra
	addiu	sp, sp, 32
	nop
	nop
	.set reorder
	.end lwSwitchTo
	
// extern lwJumpToParam(LWPool lw, ThreadId to, ThreadArg parameter);
	FRAME(lwJumpToParam)

	.set noreorder
	lw		v0, CUR(a0)		// lw->current
	lw		v1, ARY(a0)		// lw->a
	sll		v0, v0, SIZE	// Offset = current << SIZE
	addu	v0, v0, v1		// lw->a[lw->current]
	/* push all save register on stack */
	addiu	sp, sp, -32		// make place for save register */
	sw		s0,  0(sp)
	sw		s1,  4(sp)
	sw		s2,  8(sp)
	sw		s3, 12(sp)
	sw		s4, 16(sp)
	sw		s5, 20(sp)
	sw		s6, 24(sp)
	sw		s7, 28(sp)
	sw		sp, STACKP(v0)	// save stack pointer
	sw		fp, FRAMEP(v0)	// save frame pointer
	sw		ra,	PROGC(v0)	// save return address (program counter)
	/* old context saved, now jump to new context */
	sw		a1, CUR(a0)		// lw->current = to
	sll		a1, a1, SIZE	// new offset
	addu	v0, a1, v1		// lw->a[to]
	lw		sp, STACKP(v0)	// get stack pointer
	lw		ra, PROGC(v0)	// get jump address
	lw		fp, FRAMEP(v0)	// get frame pointer
	addiu	sp, sp, -16		// make place for a0-a3 register (for va_args)
	/* XXX probably this fixes the problem with va_arg because the c-calling 
	   convetion saves the first 16 bytes for a0 - a3 but this is a wild guess
	   --cjeker 20010315 */
	j		ra
	move    a1, a2			// move parameter to a0
	nop
	nop
	.set reorder
	.end lwJumpToParam
	
