Newsgroups: comp.sys.mac.programmer
Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!think.com!snorkelwacker.mit.edu!stanford.edu!neon.Stanford.EDU!cheshire
From: cheshire@neon.Stanford.EDU (Stuart David Cheshire)
Subject: Re: VBL tasks
Message-ID: <1991May15.081149.4579@neon.Stanford.EDU>
Organization: Computer Science Department, Stanford University, Ca , USA
References: <1991May13.014725.5238@neon.Stanford.EDU>
Date: Wed, 15 May 1991 08:11:49 GMT
Lines: 54

Many thanks to everyone who responded to my question.

The answer is that the vblAddr has to point into the System heap AS WELL as the
queue element itself residing in the system heap. I found an easy way to put a
piece of code in the system heap which calls my routine. It may look dangerous,
but it seems to work as long as you are not stupid and deliberately call UnLoad
Seg to throw away the code it is trying to call.

Sample code follows:

/* define a structure which is a VBLTask queue element with four bytes to
stash A5, our application global pointer, appended to the end */

typedef struct { VBLTask task; long *regA5; } ex_VBLTask;
local ex_VBLTask *task_qelem;

/* define a 'jump instruction' structure to put on the system heap. It is
six bytes -- a two byte opcode and a four byte absolute address. The code
that address points to must already be in memory and we must not call
UnLoadSeg or it will vanish under us. */

typedef struct { short jmp_opcode; void (*codeptr)(void); } jumpcode;
local jumpcode *task_code;

/* code starts here*/

	{
	/* allocate structures in System Heap */
	task_qelem = (ex_VBLTask*) NewPtrSysClear(sizeof(ex_VBLTask));
	task_code  = (jumpcode *)  NewPtrSysClear(sizeof(jumpcode));
	
	/* fill in opcode for jump and the address to jump to */
	task_code->jmp_opcode     = 0x4EF9;
	task_code->codeptr        = &MacTick;
	
	/* set up the queue element and install it */
	task_qelem->task.qType    = vType;
	task_qelem->task.vblAddr  = (ProcPtr)task_code;
	task_qelem->task.vblCount = 1;
	task_qelem->regA5         = Application_A5;
	VInstall(task_qelem);
	}

local void MacTick(void)
	{
	asm	{	move.l	a5, -(sp)
			move.l	OFFSET(ex_VBLTask,regA5)(a0), a5
		}
	
	/* do stuff here. Globals may be accessed if required. */
	
	asm {	move.l (sp)+, a5 }
	}

