DPRG
DPRG List  



DPRG: no subject (file transmission)

Subject: DPRG: no subject (file transmission)
From: David Philip Anderson dpa at io.isem.smu.edu
Date: Fri Feb 6 16:50:41 CST 1998

howdy

I battled for 3 days (well, evenings) to get the icc11 multi-tasking code
to work properly, but to no avail.  I traced through the code and I now
believe that the odd way he uses RTI instructions outside of interrupts, and
the curious implementation of the context switches, is clobbering the "normal"
interrupt service routines and garbaging their stacks.

I wrote a very simple, even elegant, test case to demonstrate this and sent
it to the email address advertised as the proper place for bug reports and
fixes, and got back the following reply:

> Return: someone at imagecraft.com
>
> Well, you may know more about libmtask than I do now... I think the purpose
> of setting up CCR that way is to simply making sure the interrupt bit is
> off.  Offhand I don't know why it doesn't work...
>
> Richard


which I assume is a not-so-subtle way of blowing me off. Offhand.

So I scrapped the whole thing and started over.  After some reflection I
concluded that the multi-tasking implementation that I'm currently using
on the robot does not need to be premptive, each task calls defer() itself,
either directly or thru msleep().  By the same token, there is no need for
a hog_processor() call, (quite the contrary!) and I've never used it.

About a day later I had a functioning multi-tasking kernel which consists
of a create_process(), kill_process(), defer(), and scheduler(). I've tested 
it every way I can think of and run it continuously for several hours, so far
so good!  It does not use any interrupts, and the context switch takes only
about 32 micro-seconds.  The TOC4 interrupt now only has to increment the
system clock, and all the other interrupt services (lcd, serial, shadow bytes)
appear to run without incident.

I include the code here for your dining and dancing pleasure, suitable for
framing or soaking and eating.

dpa


/* ------------------------------------------------------------------- */
/* task.h	struct definitions for multi-tasking 

05 Feb 98 dpa	Created.

/* ------------------------------------------------------------------- */

typedef struct task TASK;

struct task
{
	TASK	*next;		/* pointer to next task in linked list */
	unsigned char 	pid;	/* process id */
	unsigned char state;	/* process state, !0 = running */
	void	(*func)();	/* function address */
	int	arg;		/* function argument */
	char	*sp;		/* function stack pointer */
	char	stack[1];	/* function stack */
};


#define DEFAULT_STACK_SIZE	256
#define MINIMUM_STACK_SIZE	64


/* ---------------------------------------------------------------------- */
/* proc.c	multi tasking kernel for M.I.T. 6.270 board and icc11

05 Feb 98 dpa	Created.
		co-operative rather than pre-emptive, tasks must 
		call defer().  Uses no interrupts, (no "ticks" arg).
		null_task increments proc_counter for diagnostics.

/* ---------------------------------------------------------------------- */

#include <stdlib.h>
#include <hc11.h>
#include "task.h"

/* ---------------------------------------------------------------------- */
/* globals, .bss (init to 0) segment */

TASK *current;		/* pointer to current context */

int gbl_pid;		/* global process ids */
int run_level;		/* 0 = single tasking, 1 = multi tasking */
int proc_counter;	/* diagnostic counter for null task */


/* ---------------------------------------------------------------------- */
/* create new multi-tasking process on heap.

	expects:	void (*func)()	function address
			int arg		function argument
			int stack_size	function stack, min=64, default=256
	returns:	int pid		process id
*/

int create_process(void (*func)(), int arg, int stack_size)
{
	TASK *p;

	if (stack_size == 0)
		stack_size = DEFAULT_STACK_SIZE;
	else	if (stack_size < MINIMUM_STACK_SIZE)
		stack_size = MINIMUM_STACK_SIZE;
		
	p = calloc(1, sizeof (TASK) + stack_size - 1);
	p->func = func;
	p->arg = arg;
	p->state = 0;
	p->pid = ++gbl_pid;
	p->sp = &p->stack[stack_size-1];

	if (current == 0) 
		current = p, p->next = p;
	else	p->next = current->next, current->next = p;
		
	return p->pid;
}


/* ---------------------------------------------------------------------- */


void defer(void)		/* context switch */
{
	if (run_level) {

	asm("	ldx	_current	; sp -> context\n"
	"	sts	8,x\n"
	"	ldx	0,x		; new context\n"
	"	stx	_current");

	asm("	tst	3,x		; new task?\n"
	"	bne	dfr\n"		
	"	jmp	_new_task	; yes, go init stack\n"
	"dfr:	lds	8,x		; no, just load sp");

	}
}


void new_task(void)		/* init stack for new task, execute it */
{
	asm("	ldx	_current	; context\n"
	"	lds	8,x		; context -> sp\n"
	"	bset	3,x,#1		; state=1");

	asm("	ldd	4,x		; *func()\n"
	"	pshb\n\tpsha\n"
	"	ldd	6,x		; func arg");
}


/* ---------------------------------------------------------------------- */

void null_task(int x)
{
	while(1) {
		proc_counter++;
		defer();
	}
}

/* ---------------------------------------------------------------------- */
/* run this last thing in main, starts up multi-tasking, does not exit */


void scheduler(void)
{
	proc_counter = 0;
	run_level = 1;
	create_process(null_task,0,1);
	asm("	jmp	_new_task");
}



/* ---------------------------------------------------------------------- */
/* TASK utilities */
/* ---------------------------------------------------------------------- */
/* return task pointer for requested process id, -1 if not found */

TASK *findpid(int pid)
{
	TASK *p;

	p = current;
	while (p->pid != pid) {
		p = p->next;
		if (p == current) {
			p = (TASK*)-1;
			break;
		}
	}
	return p;
}

/* ---------------------------------------------------------------------- */
/* return task pointer to previous task in linked list */


TASK *findprev(TASK *t)
{
	TASK *p;
	p = t;
	while (p->next != t) p = p->next;
	return p;
}

/* ---------------------------------------------------------------------- */
/* kill task by process id */

void kill_process(int pid) 
{
	TASK *t,*p;

	if (pid) {
		if((t = findpid(pid)) != (TASK*)-1) {

			p = findprev(t);
			p->next = t->next;
			free(t);

			if (t == current) {
				current = p->next;
		    		asm("	ldx	_current\n"
				"	lds	8,x\n"
				"	rts");
			}
		}
	}
}


/* ---------------------------------------------------------------------- */
/* kill self */

void terminate(void)
{
	kill_process(current->pid);
}

/* ---------------------------------------------------------------------- */
/* EOF proc.c */

------------------------------

More information about the DPRG mailing list