////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: kernel.c
|
// Filename: kernel.c
|
//
|
//
|
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
|
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
|
//
|
//
|
// Purpose: If you are looking for a main() program associated with the
|
// Purpose: If you are looking for a main() program associated with the
|
// ZipOS, this is it. This is the main program for the supervisor
|
// ZipOS, this is it. This is the main program for the supervisor
|
// task. It handles interrupt processing, creating tasks, context swaps,
|
// task. It handles interrupt processing, creating tasks, context swaps,
|
// creating tasks, and ... just about everything else a kernel must handle.
|
// creating tasks, and ... just about everything else a kernel must handle.
|
//
|
//
|
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This program is free software (firmware): you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License as published
|
// modify it under the terms of the GNU General Public License as published
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
//
|
//
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
// target there if the PDF file isn't present.) If not, see
|
// target there if the PDF file isn't present.) If not, see
|
// <http://www.gnu.org/licenses/> for a copy.
|
// <http://www.gnu.org/licenses/> for a copy.
|
//
|
//
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// http://www.gnu.org/licenses/gpl.html
|
// http://www.gnu.org/licenses/gpl.html
|
//
|
//
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
//
|
//
|
|
|
#include "zipsys.h"
|
#include "zipsys.h"
|
#include "board.h"
|
#include "board.h"
|
#include "ksched.h"
|
#include "ksched.h"
|
#include "kfildes.h"
|
#include "kfildes.h"
|
#include "taskp.h"
|
#include "taskp.h"
|
#include "syspipe.h"
|
#include "syspipe.h"
|
#include "ktraps.h"
|
#include "ktraps.h"
|
#include "errno.h"
|
#include "errno.h"
|
#include "swint.h"
|
#include "swint.h"
|
|
|
extern void kpanic(void);
|
extern void kpanic(void);
|
extern void raw_put_uart(int val);
|
extern void raw_put_uart(int val);
|
|
|
unsigned int nresets = 0;
|
unsigned int nresets = 0;
|
|
|
extern int kntasks(void);
|
extern int kntasks(void);
|
extern void kinit(TASKP *tasklist);
|
extern void kinit(TASKP *tasklist);
|
extern void restore_context(int *), save_context(int *);
|
extern void restore_context(int *), save_context(int *);
|
SYSPIPE *rxpipe, *txpipe, *keypipe, *lcdpipe, *pwmpipe, *cmdpipe;
|
SYSPIPE *rxpipe, *txpipe, *keypipe, *lcdpipe, *pwmpipe, *cmdpipe;
|
KDEVICE *pipedev, *txdev, *pwmdev;
|
KDEVICE *pipedev, *txdev, *pwmdev;
|
void *heap; // = _top_of_heap; // Need to wait on startup to set this
|
void *heap; // = _top_of_heap; // Need to wait on startup to set this
|
|
|
#define CONTEXT_LENGTH 80000 // 1ms
|
#define CONTEXT_LENGTH 80000 // 1ms
|
#define TICKS_PER_SECOND 1000
|
#define TICKS_PER_SECOND 1000
|
|
|
void kwrite_audio(TASKP tsk, int dev, int *dst, int len);
|
void kwrite_audio(TASKP tsk, int dev, int *dst, int len);
|
void kwrite_txuart(TASKP tsk, int dev, int *dst, int len);
|
void kwrite_txuart(TASKP tsk, int dev, int *dst, int len);
|
int kpost(TASKP *task, unsigned events, int milliseconds);
|
int kpost(TASKP *task, unsigned events, int milliseconds);
|
TASKP kschedule(int LAST_TASK, TASKP *tasklist, TASKP last);
|
TASKP kschedule(int LAST_TASK, TASKP *tasklist, TASKP last);
|
extern TASKP *ksetup(void);
|
extern TASKP *ksetup(void);
|
|
|
int LAST_TASK;
|
int LAST_TASK;
|
|
|
|
extern void txstr(const char *);
|
|
|
void kernel_entry(void) {
|
void kernel_entry(void) {
|
int nheartbeats= 0, tickcount = 0, milliseconds=0, ticks = 0;
|
int nheartbeats= 0, tickcount = 0, milliseconds=0, ticks = 0;
|
int audiostate = 0, buttonstate = 0;
|
int audiostate = 0, buttonstate = 0;
|
TASKP *tasklist, current;
|
TASKP *tasklist, current;
|
int *last_context;
|
int *last_context;
|
IOSPACE *sys = (IOSPACE *)IOADDR;
|
|
|
|
tasklist = ksetup();
|
tasklist = ksetup();
|
|
|
current = tasklist[0];
|
current = tasklist[0];
|
restore_context(current->context);
|
restore_context(current->context);
|
last_context = current->context;
|
last_context = current->context;
|
|
|
unsigned enableset =
|
unsigned enableset =
|
INT_ENABLEV(INT_BUTTON)
|
INT_ENABLEV(INT_BUTTON)
|
|INT_ENABLEV(INT_TIMA)
|
|INT_ENABLEV(INT_TIMER)
|
// |INT_ENABLEV(INT_UARTRX)
|
// |INT_ENABLEV(INT_UARTRX)
|
// |INT_ENABLEV(INT_UARTTX) // Needs to be turned on by driver
|
// |INT_ENABLEV(INT_UARTTX) // Needs to be turned on by driver
|
// |INT_ENABLEV(INT_AUDIO // Needs to be turned on by driver)
|
// |INT_ENABLEV(INT_AUDIO // Needs to be turned on by driver)
|
// |INT_ENABLEV(INT_GPIO)
|
// |INT_ENABLEV(INT_GPIO)
|
// |INT_ENABLEV(INT_TIMB);
|
|
;
|
;
|
// Then selectively turn some of them back on
|
// Then selectively turn some of them back on
|
sys->io_pic = INT_ENABLE | enableset | 0x07fff;
|
_sys->io_pic = INT_ENABLE | enableset | 0x07fff;
|
|
|
|
txstr("HEAP: "); txhex(heap);
|
|
|
do {
|
do {
|
int need_resched = 0, context_has_been_saved, pic;
|
int need_resched = 0, context_has_been_saved, pic;
|
nheartbeats++;
|
nheartbeats++;
|
|
|
zip_rtu();
|
zip_rtu();
|
|
|
last_context = current->context;
|
last_context = current->context;
|
context_has_been_saved = 0;
|
context_has_been_saved = 0;
|
pic = sys->io_pic;
|
pic = _sys->io_pic;
|
|
|
if (pic & 0x8000) { // If there's an active interrupt
|
if (pic & 0x8000) { // If there's an active interrupt
|
// Interrupt processing
|
// Interrupt processing
|
sys->io_spio = 0x44;
|
_sys->io_spio = 0x44;
|
|
|
// First, turn off pending interrupts
|
// First, turn off pending interrupts
|
// Although we migt just write 0x7fff7fff to the
|
// Although we migt just write 0x7fff7fff to the
|
// interrupt controller, how do we know another
|
// interrupt controller, how do we know another
|
// interrupt hasn't taken place since we read it?
|
// interrupt hasn't taken place since we read it?
|
// Thus we turn off the pending interrupts that we
|
// Thus we turn off the pending interrupts that we
|
// know about.
|
// know about.
|
pic &= 0x7fff;
|
pic &= 0x7fff;
|
// Acknowledge current ints, and turn off pending ints
|
// Acknowledge current ints, and turn off pending ints
|
sys->io_pic = INT_DISABLEV(pic)|(INT_CLEAR(pic));
|
_sys->io_pic = INT_DISABLEV(pic)|(INT_CLEAR(pic));
|
if(pic&INT_TIMA) {
|
if(pic&INT_TIMER) {
|
if (++ticks >= TICKS_PER_SECOND) {//(pic & SYSINT_PPS)
|
if (++ticks >= TICKS_PER_SECOND) {//(pic & SYSINT_PPS)
|
// Toggle the low order LED
|
// Toggle the low order LED
|
tickcount++;
|
tickcount++;
|
ticks = 0;
|
ticks = 0;
|
sys->io_spio = ((sys->io_spio&1)^1)|0x010;
|
_sys->io_spio = ((_sys->io_spio&1)^1)|0x010;
|
pic |= SWINT_CLOCK;
|
pic |= SWINT_CLOCK;
|
}
|
}
|
if (buttonstate)
|
if (buttonstate)
|
buttonstate--;
|
buttonstate--;
|
else
|
else if ((_sys->io_spio & 0x0f0)==0)
|
enableset |= INT_ENABLEV(INT_BUTTON);
|
enableset |= INT_ENABLEV(INT_BUTTON);
|
}
|
}
|
//
|
//
|
if (pic&INT_BUTTON) {
|
if (pic&INT_BUTTON) {
|
// Need to turn the button interrupt off
|
// Need to turn the button interrupt off
|
enableset &= ~(INT_ENABLEV(INT_BUTTON));
|
enableset &= ~(INT_ENABLEV(INT_BUTTON));
|
if ((sys->io_spio&0x0f0)==0x030)
|
if ((_sys->io_spio&0x0f0)==0x030)
|
kpanic();
|
kpanic();
|
buttonstate = 3;
|
if (buttonstate)
|
|
pic &= ~INT_BUTTON;
|
|
buttonstate = 50;
|
}
|
}
|
if (pic & INT_UARTRX) {
|
if (pic & INT_UARTRX) {
|
int v = sys->io_uart;
|
int v = _sys->io_uart;
|
|
|
if ((v & (~0x7f))==0) {
|
if ((v & (~0x7f))==0) {
|
kpush_syspipe(rxpipe, v);
|
kpush_syspipe(rxpipe, v);
|
|
|
// Local Echo
|
// Local Echo
|
if (pic & INT_UARTTX) {
|
if (pic & INT_UARTTX) {
|
sys->io_uart = v;
|
_sys->io_uart = v;
|
sys->io_pic = INT_UARTTX;
|
_sys->io_pic = INT_UARTTX;
|
pic &= ~INT_UARTTX;
|
pic &= ~INT_UARTTX;
|
}
|
}
|
}
|
}
|
} if (pic & INT_UARTTX) {
|
} if (pic & INT_UARTTX) {
|
int v;
|
char ch;
|
if (kpop_syspipe(txpipe, &v)==0) {
|
if (kpop_syspipe(txpipe, &ch)==0) {
|
|
unsigned v = ch;
|
enableset |= (INT_ENABLEV(INT_UARTTX));
|
enableset |= (INT_ENABLEV(INT_UARTTX));
|
sys->io_uart= v;
|
_sys->io_uart= v;
|
sys->io_pic = INT_UARTTX;
|
_sys->io_pic = INT_UARTTX;
|
// if (v == 'W')
|
// if (v == 'W')
|
// sys->io_timb = 5;
|
// sys->io_watchdog = 5;
|
// 75k was writing the 'e'
|
// 75k was writing the 'e'
|
} else
|
} else
|
enableset &= ~(INT_ENABLEV(INT_UARTTX));
|
enableset&= ~(INT_DISABLEV(INT_UARTTX));
|
} if (audiostate) {
|
} if (audiostate) {
|
if (pic & INT_AUDIO) {
|
if (pic & INT_AUDIO) {
|
int v;
|
unsigned short sample;
|
|
|
// States:
|
// States:
|
// 0 -- not in use
|
// 0 -- not in use
|
// 1 -- First sample, buffer empty
|
// 1 -- in use
|
// time to read a new sample
|
|
// 2 -- second sample, to read new
|
if (kpop_short_syspipe(pwmpipe, &sample)==0) {
|
// 3 -- Need to turn off
|
_sys->io_pwm_audio = sample;
|
if ((audiostate & 3)==2) {
|
_sys->io_spio = 0x022;
|
sys->io_pwm_audio = (audiostate>>2)&0x0ffff;
|
// audiostate = 1;
|
audiostate = 1;
|
|
} else if (kpop_syspipe(pwmpipe, &v)==0) {
|
|
audiostate = (2|(v<<2))&0x03ffff;
|
|
sys->io_pwm_audio = (v>>16)&0x0ffff;
|
|
} else {
|
} else {
|
audiostate = 0;
|
audiostate = 0;
|
// Turn the device off
|
// Turn the device off
|
sys->io_pwm_audio = 0x10000;
|
_sys->io_pwm_audio = 0x10000;
|
// Turn the interrupts off
|
// Turn the interrupts off
|
enableset &= ~(INT_ENABLEV(INT_AUDIO));
|
enableset &= ~(INT_ENABLEV(INT_AUDIO));
|
sys->io_spio = 0x020;
|
_sys->io_spio = 0x020;
|
}
|
}
|
|
|
// This particular interrupt cannot be cleared
|
// This particular interrupt cannot be cleared
|
// until the port has been written to. Hence,
|
// until the port has been written to. Hence,
|
// now that we've written to the port, we clear
|
// now that we've written to the port, we clear
|
// it now. If it needs retriggering, the port
|
// it now. If it needs retriggering, the port
|
// will retrigger itself -- despite being
|
// will retrigger itself -- despite being
|
// cleared here.
|
// cleared here.
|
sys->io_pic = INT_AUDIO;
|
_sys->io_pic = INT_AUDIO;
|
}} else { // if (audiostate == 0)
|
}}
|
int sample;
|
/*
|
if (kpop_syspipe(pwmpipe, &sample)==0) {
|
else { // if (audiostate == 0)
|
audiostate = (2|(sample<<2))&0x03ffff;
|
unsigned short sample;
|
sys->io_pwm_audio = 0x310000 | ((sample>>16)&0x0ffff);
|
|
enableset |= (INT_ENABLEV(INT_AUDIO));
|
if (kpop_short_syspipe(pwmpipe, &sample)==0) {
|
sys->io_spio = 0x022;
|
audiostate = 1;
|
sys->io_pic = INT_AUDIO;
|
_sys->io_pwm_audio = 0x310000 | sample;
|
} // else sys->io_spio = 0x020;
|
enableset |= (INT_ENABLEV(INT_AUDIO));
|
}
|
_sys->io_spio = 0x022;
|
|
_sys->io_pic = INT_AUDIO;
|
|
} // else sys->io_spio = 0x020;
|
|
}
|
|
*/
|
milliseconds = kpost(tasklist, pic, milliseconds);
|
milliseconds = kpost(tasklist, pic, milliseconds);
|
|
|
// Restart interrupts
|
// Restart interrupts
|
enableset &= (~0x0ffff); // Keep the bottom bits off
|
enableset &= (~0x0ffff); // Keep the bottom bits off
|
sys->io_pic = INT_ENABLE|enableset;
|
_sys->io_pic = INT_ENABLE|enableset;
|
} else {
|
} else {
|
sys->io_pic = INT_ENABLE; // Make sure interrupts are on
|
_sys->io_pic = INT_ENABLE; // Make sure interrupts are on
|
int sample;
|
unsigned short sample;
|
|
|
// Check for the beginning of an audio pipe. If the
|
// Check for the beginning of an audio pipe. If the
|
// interrupt is not enabled, we still might need to
|
// interrupt is not enabled, we still might need to
|
// enable it.
|
// enable it.
|
if ((audiostate==0)&&(kpop_syspipe(pwmpipe, &sample)==0)) {
|
|
audiostate = (2|(sample<<2))&0x03ffff;
|
if ((audiostate==0)&&(kpop_short_syspipe(pwmpipe, &sample)==0)) {
|
sys->io_pwm_audio = 0x310000 | ((sample>>16)&0x0ffff);
|
audiostate = 1;
|
sys->io_pic = INT_AUDIO;
|
_sys->io_pwm_audio = 0x310000 | (sample);
|
|
_sys->io_pic = INT_AUDIO;
|
enableset |= (INT_ENABLEV(INT_AUDIO));
|
enableset |= (INT_ENABLEV(INT_AUDIO));
|
sys->io_spio = 0x022;
|
_sys->io_spio = 0x022;
|
} // else sys->io_spio = 0x020;
|
} // else sys->io_spio = 0x020;
|
|
|
// Or the beginning of a transmit pipe.
|
// Or the beginning of a transmit pipe.
|
if (pic & INT_UARTTX) {
|
if (pic & INT_UARTTX) {
|
int v;
|
char ch;
|
if (kpop_syspipe(txpipe, &v)==0) {
|
if (kpop_syspipe(txpipe, &ch)==0) {
|
|
unsigned v = ch;
|
enableset |= (INT_ENABLEV(INT_UARTTX));
|
enableset |= (INT_ENABLEV(INT_UARTTX));
|
sys->io_uart = v;
|
_sys->io_uart = v;
|
sys->io_pic = INT_UARTTX;
|
_sys->io_pic = INT_UARTTX;
|
// if (v == 'W')
|
|
// sys->io_timb = 5;
|
|
} else
|
} else
|
enableset &= ~(INT_ENABLEV(INT_UARTTX));
|
enableset &= ~(INT_ENABLEV(INT_UARTTX));
|
}
|
}
|
|
|
// What if someone left interrupts off?
|
// What if someone left interrupts off?
|
// This might happen as part of a wait trap call, such
|
// This might happen as part of a wait trap call, such
|
// as syspipe() accomplishes within uwrite_syspipe()
|
// as syspipe() accomplishes within uwrite_syspipe()
|
// (We also might've just turned them off ... ooops)
|
// (We also might've just turned them off ... ooops)
|
enableset &= (~0x0ffff); // Keep the bottom bits off
|
enableset &= (~0x0ffff); // Keep the bottom bits off
|
sys->io_pic = INT_ENABLE | enableset;
|
_sys->io_pic = INT_ENABLE | enableset;
|
}
|
}
|
sys->io_spio = 0x40;
|
_sys->io_spio = 0x40;
|
|
|
int zcc = zip_ucc();
|
int zcc = zip_ucc();
|
if (zcc & CC_TRAPBIT) {
|
if (zcc & CC_TRAPBIT) {
|
// sys->io_spio = 0x0ea;
|
// sys->io_spio = 0x0ea;
|
|
|
context_has_been_saved = 1;
|
context_has_been_saved = 1;
|
save_context(last_context);
|
save_context(last_context);
|
last_context[14] = zcc & (~CC_TRAPBIT);
|
last_context[14] = zcc & (~CC_TRAPBIT);
|
// Do trap handling
|
// Do trap handling
|
switch(last_context[1]) {
|
switch(last_context[1]) {
|
case TRAPID_WAIT:
|
case TRAPID_WAIT:
|
{ // The task wishes to wait on an interrupt
|
{ // The task wishes to wait on an interrupt
|
int ilist, timeout;
|
int ilist, timeout;
|
ilist = last_context[2];
|
ilist = last_context[2];
|
timeout= last_context[3];
|
timeout= last_context[3];
|
last_context[1] = ilist & current->pending;
|
last_context[1] = ilist & current->pending;
|
if (current->pending & ilist) {
|
if (current->pending & ilist) {
|
// Clear upon any read
|
// Clear upon any read
|
current->pending &= (~last_context[1]);
|
current->pending &= (~last_context[1]);
|
} else {
|
} else {
|
current->waitsig = ilist;
|
current->waitsig = ilist;
|
if (timeout != 0) {
|
if (timeout != 0) {
|
current->state = SCHED_WAITING;
|
current->state = SCHED_WAITING;
|
need_resched = 1;
|
need_resched = 1;
|
if (timeout > 0) {
|
if (timeout > 0) {
|
current->timeout=milliseconds+timeout;
|
current->timeout=milliseconds+timeout;
|
current->waitsig |= SWINT_TIMEOUT;
|
current->waitsig |= SWINT_TIMEOUT;
|
}
|
}
|
}
|
}
|
}} break;
|
}} break;
|
case TRAPID_CLEAR:
|
case TRAPID_CLEAR:
|
{ unsigned timeout;
|
{ unsigned timeout;
|
// The task wishes to clear any pending
|
// The task wishes to clear any pending
|
// interrupts, in a likely attempt to create
|
// interrupts, in a likely attempt to create
|
// them soon.
|
// them soon.
|
last_context[1] = last_context[2] & current->pending;
|
last_context[1] = last_context[2] & current->pending;
|
// Clear upon any read
|
// Clear upon any read
|
current->pending &= (~last_context[1]);
|
current->pending &= (~last_context[1]);
|
timeout = (unsigned)last_context[2];
|
timeout = (unsigned)last_context[2];
|
if (timeout) {
|
if (timeout) {
|
if ((int)timeout < 0)
|
if ((int)timeout < 0)
|
// Turn off any pending timeout
|
// Turn off any pending timeout
|
current->pending &= (~SWINT_TIMEOUT);
|
current->pending &= (~SWINT_TIMEOUT);
|
else
|
else
|
// Otherwise, start a timeout
|
// Otherwise, start a timeout
|
// counter
|
// counter
|
current->timeout = milliseconds+timeout;
|
current->timeout = milliseconds+timeout;
|
}} break;
|
}} break;
|
case TRAPID_POST:
|
case TRAPID_POST:
|
kpost(tasklist, last_context[2]&(~0x07fff),
|
kpost(tasklist, last_context[2]&(~0x07fff),
|
milliseconds);
|
milliseconds);
|
break;
|
break;
|
case TRAPID_YIELD:
|
case TRAPID_YIELD:
|
need_resched = 1;
|
need_resched = 1;
|
break;
|
break;
|
case TRAPID_READ:
|
case TRAPID_READ:
|
{
|
{
|
KFILDES *fd = NULL;
|
KFILDES *fd = NULL;
|
if ((unsigned)last_context[2]
|
if ((unsigned)last_context[2]
|
< (unsigned)MAX_KFILDES)
|
< (unsigned)MAX_KFILDES)
|
fd = current->fd[last_context[2]];
|
fd = current->fd[last_context[2]];
|
if ((!fd)||(!fd->dev))
|
if ((!fd)||(!fd->dev))
|
last_context[1] = -EBADF;
|
last_context[1] = -EBADF;
|
else
|
else
|
fd->dev->read(current, fd->id,
|
fd->dev->read(current, fd->id,
|
(void *)last_context[3], last_context[4]);
|
(void *)last_context[3], last_context[4]);
|
} break;
|
} break;
|
case TRAPID_WRITE:
|
case TRAPID_WRITE:
|
{ KFILDES *fd = NULL;
|
{ KFILDES *fd = NULL;
|
if ((unsigned)last_context[2]
|
if ((unsigned)last_context[2]
|
< (unsigned)MAX_KFILDES)
|
< (unsigned)MAX_KFILDES)
|
fd = current->fd[last_context[2]];
|
fd = current->fd[last_context[2]];
|
else { kpanic(); zip_halt(); }
|
else { kpanic(); zip_halt(); }
|
if ((!fd)||(!fd->dev))
|
if ((!fd)||(!fd->dev))
|
last_context[1] = -EBADF;
|
last_context[1] = -EBADF;
|
else {
|
else {
|
fd->dev->write(current, fd->id,
|
fd->dev->write(current, fd->id,
|
(void *)last_context[3], last_context[4]);
|
(void *)last_context[3], last_context[4]);
|
}}
|
}}
|
break;
|
break;
|
case TRAPID_TIME:
|
case TRAPID_TIME:
|
last_context[1] = tickcount;
|
last_context[1] = tickcount;
|
break;
|
break;
|
case TRAPID_MALLOC:
|
case TRAPID_MALLOC:
|
last_context[1] = (int)sys_malloc(last_context[2]);
|
last_context[1] = (int)sys_malloc(last_context[2]);
|
break;
|
break;
|
case TRAPID_FREE:
|
case TRAPID_FREE:
|
// Our current malloc cannot free
|
// Our current malloc cannot free
|
// sys_free(last_context[2])
|
// sys_free(last_context[2])
|
break;
|
break;
|
case TRAPID_EXIT:
|
case TRAPID_EXIT:
|
current->state = SCHED_EXIT;
|
current->state = SCHED_EXIT;
|
need_resched = 1;
|
need_resched = 1;
|
kpanic();
|
kpanic();
|
zip_halt();
|
zip_halt();
|
break;
|
break;
|
default:
|
default:
|
current->state = SCHED_ERR;
|
current->state = SCHED_ERR;
|
need_resched = 1;
|
need_resched = 1;
|
kpanic();
|
kpanic();
|
zip_halt();
|
zip_halt();
|
break;
|
break;
|
}
|
}
|
|
|
restore_context(last_context);
|
restore_context(last_context);
|
} else if (zcc & (CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_ILL)) {
|
} else if (zcc & (CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_ILL)) {
|
current->state = SCHED_ERR;
|
current->state = SCHED_ERR;
|
// current->errno = -EBUS;
|
current->errno = (int)_sys->io_buserr;
|
current->errno = (int)sys->io_buserr;
|
|
save_context(last_context);
|
save_context(last_context);
|
context_has_been_saved = 1;
|
context_has_been_saved = 1;
|
kpanic();
|
kpanic();
|
zip_halt();
|
zip_halt();
|
}
|
}
|
|
|
if ((need_resched)||(current->state != SCHED_READY)
|
if ((need_resched)||(current->state != SCHED_READY)
|
||(current == tasklist[LAST_TASK]))
|
||(current == tasklist[LAST_TASK]))
|
current = kschedule(LAST_TASK, tasklist, current);
|
current = kschedule(LAST_TASK, tasklist, current);
|
|
|
if (current->context != last_context) {
|
if (current->context != last_context) {
|
// Swap contexts
|
// Swap contexts
|
if (!context_has_been_saved)
|
if (!context_has_been_saved)
|
save_context(last_context);
|
save_context(last_context);
|
restore_context(current->context);
|
restore_context(current->context);
|
}
|
}
|
} while(1);
|
} while(1);
|
}
|
}
|
|
|
TASKP kschedule(int LAST_TASK, TASKP *tasklist, TASKP last) {
|
TASKP kschedule(int LAST_TASK, TASKP *tasklist, TASKP last) {
|
TASKP current = tasklist[LAST_TASK];
|
TASKP current = tasklist[LAST_TASK];
|
int nxtid = 0, i;
|
int nxtid = 0, i;
|
|
|
// What task were we just running?
|
// What task were we just running?
|
for(i=0; i<=LAST_TASK; i++) {
|
for(i=0; i<=LAST_TASK; i++) {
|
if (last == tasklist[i]) {
|
if (last == tasklist[i]) {
|
// If we found it, then let's run the next one
|
// If we found it, then let's run the next one
|
nxtid = i+1;
|
nxtid = i+1;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
// Now let's see if we can find the next ready task to run
|
// Now let's see if we can find the next ready task to run
|
for(; nxtid<LAST_TASK; nxtid++) {
|
for(; nxtid<LAST_TASK; nxtid++) {
|
if (tasklist[nxtid]->state == SCHED_READY) {
|
if (tasklist[nxtid]->state == SCHED_READY) {
|
current=tasklist[nxtid];
|
current=tasklist[nxtid];
|
break;
|
break;
|
}
|
}
|
}
|
}
|
// The last task (the idle task) doesn't count
|
// The last task (the idle task) doesn't count
|
if (nxtid >= LAST_TASK) {
|
if (nxtid >= LAST_TASK) {
|
nxtid = 0; // Don't automatically run idle task
|
nxtid = 0; // Don't automatically run idle task
|
for(; nxtid<LAST_TASK; nxtid++)
|
for(; nxtid<LAST_TASK; nxtid++)
|
if (tasklist[nxtid]->state == SCHED_READY) {
|
if (tasklist[nxtid]->state == SCHED_READY) {
|
break;
|
break;
|
}
|
}
|
// Now we stop at the idle task, if nothing else is ready
|
// Now we stop at the idle task, if nothing else is ready
|
current = tasklist[nxtid];
|
current = tasklist[nxtid];
|
} return current;
|
} return current;
|
}
|
}
|
|
|
int kpost(TASKP *tasklist, unsigned events, int milliseconds) {
|
int kpost(TASKP *tasklist, unsigned events, int milliseconds) {
|
int i;
|
int i;
|
if (events & INT_TIMA)
|
if (events & INT_TIMER)
|
milliseconds++;
|
milliseconds++;
|
if (milliseconds<0) {
|
if (milliseconds<0) {
|
milliseconds -= 0x80000000;
|
milliseconds -= 0x80000000;
|
for(i=0; i<=LAST_TASK; i++) {
|
for(i=0; i<=LAST_TASK; i++) {
|
if(tasklist[i]->timeout) {
|
if(tasklist[i]->timeout) {
|
tasklist[i]->timeout -= 0x80000000;
|
tasklist[i]->timeout -= 0x80000000;
|
if (tasklist[i]->timeout==0)
|
if (tasklist[i]->timeout==0)
|
tasklist[i]->timeout++;
|
tasklist[i]->timeout++;
|
if ((int)tasklist[i]->timeout < milliseconds) {
|
if ((int)tasklist[i]->timeout < milliseconds) {
|
tasklist[i]->pending |= SWINT_TIMEOUT;
|
tasklist[i]->pending |= SWINT_TIMEOUT;
|
tasklist[i]->timeout = 0;
|
tasklist[i]->timeout = 0;
|
}
|
}
|
}
|
}
|
}
|
}
|
} else {
|
} else {
|
for(i=0; i<=LAST_TASK; i++) {
|
for(i=0; i<=LAST_TASK; i++) {
|
if(tasklist[i]->timeout) {
|
if(tasklist[i]->timeout) {
|
if (tasklist[i]->timeout < (unsigned)milliseconds) {
|
if (tasklist[i]->timeout < (unsigned)milliseconds) {
|
tasklist[i]->pending |= SWINT_TIMEOUT;
|
tasklist[i]->pending |= SWINT_TIMEOUT;
|
tasklist[i]->timeout = 0;
|
tasklist[i]->timeout = 0;
|
}
|
}
|
}
|
}
|
}
|
}
|
} for(i=0; i<=LAST_TASK; i++) {
|
} for(i=0; i<=LAST_TASK; i++) {
|
tasklist[i]->pending |= events;
|
tasklist[i]->pending |= events;
|
if ((tasklist[i]->state == SCHED_WAITING)
|
if ((tasklist[i]->state == SCHED_WAITING)
|
&&(tasklist[i]->waitsig&tasklist[i]->pending)) {
|
&&(tasklist[i]->waitsig&tasklist[i]->pending)) {
|
tasklist[i]->state = SCHED_READY;
|
tasklist[i]->state = SCHED_READY;
|
tasklist[i]->context[1] = tasklist[i]->waitsig & tasklist[i]->pending;
|
tasklist[i]->context[1] = tasklist[i]->waitsig & tasklist[i]->pending;
|
tasklist[i]->pending &= (~tasklist[i]->context[1]);
|
tasklist[i]->pending &= (~tasklist[i]->context[1]);
|
tasklist[i]->waitsig = 0;
|
tasklist[i]->waitsig = 0;
|
}
|
}
|
} return milliseconds;
|
} return milliseconds;
|
}
|
}
|
|
|
|
|
|
|