OpenCores
URL https://opencores.org/ocsvn/thor/thor/trunk

Subversion Repositories thor

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 22 to Rev 23
    Reverse comparison

Rev 22 → Rev 23

/thor/trunk/software/FMTK/source/kernel/keybd.c
0,0 → 1,398
// The keyboard semaphore is locked only for short durations, so the interrupt
// routine doesn't need to make many attempts to lock the semaphore.
 
#include "config.h"
#include "const.h"
#include "types.h"
#include "glo.h"
#include "proto.h"
 
#define SC_F12 0x07
#define SC_C 0x21
#define SC_T 0x2C
#define SC_Z 0x1A
#define SC_KEYUP 0xF0
#define SC_EXTEND 0xE0
#define SC_CTRL 0x14
#define SC_RSHIFT 0x59
#define SC_NUMLOCK 0x77
#define SC_SCROLLLOCK 0x7E
#define SC_CAPSLOCK 0x58
#define SC_ALT 0x11
/*
#define SC_LSHIFT EQU $12
SC_DEL EQU $71 ; extend
SC_LCTRL EQU $58
*/
#define SC_TAB 0x0D
 
extern byte keybdExtendedCodes[];
extern byte keybdControlCodes[];
extern byte shiftedScanCodes[];
extern byte unshiftedScanCodes[];
extern signed byte KeybdGetStatus();
extern byte KeybdGetScancode();
extern void KeybdClearRcv();
int kbd_sema = 0;
 
//
// KeyState2_
// 76543210
// |||||||+ = shift
// ||||||+- = alt
// |||||+-- = control
// ||||+--- = numlock
// |||+---- = capslock
// ||+----- = scrolllock
// |+------ =
// +------- = extended
//
 
unsigned int keybd_irq_stack[256];
static hMBX hKeybdMbx = -1;
 
void KeybdIRQ()
{
__int8 sc;
__int8 kh, kt;
hTCB ht;
TCB *t;
JCB *jcb;
int nn;
 
prolog asm {
sync
sw r1,TCB_ir1[tr]
sw r2,TCB_ir2[tr]
sw r3,TCB_ir3[tr]
sw r4,TCB_ir4[tr]
sw r5,TCB_ir5[tr]
sw r6,TCB_ir6[tr]
sw r7,TCB_ir7[tr]
sw r8,TCB_ir8[tr]
sw r9,TCB_ir9[tr]
sw r10,TCB_ir10[tr]
sw r11,TCB_ir11[tr]
sw r12,TCB_ir12[tr]
sw r13,TCB_ir13[tr]
sw r14,TCB_ir14[tr]
sw r15,TCB_ir15[tr]
sw r16,TCB_ir16[tr]
sw r17,TCB_ir17[tr]
sw r18,TCB_ir18[tr]
sw r19,TCB_ir19[tr]
sw r20,TCB_ir20[tr]
sw r21,TCB_ir21[tr]
sw r22,TCB_ir22[tr]
sw r23,TCB_ir23[tr]
sw r24,TCB_ir24[tr]
sw r25,TCB_ir25[tr]
sw r26,TCB_ir26[tr]
sw r27,TCB_ir27[tr]
sws ds,TCB_ids[tr]
sws es,TCB_ies[tr]
sws fs,TCB_ifs[tr]
sws gs,TCB_igs[tr]
sws hs,TCB_ihs[tr]
sws ss,TCB_iss[tr]
sws cs,TCB_ics[tr]
sws ds.lmt,TCB_idslmt[tr]
sws es.lmt,TCB_ieslmt[tr]
sws fs.lmt,TCB_ifslmt[tr]
sws gs.lmt,TCB_igslmt[tr]
sws hs.lmt,TCB_ihslmt[tr]
sws ss.lmt,TCB_isslmt[tr]
sws cs.lmt,TCB_icslmt[tr]
sws c1,TCB_ic1[tr]
sws c2,TCB_ic2[tr]
sws c3,TCB_ic3[tr]
sws c4,TCB_ic4[tr]
sws c5,TCB_ic5[tr]
sws c6,TCB_ic6[tr]
sws c7,TCB_ic7[tr]
sws c8,TCB_ic8[tr]
sws c9,TCB_ic9[tr]
sws c10,TCB_ic10[tr]
sws c11,TCB_ic11[tr]
sws c13,TCB_ic13[tr]
sws c14,TCB_ic14[tr]
sws pregs,TCB_ipregs[tr]
 
ldi sp,#irq_stack_+511*8 ; setup system stack and data segments
mtspr ss,r0
ldis ss.lmt,#-1
mtspr ds,r0
ldis ds.lmt,#-1
ldi hs,#$FFD00000
ldi hs.lmt,#$100000
}
while (KeybdGetStatus() < 0) { // Is there actually a scancode available ?
sc = KeybdGetScancode();
jcb = IOFocusNdx; // Are there any jobs with focus ?
if (jcb) {
if (LockSemaphore(&kbd_sema,200)) {
KeybdClearRcv(); // clear recieve register
kh = jcb->KeybdHead;
kt = jcb->KeybdTail;
kh++;
if (kh > jcb->KeybdBufSz)
kh = 0;
if (kh <> kt) {
jcb->KeybdHead = kh;
jcb->KeybdBuf[kh] = sc;
}
UnlockSemaphore(&kbd_sema);
}
// Trigger debugger if F12 pressed. Set a breakpoint at the RTI
// return address.
if (sc==SC_F12 && !jcb->KeyState1) {
asm {
mfspr r1,ipc
mtspr dbad0,r1 ; Set breakpoint 0 address
mfspr r1,dbctrl
or r1,r1,#1 ; enable breakpoint #0
and r1,r1,#~0x30000
mtspr dbctrl,r1
}
}
// If CTRL-C is pressed, cause the tasks to return to the
// catch handler.
if (jcb->KeyState2 & 4) {
if(sc == SC_C) { // control-c ?
for (nn = 0; nn < 8; nn++) {
if (jcb->tasks[nn]==-1)
break;
t = &tcbs[jcb->tasks[nn]];
t->exception = 512+3; // CTRL-C type exception
}
}
else if (sc==SC_T || sc==SC_Z) {
t = &tcbs[2];
t->exception = (512 + ((sc==SC_T) ? 20 : 26)) | (GetRunningTCB() << 32);
}
}
if ((jcb->KeyState2 & 2) && sc == SC_TAB) // ALT + TAB ?
if (hFocusSwitchMbx >= 0)
FMTK_PostMsg(hFocusSwitchMbx,-1,-1,-1);
// iof_switch++;
}
if (hKeybdMbx >= 0)
FMTK_PostMsg(hKeybdMbx,-1,-1,-1);
}
// Restore the processor registers and return using an RTI.
epilog asm {
lw r1,TCB_ir1[tr]
lw r2,TCB_ir2[tr]
lw r3,TCB_ir3[tr]
lw r4,TCB_ir4[tr]
lw r5,TCB_ir5[tr]
lw r6,TCB_ir6[tr]
lw r7,TCB_ir7[tr]
lw r8,TCB_ir8[tr]
lw r9,TCB_ir9[tr]
lw r10,TCB_ir10[tr]
lw r11,TCB_ir11[tr]
lw r12,TCB_ir12[tr]
lw r13,TCB_ir13[tr]
lw r14,TCB_ir14[tr]
lw r15,TCB_ir15[tr]
lw r16,TCB_ir16[tr]
lw r17,TCB_ir17[tr]
lw r18,TCB_ir18[tr]
lw r19,TCB_ir19[tr]
lw r20,TCB_ir20[tr]
lw r21,TCB_ir21[tr]
lw r22,TCB_ir22[tr]
lw r23,TCB_ir23[tr]
lw r24,TCB_ir24[tr]
lw r25,TCB_ir25[tr]
lw r26,TCB_ir26[tr]
lw r27,TCB_ir27[tr]
lws ds,TCB_ids[tr]
lws es,TCB_ies[tr]
lws fs,TCB_ifs[tr]
lws gs,TCB_igs[tr]
lws hs,TCB_ihs[tr]
lws ss,TCB_iss[tr]
lws cs,TCB_ics[tr]
lws ds.lmt,TCB_idslmt[tr]
lws es.lmt,TCB_ieslmt[tr]
lws fs.lmt,TCB_ifslmt[tr]
lws gs.lmt,TCB_igslmt[tr]
lws hs.lmt,TCB_ihslmt[tr]
lws ss.lmt,TCB_isslmt[tr]
lws cs.lmt,TCB_icslmt[tr]
lws c1,TCB_ic1[tr]
lws c2,TCB_ic2[tr]
lws c3,TCB_ic3[tr]
lws c4,TCB_ic4[tr]
lws c5,TCB_ic5[tr]
lws c6,TCB_ic6[tr]
lws c7,TCB_ic7[tr]
lws c8,TCB_ic8[tr]
lws c9,TCB_ic9[tr]
lws c10,TCB_ic10[tr]
lws c11,TCB_ic11[tr]
lws c13,TCB_ic13[tr]
lws c14,TCB_ic14[tr]
lws pregs,TCB_ipregs[tr]
sync
rti
}
}
 
 
// Return -1 if there is a scancode available in the buffer.
 
int KeybdGetBufferStatus()
{
JCB *j;
__int8 kh, kt;
 
kh = kt = 0;
j = GetJCBPtr();
if (LockSemaphore(&kbd_sema,200)) {
kh = j->KeybdHead;
kt = j->KeybdTail;
UnlockSemaphore(&kbd_sema);
}
if (kh<>kt)
return -1;
return 0;
}
 
// Get a scancode from the keyboard buffer.
 
__int8 KeybdGetBufferedScancode()
{
JCB *j;
__int8 kh, kt;
__int8 sc;
 
j = GetJCBPtr();
sc = 0;
if (LockSemaphore(&kbd_sema,200)) {
kh = j->KeybdHead;
kt = j->KeybdTail;
if (kh <> kt) {
sc = j->KeybdBuf[kt];
kt++;
if (kt > j->KeybdBufSz)
kt = 0;
j->KeybdTail = kt;
}
UnlockSemaphore(&kbd_sema);
}
return sc;
}
 
private char KeybdGetBufferedChar()
{
JCB *j;
unsigned __int8 sc;
char ch;
int d1, d2, d3;
static int fc = 0;
 
if (!fc) {
FMTK_AllocMbx(&hKeybdMbx);
fc = 1;
}
j = GetJCBPtr();
forever {
while (KeybdGetBufferStatus() >= 0) {
if (j->KeybdWaitFlag==0)
return -1;
FMTK_WaitMsg(hKeybdMbx, &d1, &d2, &d3, 0x7FFFFFFFFFFFFFFFL);
}
// The following typecast is needed to avoid a compiler bug in the
// optimizer which removes the conversion from byte to word by zero
// extension.
sc = (unsigned __int8)KeybdGetBufferedScancode();
switch(sc) {
case SC_KEYUP:
j->KeyState1 = -1;
break;
case SC_EXTEND:
j->KeyState2 |= 0x80;
break;
case SC_CTRL:
if (j->KeyState1 >= 0)
j->KeyState2 |= 4;
else
j->KeyState2 &= ~4;
j->KeyState1 = 0;
break;
case SC_RSHIFT:
if (j->KeyState1 >= 0)
j->KeyState2 |= 1;
else
j->KeyState2 &= ~1;
j->KeyState1 = 0;
break;
case SC_NUMLOCK:
j->KeyState2 ^= 16;
//KeybdSetLEDStatus();
break;
case SC_CAPSLOCK:
j->KeyState2 ^= 32;
//KeybdSetLEDStatus();
break;
case SC_SCROLLLOCK:
j->KeyState2 ^= 64;
//KeybdSetLEDStatus();
break;
case SC_ALT:
if (j->KeyState1 >= 0)
j->KeyState2 |= 2;
else
j->KeyState2 &= ~2;
j->KeyState1 = 0;
break;
default:
if (sc == SC_TAB && (j->KeyState2 & 2) && j->KeyState1==0) {
iof_switch++;
}
else {
if (j->KeyState1) {
j->KeyState1 = 0;
}
else {
if (j->KeyState2 & 0x80) { // Extended code ?
j->KeyState2 &= ~0x80;
ch = keybdExtendedCodes[sc];
return ch;
}
else if (j->KeyState2 & 0x04) { // control ?
ch = keybdControlCodes[sc];
return ch;
}
else if (j->KeyState2 & 0x01) { // shifted ?
ch = shiftedScanCodes[sc];
return ch;
}
else {
ch = unshiftedScanCodes[sc];
return ch;
}
}
}
}
}
}
 
char KeybdGetBufferedCharWait() {
JCB *j;
j = GetJCBPtr();
j->KeybdWaitFlag = 1;
return KeybdGetBufferedChar();
}
 
char KeybdGetBufferedCharNoWait() {
JCB *j;
j = GetJCBPtr();
j->KeybdWaitFlag = 0;
return KeybdGetBufferedChar();
}
 
/thor/trunk/software/FMTK/source/kernel/UnlockSemaphore.c
0,0 → 1,32
// ============================================================================
// __
// \\__/ o\ (C) 2012-2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// UnlockSemaphore.c
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ============================================================================
//
pascal void UnlockSemaphore(int *sema)
{
asm {
lw r1,32[bp]
ldi r2,#-1
sw r2,[r1]
}
}
/thor/trunk/software/FMTK/source/kernel/console.c
0,0 → 1,313
#include "types.h"
#include "proto.h"
 
// The text screen memory can only handle half-word transfers, hence the use
// of memsetH, memcpyH.
 
extern int IOFocusNdx;
 
short int *GetScreenLocation()
{
return GetJCBPtr()->pVidMem;
}
 
short int GetCurrAttr()
{
return GetJCBPtr()->NormAttr;
}
 
void SetCurrAttr(short int attr)
{
GetJCBPtr()->NormAttr = attr & 0xFFFFFC00;
}
 
static pascal void SetVideoReg(int regno, int val)
{
if (regno < 0 or regno > 11) {
printf("bad video regno: %d", regno);
return;
}
asm {
lw r1,32[bp]
lw r2,40[bp]
shli r1,r1,#2
sh r2,zs:$FFDA0000[r1]
}
}
 
void SetCursorPos(int row, int col)
{
JCB *j;
 
j = GetJCBPtr();
j->CursorCol = col;
j->CursorRow = row;
UpdateCursorPos();
}
 
void SetCursorCol(int col)
{
JCB *j;
 
j = GetJCBPtr();
j->CursorCol = col;
UpdateCursorPos();
}
 
int GetCursorPos()
{
JCB *j;
 
j = GetJCBPtr();
return j->CursorCol | (j->CursorRow << 8);
}
 
int GetTextCols()
{
return GetJCBPtr()->VideoCols;
}
 
int GetTextRows()
{
return GetJCBPtr()->VideoRows;
}
 
char AsciiToScreen(char ch)
{
if (ch==0x5B)
return 0x1B;
if (ch==0x5D)
return 0x1D;
ch &= 0xFF;
ch |= 0x100;
if (!(ch & 0x20))
return ch;
if (!(ch & 0x40))
return ch;
ch = ch & 0x19F;
return ch;
}
 
char ScreenToAscii(char ch)
{
ch &= 0xFF;
if (ch==0x1B)
return 0x5B;
if (ch==0x1D)
return 0x5D;
if (ch < 27)
ch += 0x60;
return ch;
}
 
void UpdateCursorPos()
{
JCB *j;
int pos;
 
j = GetJCBPtr();
// if (j == IOFocusNdx) {
pos = j->CursorRow * j->VideoCols + j->CursorCol;
SetVideoReg(11,pos);
// }
}
 
void HomeCursor()
{
JCB *j;
 
j = GetJCBPtr();
j->CursorCol = 0;
j->CursorRow = 0;
UpdateCursorPos();
}
 
short int *CalcScreenLocation()
{
JCB *j;
int pos;
 
j = GetJCBPtr();
pos = j->CursorRow * j->VideoCols + j->CursorCol;
// if (j == IOFocusNdx) {
SetVideoReg(11,pos);
// }
return GetScreenLocation()+pos;
}
 
void ClearScreen()
{
short int *p;
int nn;
int mx;
JCB *j;
short int vc;
j = GetJCBPtr();
p = GetScreenLocation();
// Compiler did a byte multiply generating a single byte result first
// before assigning it to mx. The (int) casts force the compiler to use
// an int result.
mx = (int)j->VideoRows * (int)j->VideoCols;
vc = GetCurrAttr() | AsciiToScreen(' ');
memsetH(p, vc, mx);
}
 
void ClearBmpScreen()
{
memsetW(0x400000, 0, 0x80000);
}
 
void BlankLine(int row)
{
short int *p;
int nn;
int mx;
JCB *j;
short int vc;
j = GetJCBPtr();
p = GetScreenLocation();
p = p + (int)j->VideoCols * row;
vc = GetCurrAttr() | AsciiToScreen(' ');
memsetH(p, vc, j->VideoCols);
}
 
// ScrollUp will call BlankLine. Scrollup is written in assembler for
// performance reasons and is included as part of the video BIOS. Note the
// BIOS cannot be called with SYS #10 because the bios isn't re-entrant and
// the bios is already active from putch().
naked ScrollUp()
{
asm {
addui sp,sp,#-8
sws c1,[sp]
bsr VBScrollUp
lws c1,[sp]
addui sp,sp,#8
rts
}
}
 
void IncrementCursorRow()
{
JCB *j;
j = GetJCBPtr();
j->CursorRow++;
if (j->CursorRow < j->VideoRows) {
UpdateCursorPos();
return;
}
j->CursorRow--;
UpdateCursorPos();
ScrollUp();
}
 
void IncrementCursorPos()
{
JCB *j;
j = GetJCBPtr();
j->CursorCol++;
if (j->CursorCol < j->VideoCols) {
UpdateCursorPos();
return;
}
j->CursorCol = 0;
IncrementCursorRow();
}
 
void DisplayChar(char ch)
{
short int *p;
int nn;
JCB *j;
 
j = GetJCBPtr();
switch(ch) {
case '\r': j->CursorCol = 0; UpdateCursorPos(); break;
case '\n': IncrementCursorRow(); break;
case 0x91:
if (j->CursorCol < j->VideoCols-1) {
j->CursorCol++;
UpdateCursorPos();
}
break;
case 0x90:
if (j->CursorRow > 0) {
j->CursorRow--;
UpdateCursorPos();
}
break;
case 0x93:
if (j->CursorCol > 0) {
j->CursorCol--;
UpdateCursorPos();
}
break;
case 0x92:
if (j->CursorRow < j->VideoRows-1) {
j->CursorRow++;
UpdateCursorPos();
}
break;
case 0x94:
if (j->CursorCol==0)
j->CursorRow = 0;
j->CursorCol = 0;
UpdateCursorPos();
break;
case 0x99: // delete
p = CalcScreenLocation();
for (nn = j->CursorCol; nn < j->VideoCols-1; nn++) {
p[nn-j->CursorCol] = p[nn+1-j->CursorCol];
}
p[nn-j->CursorCol] = GetCurrAttr() | AsciiToScreen(' ');
break;
case 0x08: // backspace
if (j->CursorCol > 0) {
j->CursorCol--;
p = CalcScreenLocation();
for (nn = j->CursorCol; nn < j->VideoCols-1; nn++) {
p[nn-j->CursorCol] = p[nn+1-j->CursorCol];
}
p[nn-j->CursorCol] = GetCurrAttr() | AsciiToScreen(' ');
}
break;
case 0x0C: // CTRL-L
ClearScreen();
HomeCursor();
break;
case '\t':
DisplayChar(' ');
DisplayChar(' ');
DisplayChar(' ');
DisplayChar(' ');
break;
default:
p = CalcScreenLocation();
*p = GetCurrAttr() | AsciiToScreen(ch);
IncrementCursorPos();
break;
}
}
 
void CRLF()
{
DisplayChar('\r');
DisplayChar('\n');
}
 
void DisplayString(char *s)
{
while (*s) { DisplayChar(*s); s++; }
}
 
void DisplayStringCRLF(char *s)
{
DisplayString(s);
CRLF();
}
 
/thor/trunk/software/FMTK/source/kernel/FMTKc.c
0,0 → 1,1050
// ============================================================================
// __
// \\__/ o\ (C) 2012-2016 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ============================================================================
//
#include "config.h"
#include "const.h"
#include "types.h"
#include "proto.h"
#include "glo.h"
 
extern int shell();
extern void KeybdIRQ();
extern pascal int putstr(char *, int);
extern int printf(char *, ...);
void panic(char *msg);
extern int FMTK_FreeMbx(hMBX);
 
int irq_stack[512];
int sp_tmp;
int FMTK_Inited;
JCB jcbs[NR_JCB];
extern TCB tcbs[NR_TCB];
extern hTCB readyQ[8];
int sysstack[1024];
int stacks[NR_TCB][1024];
int sys_stacks[NR_TCB][512];
int bios_stacks[NR_TCB][512];
int fmtk_irq_stack[512];
int fmtk_sys_stack[512];
MBX mailbox[NR_MBX];
MSG message[NR_MSG];
int nMsgBlk;
int nMailbox;
hJCB freeJCB;
hMSG freeMSG;
hMBX freeMBX;
JCB *IOFocusNdx;
int IOFocusTbl[4];
int iof_switch;
int BIOS1_sema;
int iof_sema;
int sys_sema;
int BIOS_RespMbx;
char hasUltraHighPriorityTasks;
int missed_ticks;
 
short int video_bufs[NR_JCB][4096];
extern hTCB TimeoutList;
 
extern void gfx_demo();
 
// This table needed in case we want to call the OS routines directly.
// It is also used by the system call interrupt as a vector table.
 
naked void FMTK_BrTbl()
{
asm {
align 4
dh FMTKInitialize_
dh FMTK_StartTask_
dh FMTK_ExitTask_
dh FMTK_KillTask_
dh FMTK_SetTaskPriority_
dh FMTK_Sleep_
dh FMTK_AllocMbx_
dh FMTK_FreeMbx_
dh FMTK_PostMsg_
dh FMTK_SendMsg_
dh FMTK_WaitMsg_
dh FMTK_CheckMsg_
}
}
 
naked int GetVecno()
{
asm {
mfspr r1,12
rts
}
}
 
naked void DisplayIRQLive()
{
asm {
lh r1,hs:328
addui r1,r1,#1
sh r1,hs:328
}
}
 
JCB *GetJCBPtr()
{
return &jcbs[tcbs[GetRunningTCB()].hJob];
}
 
 
// ----------------------------------------------------------------------------
// Select a task to run.
// ----------------------------------------------------------------------------
 
private const __int8 startQ[32] = { 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 1, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 1, 0, 7, 0, 0, 0, 0 };
private __int8 startQNdx;
 
private hTCB SelectTaskToRun()
{
int nn,kk;
TCB *p, *q;
int qToCheck;
hTCB h;
startQNdx++;
startQNdx &= 31;
qToCheck = startQ[startQNdx];
qToCheck &= 7;
for (nn = 0; nn < 8; nn++) {
h = readyQ[qToCheck];
if (h >= 0 && h < NR_TCB) {
p = &tcbs[h];
kk = 0;
// Can run the head of a lower Q level if it's not the running
// task, otherwise look to the next task.
if (h != GetRunningTCB())
q = p;
else
q = &tcbs[p->next];
do {
if (!(q->status & TS_RUNNING)) {
if (q->affinity == getCPU()) {
readyQ[qToCheck] = q - tcbs;
return q - tcbs;
}
}
q = &tcbs[q->next];
kk = kk + 1;
} while (q != p && kk < NR_TCB);
}
qToCheck++;
qToCheck &= 7;
}
return GetRunningTCB();
panic("No entries in ready queue.");
}
 
// ----------------------------------------------------------------------------
// There isn't any 'C' code in the SystemCall() function. If there were it
// would have to be arranged like the TimerIRQ() or RescheduleIRQ() functions.
// ----------------------------------------------------------------------------
 
naked FMTK_SystemCall()
{
asm {
sync
sw r2,TCB_r2[tr]
sw r3,TCB_r3[tr]
sw r4,TCB_r4[tr]
sw r5,TCB_r5[tr]
sw r6,TCB_r6[tr]
sw r7,TCB_r7[tr]
sw r8,TCB_r8[tr]
sw r9,TCB_r9[tr]
sw r10,TCB_r10[tr]
sw r11,TCB_r11[tr]
sw r12,TCB_r12[tr]
sw r13,TCB_r13[tr]
sw r14,TCB_r14[tr]
sw r15,TCB_r15[tr]
sw r16,TCB_r16[tr]
sw r17,TCB_r17[tr]
sw r18,TCB_r18[tr]
sw r19,TCB_r19[tr]
sw r20,TCB_r20[tr]
sw r21,TCB_r21[tr]
sw r22,TCB_r22[tr]
sw r23,TCB_r23[tr]
sw r24,TCB_r24[tr]
sw r25,TCB_r25[tr]
sw r26,TCB_r26[tr]
sw r27,TCB_r27[tr]
sws ds,TCB_ds[tr]
sws es,TCB_es[tr]
sws fs,TCB_fs[tr]
sws gs,TCB_gs[tr]
sws hs,TCB_hs[tr]
sws ss,TCB_ss[tr]
sws cs,TCB_cs[tr]
sws ds.lmt,TCB_dslmt[tr]
sws es.lmt,TCB_eslmt[tr]
sws fs.lmt,TCB_fslmt[tr]
sws gs.lmt,TCB_gslmt[tr]
sws hs.lmt,TCB_hslmt[tr]
sws ss.lmt,TCB_sslmt[tr]
sws cs.lmt,TCB_cslmt[tr]
sws c1,TCB_c1[tr]
sws c2,TCB_c2[tr]
sws c3,TCB_c3[tr]
sws c4,TCB_c4[tr]
sws c5,TCB_c5[tr]
sws c6,TCB_c6[tr]
sws c7,TCB_c7[tr]
sws c8,TCB_c8[tr]
sws c9,TCB_c9[tr]
sws c10,TCB_c10[tr]
sws c11,TCB_c11[tr]
sws c13,TCB_c13[tr]
sws c14,TCB_c14[tr]
sws pregs,TCB_pregs[tr]
}
asm {
ldi sp,#sysstack_+1023*8 ; switch to system stack
mtspr ss,r0
ldi ss.lmt,#-1
mtspr ds,r0 ; and data segment
ldi ds.lmt,#-1
mfspr r6,c13 ; r6 = return address
lbu r7,[r6] ; r7 = static call number parameter
addui r6,r6,#1
mtspr c13,r6
sws c13,TCB_c13[tr] ; save c13 in task image
cmpi p0,r7,#20
p0.gtu ldi r1,#E_BadFuncno
p0.gtu br .0001
addui sp,sp,#-40
sw r1,[sp]
sw r2,8[sp]
sw r3,16[sp]
sw r4,24[sp]
sw r5,32[sp]
jhi c1,cs:FMTK_BrTbl_[r7] ; do the system function
.0001:
; leave r1 as system call result
lw r2,TCB_r2[tr]
lw r3,TCB_r3[tr]
lw r4,TCB_r4[tr]
lw r5,TCB_r5[tr]
lw r6,TCB_r6[tr]
lw r7,TCB_r7[tr]
lw r8,TCB_r8[tr]
lw r9,TCB_r9[tr]
lw r10,TCB_r10[tr]
lw r11,TCB_r11[tr]
lw r12,TCB_r12[tr]
lw r13,TCB_r13[tr]
lw r14,TCB_r14[tr]
lw r15,TCB_r15[tr]
lw r16,TCB_r16[tr]
lw r17,TCB_r17[tr]
lw r18,TCB_r18[tr]
lw r19,TCB_r19[tr]
lw r20,TCB_r20[tr]
lw r21,TCB_r21[tr]
lw r22,TCB_r22[tr]
lw r23,TCB_r23[tr]
lw r24,TCB_r24[tr]
lw r25,TCB_r25[tr]
lw r26,TCB_r26[tr]
lw r27,TCB_r27[tr]
lws ds,TCB_ds[tr]
lws es,TCB_es[tr]
lws fs,TCB_fs[tr]
lws gs,TCB_gs[tr]
lws hs,TCB_hs[tr]
lws ss,TCB_ss[tr]
lws cs,TCB_cs[tr]
lws ds.lmt,TCB_dslmt[tr]
lws es.lmt,TCB_eslmt[tr]
lws fs.lmt,TCB_fslmt[tr]
lws gs.lmt,TCB_gslmt[tr]
lws hs.lmt,TCB_hslmt[tr]
lws ss.lmt,TCB_sslmt[tr]
lws cs.lmt,TCB_cslmt[tr]
lws c1,TCB_c1[tr]
lws c2,TCB_c2[tr]
lws c3,TCB_c3[tr]
lws c4,TCB_c4[tr]
lws c5,TCB_c5[tr]
lws c6,TCB_c6[tr]
lws c7,TCB_c7[tr]
lws c8,TCB_c8[tr]
lws c9,TCB_c9[tr]
lws c10,TCB_c10[tr]
lws c11,TCB_c11[tr]
lws c13,TCB_c13[tr]
lws c14,TCB_c14[tr]
lws pregs,TCB_pregs[tr]
sync
rte
}
}
 
// ----------------------------------------------------------------------------
// If timer interrupts are enabled during a priority #0 task, this routine
// only updates the missed ticks and remains in the same task. No timeouts
// are updated and no task switches will occur. The timer tick routine
// basically has a fixed latency when priority #0 is present.
// ----------------------------------------------------------------------------
 
void FMTK_SchedulerIRQ()
{
TCB *t;
 
prolog asm {
sync
sw r1,TCB_ir1[tr]
sw r2,TCB_ir2[tr]
sw r3,TCB_ir3[tr]
sw r4,TCB_ir4[tr]
sw r5,TCB_ir5[tr]
sw r6,TCB_ir6[tr]
sw r7,TCB_ir7[tr]
sw r8,TCB_ir8[tr]
sw r9,TCB_ir9[tr]
sw r10,TCB_ir10[tr]
sw r11,TCB_ir11[tr]
sw r12,TCB_ir12[tr]
sw r13,TCB_ir13[tr]
sw r14,TCB_ir14[tr]
sw r15,TCB_ir15[tr]
sw r16,TCB_ir16[tr]
sw r17,TCB_ir17[tr]
sw r18,TCB_ir18[tr]
sw r19,TCB_ir19[tr]
sw r20,TCB_ir20[tr]
sw r21,TCB_ir21[tr]
sw r22,TCB_ir22[tr]
sw r23,TCB_ir23[tr]
sw r24,TCB_ir24[tr]
sw r25,TCB_ir25[tr]
sw r26,TCB_ir26[tr]
sw r27,TCB_ir27[tr]
sws ds,TCB_ids[tr]
sws es,TCB_ies[tr]
sws fs,TCB_ifs[tr]
sws gs,TCB_igs[tr]
sws hs,TCB_ihs[tr]
sws ss,TCB_iss[tr]
sws cs,TCB_ics[tr]
sws ds.lmt,TCB_idslmt[tr]
sws es.lmt,TCB_ieslmt[tr]
sws fs.lmt,TCB_ifslmt[tr]
sws gs.lmt,TCB_igslmt[tr]
sws hs.lmt,TCB_ihslmt[tr]
sws ss.lmt,TCB_isslmt[tr]
sws cs.lmt,TCB_icslmt[tr]
sws c1,TCB_ic1[tr]
sws c2,TCB_ic2[tr]
sws c3,TCB_ic3[tr]
sws c4,TCB_ic4[tr]
sws c5,TCB_ic5[tr]
sws c6,TCB_ic6[tr]
sws c7,TCB_ic7[tr]
sws c8,TCB_ic8[tr]
sws c9,TCB_ic9[tr]
sws c10,TCB_ic10[tr]
sws c11,TCB_ic11[tr]
sws c13,TCB_ic13[tr]
sws c14,TCB_ic14[tr]
sws pregs,TCB_ipregs[tr]
 
ldi sp,#irq_stack_+511*8 ; setup system stack and data segments
mtspr ss,r0
ldis ss.lmt,#-1
mtspr ds,r0
ldis ds.lmt,#-1
ldi hs,#$FFD00000
ldi hs.lmt,#$100000
ldi r1,#2 ; reset edge sense circuit
sh r1,hs:PIC_ESR
}
DisplayIRQLive();
if (LockSemaphore(&sys_sema,10)) {
t = GetRunningTCBPtr();
t->ticks = t->ticks + (t->endTick - t->startTick);
if (t->priority != 000) {
t->status = TS_PREEMPT;
while (TimeoutList >= 0 && TimeoutList < NR_TCB) {
if (tcbs[TimeoutList].timeout<=0)
InsertIntoReadyList(PopTimeoutList());
else {
tcbs[TimeoutList].timeout = tcbs[TimeoutList].timeout - missed_ticks - 1;
missed_ticks = 0;
break;
}
}
if (t->priority > 002)
SetRunningTCB(SelectTaskToRun());
GetRunningTCBPtr()->status = TS_RUNNING;
}
else {
missed_ticks++;
}
UnlockSemaphore(&sys_sema);
}
else {
missed_ticks++;
}
// If an exception was flagged (eg CTRL-C) return to the catch handler
// not the interrupted code.
t = GetRunningTCBPtr();
if (t->exception) {
t->icregs[1] = t->icregs[11]; // set link register to catch handler
t->icregs[13] = t->icregs[11]; // and the PC register
t->iregs[1] = t->exception; // r1 = exception value
t->exception = 0;
t->iregs[2] = 24; // r2 = exception type
}
epilog asm {
lw r1,TCB_ir1[tr]
lw r2,TCB_ir2[tr]
lw r3,TCB_ir3[tr]
lw r4,TCB_ir4[tr]
lw r5,TCB_ir5[tr]
lw r6,TCB_ir6[tr]
lw r7,TCB_ir7[tr]
lw r8,TCB_ir8[tr]
lw r9,TCB_ir9[tr]
lw r10,TCB_ir10[tr]
lw r11,TCB_ir11[tr]
lw r12,TCB_ir12[tr]
lw r13,TCB_ir13[tr]
lw r14,TCB_ir14[tr]
lw r15,TCB_ir15[tr]
lw r16,TCB_ir16[tr]
lw r17,TCB_ir17[tr]
lw r18,TCB_ir18[tr]
lw r19,TCB_ir19[tr]
lw r20,TCB_ir20[tr]
lw r21,TCB_ir21[tr]
lw r22,TCB_ir22[tr]
lw r23,TCB_ir23[tr]
lw r24,TCB_ir24[tr]
lw r25,TCB_ir25[tr]
lw r26,TCB_ir26[tr]
lw r27,TCB_ir27[tr]
lws ds,TCB_ids[tr]
lws es,TCB_ies[tr]
lws fs,TCB_ifs[tr]
lws gs,TCB_igs[tr]
lws hs,TCB_ihs[tr]
lws ss,TCB_iss[tr]
lws cs,TCB_ics[tr]
lws ds.lmt,TCB_idslmt[tr]
lws es.lmt,TCB_ieslmt[tr]
lws fs.lmt,TCB_ifslmt[tr]
lws gs.lmt,TCB_igslmt[tr]
lws hs.lmt,TCB_ihslmt[tr]
lws ss.lmt,TCB_isslmt[tr]
lws cs.lmt,TCB_icslmt[tr]
lws c1,TCB_ic1[tr]
lws c2,TCB_ic2[tr]
lws c3,TCB_ic3[tr]
lws c4,TCB_ic4[tr]
lws c5,TCB_ic5[tr]
lws c6,TCB_ic6[tr]
lws c7,TCB_ic7[tr]
lws c8,TCB_ic8[tr]
lws c9,TCB_ic9[tr]
lws c10,TCB_ic10[tr]
lws c11,TCB_ic11[tr]
lws c13,TCB_ic13[tr]
lws c14,TCB_ic14[tr]
lws pregs,TCB_ipregs[tr]
sync
rti
}
}
 
void FMTK_SchedulerIRQ2()
{
TCB *t;
 
prolog asm {
sync
sw r1,TCB_ir1[tr]
sw r2,TCB_ir2[tr]
sw r3,TCB_ir3[tr]
sw r4,TCB_ir4[tr]
sw r5,TCB_ir5[tr]
sw r6,TCB_ir6[tr]
sw r7,TCB_ir7[tr]
sw r8,TCB_ir8[tr]
sw r9,TCB_ir9[tr]
sw r10,TCB_ir10[tr]
sw r11,TCB_ir11[tr]
sw r12,TCB_ir12[tr]
sw r13,TCB_ir13[tr]
sw r14,TCB_ir14[tr]
sw r15,TCB_ir15[tr]
sw r16,TCB_ir16[tr]
sw r17,TCB_ir17[tr]
sw r18,TCB_ir18[tr]
sw r19,TCB_ir19[tr]
sw r20,TCB_ir20[tr]
sw r21,TCB_ir21[tr]
sw r22,TCB_ir22[tr]
sw r23,TCB_ir23[tr]
sw r24,TCB_ir24[tr]
sw r25,TCB_ir25[tr]
sw r26,TCB_ir26[tr]
sw r27,TCB_ir27[tr]
sws ds,TCB_ids[tr]
sws es,TCB_ies[tr]
sws fs,TCB_ifs[tr]
sws gs,TCB_igs[tr]
sws hs,TCB_ihs[tr]
sws ss,TCB_iss[tr]
sws cs,TCB_ics[tr]
sws ds.lmt,TCB_idslmt[tr]
sws es.lmt,TCB_ieslmt[tr]
sws fs.lmt,TCB_ifslmt[tr]
sws gs.lmt,TCB_igslmt[tr]
sws hs.lmt,TCB_ihslmt[tr]
sws ss.lmt,TCB_isslmt[tr]
sws cs.lmt,TCB_icslmt[tr]
sws c1,TCB_ic1[tr]
sws c2,TCB_ic2[tr]
sws c3,TCB_ic3[tr]
sws c4,TCB_ic4[tr]
sws c5,TCB_ic5[tr]
sws c6,TCB_ic6[tr]
sws c7,TCB_ic7[tr]
sws c8,TCB_ic8[tr]
sws c9,TCB_ic9[tr]
sws c10,TCB_ic10[tr]
sws c11,TCB_ic11[tr]
sws c13,TCB_ic13[tr]
sws c14,TCB_ic14[tr]
sws pregs,TCB_ipregs[tr]
 
ldi sp,#irq_stack_+511*8 ; setup system stack and data segments
mtspr ss,r0
ldis ss.lmt,#-1
mtspr ds,r0
ldis ds.lmt,#-1
ldi hs,#$FFD00000
ldi hs.lmt,#$100000
ldi r1,#2 ; reset edge sense circuit
sh r1,hs:PIC_ESR
}
t->icregs[14] += 4; // update return address
// Explicit rescheduling request.
t = GetRunningTCBPtr();
t->ticks = t->ticks + (t->endTick - t->startTick);
t->status = TS_GIVEAWAY;
//t->iipc = t->iipc + 4; // advance the return address
SetRunningTCB(SelectTaskToRun());
t = GetRunningTCBPtr();
t->status = TS_RUNNING;
// If an exception was flagged (eg CTRL-C) return to the catch handler
// not the interrupted code.
if (t->exception) {
t->cregs[1] = t->cregs[11]; // set link register to catch handler
t->cregs[13] = t->cregs[11]; // and the PC register
t->regs[1] = t->exception; // r1 = exception value
t->exception = 0;
t->regs[2] = 24; // r2 = exception type
}
// Restore the processor registers and return using an RTE.
epilog asm {
lw r1,TCB_ir1[tr]
lw r2,TCB_ir2[tr]
lw r3,TCB_ir3[tr]
lw r4,TCB_ir4[tr]
lw r5,TCB_ir5[tr]
lw r6,TCB_ir6[tr]
lw r7,TCB_ir7[tr]
lw r8,TCB_ir8[tr]
lw r9,TCB_ir9[tr]
lw r10,TCB_ir10[tr]
lw r11,TCB_ir11[tr]
lw r12,TCB_ir12[tr]
lw r13,TCB_ir13[tr]
lw r14,TCB_ir14[tr]
lw r15,TCB_ir15[tr]
lw r16,TCB_ir16[tr]
lw r17,TCB_ir17[tr]
lw r18,TCB_ir18[tr]
lw r19,TCB_ir19[tr]
lw r20,TCB_ir20[tr]
lw r21,TCB_ir21[tr]
lw r22,TCB_ir22[tr]
lw r23,TCB_ir23[tr]
lw r24,TCB_ir24[tr]
lw r25,TCB_ir25[tr]
lw r26,TCB_ir26[tr]
lw r27,TCB_ir27[tr]
lws ds,TCB_ids[tr]
lws es,TCB_ies[tr]
lws fs,TCB_ifs[tr]
lws gs,TCB_igs[tr]
lws hs,TCB_ihs[tr]
lws ss,TCB_iss[tr]
lws cs,TCB_ics[tr]
lws ds.lmt,TCB_idslmt[tr]
lws es.lmt,TCB_ieslmt[tr]
lws fs.lmt,TCB_ifslmt[tr]
lws gs.lmt,TCB_igslmt[tr]
lws hs.lmt,TCB_ihslmt[tr]
lws ss.lmt,TCB_isslmt[tr]
lws cs.lmt,TCB_icslmt[tr]
lws c1,TCB_ic1[tr]
lws c2,TCB_ic2[tr]
lws c3,TCB_ic3[tr]
lws c4,TCB_ic4[tr]
lws c5,TCB_ic5[tr]
lws c6,TCB_ic6[tr]
lws c7,TCB_ic7[tr]
lws c8,TCB_ic8[tr]
lws c9,TCB_ic9[tr]
lws c10,TCB_ic10[tr]
lws c11,TCB_ic11[tr]
lws c13,TCB_ic13[tr]
lws c14,TCB_ic14[tr]
lws pregs,TCB_ipregs[tr]
sync
rti
}
}
 
void panic(char *msg)
{
putstr(msg,84);
j1: goto j1;
}
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
void IdleTask()
{
int ii;
__int32 *screen = (__int32 *)0xFFD00000;
 
// try {
j1: ;
forever {
try {
ii++;
if (getCPU()==0)
outh(&screen[81],ii);
}
catch(static __exception ex=0) {
if (ex&0xFFFFFFFFL==515) {
printf("IdleTask: CTRL-C pressed.\r\n");
}
else
throw ex;
}
}
/*
}
catch (static __exception ex1=0) {
printf("IdleTask: exception %d.\r\n", ex1);
goto j1;
}
*/
}
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
int FMTK_KillTask(int taskno)
{
hTCB ht;
int nn;
JCB *j;
 
check_privilege();
ht = taskno;
if (LockSemaphore(&sys_sema,-1)) {
RemoveFromReadyList(ht);
RemoveFromTimeoutList(ht);
for (nn = 0; nn < 4; nn++)
if (tcbs[ht].hMailboxes[nn] >= 0 && tcbs[ht].hMailboxes[nn] < NR_MBX) {
FMTK_FreeMbx(tcbs[ht].hMailboxes[nn]);
tcbs[ht].hMailboxes[nn] = -1;
}
// remove task from job's task list
j = &jcbs[tcbs[ht].hJob];
for (nn = 0; nn < 8; nn++) {
if (j->tasks[nn]==ht)
j->tasks[nn] = -1;
}
// If the job no longer has any tasks associated with it, it is
// finished.
for (nn = 0; nn < 8; nn++)
if (j->tasks[nn]!=-1)
break;
if (nn == 8) {
j->next = freeJCB;
freeJCB = j - jcbs;
}
UnlockSemaphore(&sys_sema);
}
}
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
int FMTK_ExitTask()
{
check_privilege();
KillTask(GetRunningTCB());
asm {
db $01
db $A6 ; INT
db $CE
db $02
} // reschedule
j1: goto j1;
}
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
int FMTK_StartTask(int priority, int affinity, int adr, int parm, hJCB job)
{
hTCB ht;
TCB *t;
int nn;
 
try {
asm {
ldi r1,#66
sc r1,hs:LEDS
}
check_privilege();
asm {
ldi r1,#60
sc r1,hs:LEDS
}
if (LockSemaphore(&sys_sema,-1)) {
ht = freeTCB;
freeTCB = tcbs[ht].next;
UnlockSemaphore(&sys_sema);
}
asm {
ldi r1,#61
sc r1,hs:LEDS
}
t = &tcbs[ht];
t->affinity = affinity;
t->priority = priority;
t->hJob = job;
// Insert into the job's list of tasks.
for (nn = 0; nn < 8; nn++) {
if (jcbs[job].tasks[nn]<0) {
jcbs[job].tasks[nn] = ht;
break;
}
}
asm {
ldi r1,#62
sc r1,hs:LEDS
}
if (nn == 8) {
if (LockSemaphore(&sys_sema,-1)) {
tcbs[ht].next = freeTCB;
freeTCB = ht;
UnlockSemaphore(&sys_sema);
}
return E_TooManyTasks;
}
asm {
ldi r1,#63
sc r1,hs:LEDS
}
t->iregs[1] = parm;
t->icregs[1] = FMTK_ExitTask;
t->iregs[27] = (unsigned int)t->stack + 1023*8;
t->icregs[13] = adr;
t->icregs[14] = adr;
// t->icr0 = 0x140000000L;
t->startTick = 0;
t->endTick = 0;
t->ticks = 0;
t->exception = 0;
asm {
ldi r1,#64
sc r1,hs:LEDS
}
if (LockSemaphore(&sys_sema,-1)) {
InsertIntoReadyList(ht);
UnlockSemaphore(&sys_sema);
}
asm {
ldi r1,#65
sc r1,hs:LEDS
}
}
catch(static int ex)
printf("StartTask error: %d\r\n", ex);
return E_Ok;
}
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
int FMTK_Sleep(int timeout)
{
hTCB ht;
check_privilege();
if (LockSemaphore(&sys_sema,-1)) {
ht = GetRunningTCB();
RemoveFromReadyList(ht);
InsertIntoTimeoutList(ht, timeout);
UnlockSemaphore(&sys_sema);
}
asm {
db $01
db $A6 ; INT
db $CE
db $02
} // reschedule
return E_Ok;
}
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
int FMTK_SetTaskPriority(hTCB ht, int priority)
{
TCB *t;
 
check_privilege();
if (priority > 077 || priority < 000)
return E_Arg;
if (LockSemaphore(&sys_sema,-1)) {
t = &tcbs[ht];
if (t->status & (TS_RUNNING | TS_READY)) {
RemoveFromReadyList(ht);
t->priority = priority;
InsertIntoReadyList(ht);
}
else
t->priority = priority;
UnlockSemaphore(&sys_sema);
}
return E_Ok;
}
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
void FMTKInitialize()
{
int nn,jj;
 
check_privilege();
// firstcall
{
asm {
ldi r1,#20
sc r1,hs:LEDS
}
hasUltraHighPriorityTasks = 0;
missed_ticks = 0;
 
IOFocusTbl[0] = 0;
IOFocusNdx = null;
iof_switch = 0;
 
SetRunningTCB(0);
tcbs[0].hJob = 0;
UnlockSemaphore(&sys_sema);
UnlockSemaphore(&iof_sema);
UnlockSemaphore(&kbd_sema);
 
for (nn = 0; nn < NR_MSG; nn++) {
message[nn].link = nn+1;
}
message[NR_MSG-1].link = -1;
freeMSG = 0;
 
asm {
ldi r1,#30
sc r1,hs:LEDS
}
 
for (nn = 0; nn < NR_JCB; nn++) {
jcbs[nn].number = nn;
for (jj = 0; jj < 8; jj++)
jcbs[nn].tasks[jj] = -1;
if (nn == 0 ) {
jcbs[nn].pVidMem = 0xFFD00000;
jcbs[nn].pVirtVidMem = &video_bufs[nn];
jcbs[nn].NormAttr = 0x0026B800;
asm {
ldi r1,#31
sc r1,hs:LEDS
}
RequestIOFocus(&jcbs[0]);
asm {
ldi r1,#34
sc r1,hs:LEDS
}
}
else {
jcbs[nn].pVidMem = &video_bufs[nn];
jcbs[nn].pVirtVidMem = &video_bufs[nn];
jcbs[nn].NormAttr = 0x0026B800;
}
asm {
ldi r1,#35
sc r1,hs:LEDS
}
jcbs[nn].VideoRows = 31;
jcbs[nn].VideoCols = 84;
jcbs[nn].CursorRow = 0;
jcbs[nn].CursorCol = 0;
jcbs[nn].KeybdHead = 0;
jcbs[nn].KeybdTail = 0;
jcbs[nn].KeyState1 = 0;
jcbs[nn].KeyState2 = 0;
jcbs[nn].KeybdBufSz = 64;
}
 
ClearScreen();
HomeCursor();
printf("FMTK Initializing");
 
asm {
ldi r1,#40
sc r1,hs:LEDS
}
 
for (nn = 0; nn < 8; nn++)
readyQ[nn] = -1;
for (nn = 0; nn < NR_TCB; nn++) {
tcbs[nn].number = nn;
tcbs[nn].next = nn+1;
tcbs[nn].prev = -1;
asm {
ldi r1,#41
sc r1,hs:LEDS
}
 
tcbs[nn].status = 0;
tcbs[nn].priority = 070;
tcbs[nn].affinity = 0;
asm {
ldi r1,#46
sc r1,hs:LEDS
}
 
tcbs[nn].sys_stack = &sys_stacks[nn] + 511;
tcbs[nn].bios_stack = &bios_stacks[nn] + 511;
asm {
ldi r1,#42
sc r1,hs:LEDS
}
 
tcbs[nn].stack = &stacks[nn] + 1023;
tcbs[nn].hJob = 0;
tcbs[nn].timeout = 0;
asm {
ldi r1,#43
sc r1,hs:LEDS
}
 
tcbs[nn].hMailboxes[0] = -1;
tcbs[nn].hMailboxes[1] = -1;
tcbs[nn].hMailboxes[2] = -1;
tcbs[nn].hMailboxes[3] = -1;
asm {
ldi r1,#44
sc r1,hs:LEDS
}
 
if (nn<2) {
tcbs[nn].affinity = nn;
tcbs[nn].priority = 030;
}
tcbs[nn].exception = 0;
asm {
ldi r1,#47
sc r1,hs:LEDS
}
 
}
tcbs[NR_TCB-1].next = -1;
freeTCB = 2;
asm {
ldi r1,#48
sc r1,hs:LEDS
}
InsertIntoReadyList(0);
InsertIntoReadyList(1);
tcbs[0].status = TS_RUNNING;
tcbs[1].status = TS_RUNNING;
asm {
ldi r1,#49
sc r1,hs:LEDS
}
SetRunningTCB(0);
TimeoutList = -1;
set_vector(4,FMTK_SystemCall);
set_vector(2,FMTK_SchedulerIRQ2);
set_vector(194,FMTK_SchedulerIRQ);
set_vector(195,KeybdIRQ);
asm {
ldi r1,#50
sc r1,hs:LEDS
}
FMTK_StartTask(030, 0, FocusSwitcher, 0, 0);
asm {
ldi r1,#55
sc r1,hs:LEDS
}
FMTK_StartTask(033, 0, shell, 0, 1);
asm {
ldi r1,#52
sc r1,hs:LEDS
}
// FMTK_StartTask(055, 0, gfx_demo, 0, 1);
FMTK_StartTask(077, 0, IdleTask, 0, 0);
asm {
ldi r1,#53
sc r1,hs:LEDS
}
// FMTK_StartTask(077, 1, IdleTask, 0, 0);
FMTK_Inited = 0x12345678;
asm {
ldi r1,#56
sc r1,hs:LEDS
}
}
}
 
/thor/trunk/software/FMTK/source/kernel/kernel.h
0,0 → 1,77
// error codes
#define E_Ok 0x00
#define E_Arg 0x01
#define E_BadMbx 0x04
#define E_QueFull 0x05
#define E_NoThread 0x06
#define E_NotAlloc 0x09
#define E_NoMsg 0x0b
#define E_Timeout 0x10
// resource errors
#define E_NoMoreMbx 0x40
#define E_NoMoreMsgBlks 0x41
#define E_NoMoreAlarmBlks 0x44
#define E_NoMoreTCBs 0x45
 
#define E_BadCallGate 0x49 // tried to call uninitialize gate
 
#define E_BadDMAChannel 0x400
#define E_DMABoundary 0x402 // transfer will cross 64/128k
#define E_BadDMAAddr 0x403 // address over 16M limit
 
#define OSCodeSel 8
#define DataSel
 
// task status
#define TS_TIMEOUT 0
#define TS_WAITMSG 1
#define TS_PREEMP 2
#define TS_RUNNING 4
#define TS_READY 8
 
// message queuing strategy
#define MQS_UNLIMITED 0 // unlimited queue size
#define MQS_NEWEST 1 // buffer queue size newest messages
#define MQS_OLDEST 2 // buffer queue size oldest messages
 
// message block type
#define MBT_DATA 0
 
// alarm constants
#define ALM_FOREVER -1 // repeat forever code
 
#define MAX_UINT -1
 
 
typedef struct tagMSG {
struct tagMSG *link;
uint d1;
uint d2;
byte type;
byte resv[3];
} MSG;
 
typedef struct tagMBX {
TCB *tq_head;
TCB *tq_tail;
MSG *mq_head;
MSG *mq_tail;
uint tq_count;
uint mq_size;
uint mq_count;
uint mq_missed;
uint owner; // hJcb of owner
char mq_strategy;
byte resv[3]; // padding to 32 bytes
} MBX;
 
typedef struct tagALARM {
ALARM *next;
ALARM *prev;
MBX *mbx;
MSG *msg;
uint BaseTimeout;
uint timeout;
uint repeat;
byte resv[4]; // padding to 32 bytes
} ALARM;
/thor/trunk/software/FMTK/source/kernel/glo.h
0,0 → 1,36
#ifndef GLO_H
#define GLO_H
 
extern int irq_stack[];
extern int FMTK_Inited;
extern JCB jcbs[NR_JCB];
extern TCB tcbs[NR_TCB];
extern hTCB readyQ[];
extern hTCB freeTCB;
extern int sysstack[1024];
extern int stacks[NR_TCB][1024];
extern int sys_stacks[NR_TCB][512];
extern int bios_stacks[NR_TCB][512];
extern int fmtk_irq_stack[512];
extern int fmtk_sys_stack[512];
extern MBX mailbox[NR_MBX];
extern MSG message[NR_MSG];
extern int nMsgBlk;
extern int nMailbox;
extern hMSG freeMSG;
extern hMBX freeMBX;
extern JCB *IOFocusNdx;
extern int IOFocusTbl[];
extern int iof_switch;
extern int BIOS1_sema;
extern int iof_sema;
extern int sys_sema;
extern int kbd_sema;
extern int BIOS_RespMbx;
extern char hasUltraHighPriorityTasks;
extern int missed_ticks;
extern short int video_bufs[51][4096];
extern hTCB TimeoutList;
extern hMBX hFocusSwitchMbx;
 
#endif
/thor/trunk/software/FMTK/source/kernel/FMTKmsg.c
0,0 → 1,600
#include "types.h"
#include "const.h"
#include "config.h"
#include "proto.h"
#include "glo.h"
 
extern int sys_sema;
 
/* ---------------------------------------------------------------
Description:
Queue a message at a mailbox.
 
Assumptions:
valid mailbox parameter.
 
Called from:
SendMsg
PostMsg
--------------------------------------------------------------- */
private pascal int QueueMsg(MBX *mbx, MSG *msg)
{
MSG *tmpmsg;
hMSG htmp;
int rr = E_Ok;
 
if (LockSemaphore(&sys_sema,-1)) {
mbx->mq_count++;
// handle potential queue overflows
switch (mbx->mq_strategy) {
// unlimited queing (do nothing)
case MQS_UNLIMITED:
break;
// buffer newest
// if the queue is full then old messages are lost
// Older messages are at the head of the queue.
// loop incase message queing strategy was changed
case MQS_NEWEST:
while (mbx->mq_count > mbx->mq_size) {
// return outdated message to message pool
htmp = message[mbx->mq_head].link;
tmpmsg = &message[htmp];
message[mbx->mq_head].link = freeMSG;
freeMSG = mbx->mq_head;
nMsgBlk++;
mbx->mq_count--;
mbx->mq_head = htmp;
if (mbx->mq_missed < MAX_UINT)
mbx->mq_missed++;
rr = E_QueFull;
}
break;
// buffer oldest
// if the queue is full then new messages are lost
// loop incase message queing strategy was changed
case MQS_OLDEST:
// first return the passed message to free pool
if (mbx->mq_count > mbx->mq_size) {
// return new message to pool
msg->link = freeMSG;
freeMSG = msg-message;
nMsgBlk++;
if (mbx->mq_missed < MAX_UINT)
mbx->mq_missed++;
rr = E_QueFull;
mbx->mq_count--;
}
// next if still over the message limit (which
// might happen if que strategy was changed), return
// messages to free pool
while (mbx->mq_count > mbx->mq_size) {
// locate the second last message on the que
tmpmsg = &message[mbx->mq_head];
while (tmpmsg-message <> mbx->mq_tail) {
msg = tmpmsg;
tmpmsg = &message[tmpmsg->link];
}
mbx->mq_tail = msg-message;
tmpmsg->link = freeMSG;
freeMSG = tmpmsg-message;
nMsgBlk++;
if (mbx->mq_missed < MAX_UINT)
mbx->mq_missed++;
mbx->mq_count--;
rr = E_QueFull;
}
if (rr == E_QueFull) {
UnlockSemaphore(&sys_sema);
return rr;
}
break;
}
// if there is a message in the queue
if (mbx->mq_tail >= 0)
message[mbx->mq_tail].link = msg-message;
else
mbx->mq_head = msg-message;
mbx->mq_tail = msg-message;
msg->link = -1;
UnlockSemaphore(&sys_sema);
}
return rr;
}
 
 
/* ---------------------------------------------------------------
Description:
Dequeues a message from a mailbox.
 
Assumptions:
Mailbox parameter is valid.
System semaphore is locked already.
 
Called from:
FreeMbx - (locks mailbox)
WaitMsg - "
CheckMsg- "
--------------------------------------------------------------- */
 
private pascal MSG *DequeueMsg(MBX *mbx)
{
MSG *tmpmsg = null;
hMSG hm;
if (mbx->mq_count) {
mbx->mq_count--;
hm = mbx->mq_head;
if (hm >= 0) { // should not be null
tmpmsg = &message[hm];
mbx->mq_head = tmpmsg->link;
if (mbx->mq_head < 0)
mbx->mq_tail = -1;
tmpmsg->link = hm;
}
}
return tmpmsg;
}
 
 
/* ---------------------------------------------------------------
Description:
Dequeues a thread from a mailbox. The thread will also
be removed from the timeout list (if it's present there),
and the timeout list will be adjusted accordingly.
 
Assumptions:
Mailbox parameter is valid.
--------------------------------------------------------------- */
 
private int DequeThreadFromMbx(MBX *mbx, TCB **thrd)
{
if (thrd == null || mbx == null)
return E_Arg;
 
if (LockSemaphore(&sys_sema,-1)) {
if (mbx->tq_head == -1) {
UnlockSemaphore(&sys_sema);
*thrd = null;
return E_NoThread;
}
mbx->tq_count--;
*thrd = &tcbs[mbx->tq_head];
mbx->tq_head = tcbs[mbx->tq_head].mbq_next;
if (mbx->tq_head > 0)
tcbs[mbx->tq_head].mbq_prev = -1;
else
mbx->tq_tail = -1;
UnlockSemaphore(&sys_sema);
}
 
// if thread is also on the timeout list then
// remove from timeout list
// adjust succeeding thread timeout if present
if ((*thrd)->status & TS_TIMEOUT)
RemoveFromTimeoutList(*thrd);
 
(*thrd)->mbq_prev = (*thrd)->mbq_next = -1;
(*thrd)->hWaitMbx = -1; // no longer waiting at mailbox
(*thrd)->status &= ~TS_WAITMSG;
return E_Ok;
 
}
 
 
/* ---------------------------------------------------------------
Description:
Allocate a mailbox. The default queue strategy is to
queue the eight most recent messages.
--------------------------------------------------------------- */
public int FMTK_AllocMbx(hMBX *phMbx)
{
MBX *mbx;
 
check_privilege();
if (phMbx==null)
return E_Arg;
if (LockSemaphore(&sys_sema,-1)) {
if (freeMBX < 0 || freeMBX >= NR_MBX) {
UnlockSemaphore(&sys_sema);
return E_NoMoreMbx;
}
mbx = &mailbox[freeMBX];
freeMBX = mbx->link;
nMailbox--;
UnlockSemaphore(&sys_sema);
}
*phMbx = mbx - mailbox;
mbx->owner = GetJCBPtr();
mbx->tq_head = -1;
mbx->tq_tail = -1;
mbx->mq_head = -1;
mbx->mq_tail = -1;
mbx->tq_count = 0;
mbx->mq_count = 0;
mbx->mq_missed = 0;
mbx->mq_size = 8;
mbx->mq_strategy = MQS_NEWEST;
return E_Ok;
}
 
 
/* ---------------------------------------------------------------
Description:
Free up a mailbox. When the mailbox is freed any queued
messages must be freed. Any queued threads must also be
dequeued.
--------------------------------------------------------------- */
public int FMTK_FreeMbx(hMBX hMbx)
{
MBX *mbx;
MSG *msg;
TCB *thrd;
check_privilege();
if (hMbx < 0 || hMbx >= NR_MBX)
return E_BadHandle;
mbx = &mailbox[hMbx];
if (LockSemaphore(&sys_sema,-1)) {
if ((mbx->owner <> GetJCBPtr()) and (GetJCBPtr() <> &jcbs)) {
UnlockSemaphore(&sys_sema);
return E_NotOwner;
}
// Free up any queued messages
while (msg = DequeueMsg(mbx)) {
msg->type = MT_FREE;
msg->retadr = -1;
msg->tgtadr = -1;
msg->link = freeMSG;
freeMSG = msg - message;
nMsgBlk++;
}
// Send an indicator to any queued threads that the mailbox
// is now defunct Setting MsgPtr = null will cause any
// outstanding WaitMsg() to return E_NoMsg.
forever {
DequeThreadFromMbx(mbx, &thrd);
if (thrd == null)
break;
thrd->msg.type = MT_NONE;
if (thrd->status & TS_TIMEOUT)
RemoveFromTimeoutList(thrd-tcbs);
InsertIntoReadyList(thrd-tcbs);
}
mbx->link = freeMBX;
freeMBX = mbx-mailbox;
nMailbox++;
UnlockSemaphore(&sys_sema);
}
return E_Ok;
}
 
 
/* ---------------------------------------------------------------
Description:
Set the mailbox message queueing strategy.
--------------------------------------------------------------- */
public int SetMbxMsgQueStrategy(hMBX hMbx, int qStrategy, int qSize)
{
MBX *mbx;
 
check_privilege();
if (hMbx < 0 || hMbx >= NR_MBX)
return E_BadHandle;
if (qStrategy > 2)
return E_Arg;
mbx = &mailbox[hMbx];
if (LockSemaphore(&sys_sema,-1)) {
if ((mbx->owner <> GetJCBPtr()) and GetJCBPtr() <> &jcbs[0]) {
UnlockSemaphore(&sys_sema);
return E_NotOwner;
}
mbx->mq_strategy = qStrategy;
mbx->mq_size = qSize;
UnlockSemaphore(&sys_sema);
}
return E_Ok;
}
 
 
/* ---------------------------------------------------------------
Description:
Send a message.
--------------------------------------------------------------- */
public int FMTK_SendMsg(hMBX hMbx, int d1, int d2, int d3)
{
MBX *mbx;
MSG *msg;
TCB *thrd;
 
check_privilege();
if (hMbx < 0 || hMbx >= NR_MBX)
return E_BadHandle;
mbx = &mailbox[hMbx];
if (LockSemaphore(&sys_sema,-1)) {
// check for a mailbox owner which indicates the mailbox
// is active.
if (mbx->owner < 0 || mbx->owner >= NR_JCB) {
UnlockSemaphore(&sys_sema);
return E_NotAlloc;
}
if (freeMSG < 0 || freeMSG >= NR_MSG) {
UnlockSemaphore(&sys_sema);
return E_NoMoreMsgBlks;
}
msg = &message[freeMSG];
freeMSG = msg->link;
--nMsgBlk;
msg->retadr = GetJCBPtr()-jcbs;
msg->tgtadr = hMbx;
msg->type = MBT_DATA;
msg->d1 = d1;
msg->d2 = d2;
msg->d3 = d3;
DequeThreadFromMbx(mbx, &thrd);
UnlockSemaphore(&sys_sema);
}
if (thrd == null)
return QueueMsg(mbx, msg);
if (LockSemaphore(&sys_sema,-1)) {
thrd->msg.retadr = msg->retadr;
thrd->msg.tgtadr = msg->tgtadr;
thrd->msg.type = msg->type;
thrd->msg.d1 = msg->d1;
thrd->msg.d2 = msg->d2;
thrd->msg.d3 = msg->d3;
// free message here
msg->type = MT_FREE;
msg->retadr = -1;
msg->tgtadr = -1;
msg->link = freeMSG;
freeMSG = msg-message;
if (thrd->status & TS_TIMEOUT)
RemoveFromTimeoutList(thrd-tcbs);
InsertIntoReadyList(thrd-tcbs);
UnlockSemaphore(&sys_sema);
}
return E_Ok;
}
 
 
/* ---------------------------------------------------------------
Description:
PostMsg() is meant to be called in order to send a
message without causing the thread to switch. This is
useful in some cases. For example interrupts that don't
require a low latency. Normally SendMsg() will be called,
even from an ISR to allow the OS to prioritize events.
--------------------------------------------------------------- */
public int FMTK_PostMsg(hMBX hMbx, int d1, int d2, int d3)
{
MBX *mbx;
MSG *msg;
TCB *thrd;
int ret;
 
check_privilege();
if (hMbx < 0 || hMbx >= NR_MBX)
return E_BadHandle;
mbx = &mailbox[hMbx];
if (LockSemaphore(&sys_sema,-1)) {
// check for a mailbox owner which indicates the mailbox
// is active.
if (mbx->owner < 0 || mbx->owner >= NR_JCB) {
UnlockSemaphore(&sys_sema);
return E_NotAlloc;
}
if (freeMSG <0 || freeMSG >= NR_MSG) {
UnlockSemaphore(&sys_sema);
return E_NoMoreMsgBlks;
}
msg = &message[freeMSG];
freeMSG = msg->link;
--nMsgBlk;
msg->retadr = GetJCBPtr()-jcbs;
msg->tgtadr = hMbx;
msg->type = MBT_DATA;
msg->d1 = d1;
msg->d2 = d2;
msg->d3 = d3;
DequeThreadFromMbx(mbx, &thrd);
UnlockSemaphore(&sys_sema);
}
if (thrd == null) {
ret = QueueMsg(mbx, msg);
return ret;
}
if (LockSemaphore(&sys_sema,-1)) {
thrd->msg.retadr = msg->retadr;
thrd->msg.tgtadr = msg->tgtadr;
thrd->msg.type = msg->type;
thrd->msg.d1 = msg->d1;
thrd->msg.d2 = msg->d2;
thrd->msg.d3 = msg->d3;
// free message here
msg->type = MT_FREE;
msg->retadr = -1;
msg->tgtadr = -1;
msg->link = freeMSG;
freeMSG = msg-message;
if (thrd->status & TS_TIMEOUT)
RemoveFromTimeoutList(thrd-tcbs);
InsertIntoReadyList(thrd-tcbs);
UnlockSemaphore(&sys_sema);
}
return E_Ok;
}
 
 
/* ---------------------------------------------------------------
Description:
Wait for message. If timelimit is zero then the thread
will wait indefinately for a message.
--------------------------------------------------------------- */
 
public int FMTK_WaitMsg(hMBX hMbx, int *d1, int *d2, int *d3, int timelimit)
{
MBX *mbx;
MSG *msg;
TCB *thrd;
TCB *rt;
 
check_privilege();
if (hMbx < 0 || hMbx >= NR_MBX)
return E_BadHandle;
mbx = &mailbox[hMbx];
if (LockSemaphore(&sys_sema,-1)) {
// check for a mailbox owner which indicates the mailbox
// is active.
if (mbx->owner <0 || mbx->owner >= NR_JCB) {
UnlockSemaphore(&sys_sema);
return E_NotAlloc;
}
msg = DequeueMsg(mbx);
UnlockSemaphore(&sys_sema);
}
if (msg == null) {
if (LockSemaphore(&sys_sema,-1)) {
thrd = GetRunningTCBPtr();
RemoveFromReadyList(thrd-tcbs);
UnlockSemaphore(&sys_sema);
}
//-----------------------
// Queue task at mailbox
//-----------------------
thrd->status |= TS_WAITMSG;
thrd->hWaitMbx = hMbx;
thrd->mbq_next = -1;
if (LockSemaphore(&sys_sema,-1)) {
if (mbx->tq_head < 0) {
thrd->mbq_prev = -1;
mbx->tq_head = thrd-tcbs;
mbx->tq_tail = thrd-tcbs;
mbx->tq_count = 1;
}
else {
thrd->mbq_prev = mbx->tq_tail;
tcbs[mbx->tq_tail].mbq_next = thrd-tcbs;
mbx->tq_tail = thrd-tcbs;
mbx->tq_count++;
}
UnlockSemaphore(&sys_sema);
}
//---------------------------
// Is a timeout specified ?
if (timelimit) {
asm { ; Waitmsg here; }
if (LockSemaphore(&sys_sema,-1)) {
InsertIntoTimeoutList(thrd-tcbs, timelimit);
UnlockSemaphore(&sys_sema);
}
}
asm { int #2 } // reschedule
// Control will return here as a result of a SendMsg or a
// timeout expiring
rt = GetRunningTCBPtr();
if (rt->msg.type == MT_NONE)
return E_NoMsg;
// rip up the envelope
rt->msg.type = MT_NONE;
rt->msg.tgtadr = -1;
rt->msg.retadr = -1;
if (d1)
*d1 = rt->msg.d1;
if (d2)
*d2 = rt->msg.d2;
if (d3)
*d3 = rt->msg.d3;
return E_Ok;
}
//-----------------------------------------------------
// We get here if there was initially a message
// available in the mailbox, or a message was made
// available after a task switch.
//-----------------------------------------------------
if (d1)
*d1 = msg->d1;
if (d2)
*d2 = msg->d2;
if (d3)
*d3 = msg->d3;
if (LockSemaphore(&sys_sema,-1)) {
msg->type = MT_FREE;
msg->retadr = -1;
msg->tgtadr = -1;
msg->link = freeMSG;
freeMSG = msg-message;
nMsgBlk++;
UnlockSemaphore(&sys_sema);
}
return E_Ok;
}
 
// ----------------------------------------------------------------------------
// PeekMsg()
// Look for a message in the queue but don't remove it from the queue.
// This is a convenince wrapper for CheckMsg().
// ----------------------------------------------------------------------------
 
int FMTK_PeekMsg(uint hMbx, int *d1, int *d2, int *d3)
{
return CheckMsg(hMbx, d1, d2, d3, 0);
}
 
/* ---------------------------------------------------------------
Description:
Check for message at mailbox. If no message is
available return immediately to the caller (CheckMsg() is
non blocking). Optionally removes the message from the
mailbox.
--------------------------------------------------------------- */
 
int FMTK_CheckMsg(hMBX hMbx, int *d1, int *d2, int *d3, int qrmv)
{
MBX *mbx;
MSG *msg;
 
check_privilege();
if (hMbx < 0 || hMbx >= NR_MBX)
return E_BadHandle;
mbx = &mailbox[hMbx];
if (LockSemaphore(&sys_sema,-1)) {
// check for a mailbox owner which indicates the mailbox
// is active.
if (mbx->owner == null) {
UnlockSemaphore(&sys_sema);
return E_NotAlloc;
}
if (qrmv == true)
msg = DequeueMsg(mbx);
else
msg = mbx->mq_head;
UnlockSemaphore(&sys_sema);
}
if (msg == null)
return E_NoMsg;
if (d1)
*d1 = msg->d1;
if (d2)
*d2 = msg->d2;
if (d3)
*d3 = msg->d3;
if (qrmv == true) {
if (LockSemaphore(&sys_sema,-1)) {
msg->type = MT_FREE;
msg->retadr = -1;
msg->tgtadr = -1;
msg->link = freeMSG;
freeMSG = msg-message;
nMsgBlk++;
UnlockSemaphore(&sys_sema);
}
}
return E_Ok;
}
 
 
/thor/trunk/software/FMTK/source/kernel/TCB.c
0,0 → 1,283
// ============================================================================
// __
// \\__/ o\ (C) 2012-2015 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// TCB.c
// Task Control Block related functions.
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ============================================================================
//
#include "config.h"
#include "const.h"
#include "types.h"
#include "proto.h"
 
extern char hasUltraHighPriorityTasks;
extern pascal prtdbl(double);
 
TCB tcbs[NR_TCB];
hTCB freeTCB;
hTCB TimeoutList;
hTCB readyQ[8];
 
 
pascal int chkTCB(TCB *p)
{
asm {
lw r1,32[bp]
//chk r1,r1,b48
}
}
 
naked TCB *GetRunningTCBPtr()
{
asm {
mov r1,tr
rts
}
}
 
naked hTCB GetRunningTCB()
{
asm {
subui r1,tr,#tcbs_
shrui r1,r1,#12
rts
}
}
 
pascal void SetRunningTCB(hTCB ht)
{
asm {
lw tr,32[bp]
shli tr,tr,#12
addui tr,tr,#tcbs_
}
}
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
pascal int InsertIntoReadyList(hTCB ht)
{
hTCB hq;
TCB *p, *q;
 
asm {
ldi r1,#70
sc r1,hs:LEDS
}
if (ht < 0 || ht >= NR_TCB)
throw E_BadHandle;
p = &tcbs[ht];
if (p->priority > 077 || p->priority < 000)
throw E_BadPriority;
asm {
ldi r1,#71
sc r1,hs:LEDS
}
if (p->priority < 003)
hasUltraHighPriorityTasks |= (1 << p->priority);
p->status = TS_READY;
hq = readyQ[p->priority>>3];
asm {
ldi r1,#72
sc r1,hs:LEDS
}
// Ready list empty ?
if (hq<0) {
p->next = ht;
p->prev = ht;
readyQ[p->priority>>3] = ht;
return E_Ok;
}
asm {
ldi r1,#75
sc r1,hs:LEDS
}
// Insert at tail of list
q = &tcbs[hq];
p->next = hq;
p->prev = q->prev;
tcbs[q->prev].next = ht;
q->prev = ht;
asm {
ldi r1,#77
sc r1,hs:LEDS
}
return E_Ok;
}
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
pascal int RemoveFromReadyList(hTCB ht)
{
TCB *t;
 
if (ht < 0 || ht >= NR_TCB)
throw E_BadHandle;
t = &tcbs[ht];
if (t->priority > 077 || t->priority < 000)
throw E_BadPriority;
if (ht==readyQ[t->priority>>3])
readyQ[t->priority>>3] = t->next;
if (ht==readyQ[t->priority>>3])
readyQ[t->priority>>3] = -1;
tcbs[t->next].prev = t->prev;
tcbs[t->prev].next = t->next;
t->next = -1;
t->prev = -1;
t->status = TS_NONE;
return E_Ok;
}
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
pascal int InsertIntoTimeoutList(hTCB ht, int to)
{
TCB *p, *q, *t;
 
if (ht < 0 || ht >= NR_TCB)
throw E_BadHandle;
t = &tcbs[ht];
if (TimeoutList<0) {
t->timeout = to;
TimeoutList = ht;
t->next = -1;
t->prev = -1;
return E_Ok;
}
 
q = null;
p = &tcbs[TimeoutList];
 
while (to > p->timeout) {
 
to -= p->timeout;
q = p;
p = &tcbs[p->next];
 
}
 
t->next = p - tcbs;
t->prev = q - tcbs;
if (p) {
p->timeout -= to;
p->prev = ht;
}
if (q)
q->next = ht;
else
TimeoutList = ht;
t->status |= TS_TIMEOUT;
return E_Ok;
 
};
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
pascal int RemoveFromTimeoutList(hTCB ht)
{
TCB *t;
if (ht < 0 || ht >= NR_TCB)
throw E_BadHandle;
t = &tcbs[ht];
if (t->next) {
tcbs[t->next].prev = t->prev;
tcbs[t->next].timeout += t->timeout;
}
if (t->prev >= 0)
tcbs[t->prev].next = t->next;
t->status = TS_NONE;
t->next = -1;
t->prev = -1;
}
 
// ----------------------------------------------------------------------------
// Pop the top entry from the timeout list.
// ----------------------------------------------------------------------------
 
hTCB PopTimeoutList()
{
TCB *p;
hTCB h;
 
h = TimeoutList;
if (TimeoutList >= 0 && TimeoutList < NR_TCB) {
TimeoutList = tcbs[TimeoutList].next;
if (TimeoutList >= 0 && TimeoutList < NR_TCB)
tcbs[TimeoutList].prev = -1;
}
return h;
}
 
 
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
 
void DumpTaskList()
{
TCB *p, *q;
int n;
int kk;
hTCB h, j;
// printf("pi is ");
// prtdbl(3.141592653589793238,10,6,'E');
printf("CPU Pri Stat Task Prev Next Timeout\r\n");
for (n = 0; n < 8; n++) {
h = readyQ[n];
if (h >= 0 && h < NR_TCB) {
q = &tcbs[h];
p = q;
kk = 0;
do {
// if (!chkTCB(p)) {
// printf("Bad TCB (%X)\r\n", p);
// break;
// }
j = p - tcbs;
printf("%3d %3d %02X %04X %04X %04X %08X %08X\r\n", p->affinity, p->priority, p->status, (int)j, p->prev, p->next, p->timeout, p->ticks);
if (p->next < 0 || p->next >= NR_TCB)
break;
p = &tcbs[p->next];
if (getcharNoWait()==3)
goto j1;
kk = kk + 1;
} while (p != q && kk < 10);
}
}
printf("Waiting tasks\r\n");
h = TimeoutList;
while (h >= 0 && h < NR_TCB) {
p = &tcbs[h];
printf("%3d %3d %02X %04X %04X %04X %08X %08X\r\n", p->affinity, p->priority, p->status, (int)j, p->prev, p->next, p->timeout, p->ticks);
h = p->next;
if (getcharNoWait()==3)
goto j1;
}
j1: ;
}
 
 
/thor/trunk/software/FMTK/source/kernel/types.h
0,0 → 1,113
#ifndef TYPES_H
#define TYPES_H
 
typedef unsigned int uint;
typedef __int16 hTCB;
typedef __int8 hJCB;
typedef __int16 hMBX;
typedef __int16 hMSG;
 
typedef struct tagMSG align(32) {
unsigned __int16 link;
unsigned __int16 retadr; // return address
unsigned __int16 tgtadr; // target address
unsigned __int16 type;
unsigned int d1; // payload data 1
unsigned int d2; // payload data 2
unsigned int d3; // payload data 3
} MSG;
 
typedef struct _tagJCB align(2048)
{
struct _tagJCB *iof_next;
struct _tagJCB *iof_prev;
char UserName[32];
char path[256];
char exitRunFile[256];
char commandLine[256];
unsigned __int32 *pVidMem;
unsigned __int32 *pVirtVidMem;
unsigned __int16 VideoRows;
unsigned __int16 VideoCols;
unsigned __int16 CursorRow;
unsigned __int16 CursorCol;
unsigned __int32 NormAttr;
__int8 KeyState1;
__int8 KeyState2;
__int8 KeybdWaitFlag;
__int8 KeybdHead;
__int8 KeybdTail;
__int8 KeybdBufSz;
unsigned __int8 KeybdBuf[64];
hJCB number;
hTCB tasks[8];
hJCB next;
} JCB;
 
struct tagMBX;
 
typedef struct _tagTCB align(4096) {
// exception storage area
int regs[64];
int cregs[16];
int sregs[8];
int sregs_lmt[8];
int pregs;
// interrupt storage
int iregs[64];
int icregs[16];
int isregs[8];
int isregs_lmt[8];
int ipregs;
 
int resv[62];
 
hTCB next;
hTCB prev;
hTCB mbq_next;
hTCB mbq_prev;
int *sys_stack;
int *bios_stack;
int *stack;
__int64 timeout;
MSG msg;
hMBX hMailboxes[4]; // handles of mailboxes owned by task
hMBX hWaitMbx; // handle of mailbox task is waiting at
hTCB number;
__int8 priority;
__int8 status;
__int8 affinity;
hJCB hJob;
__int64 startTick;
__int64 endTick;
__int64 ticks;
int exception;
} TCB;
 
typedef struct tagMBX align(64) {
hMBX link;
hJCB owner; // hJcb of owner
hTCB tq_head;
hTCB tq_tail;
hMSG mq_head;
hMSG mq_tail;
char mq_strategy;
byte resv[2];
uint tq_count;
uint mq_size;
uint mq_count;
uint mq_missed;
} MBX;
 
typedef struct tagALARM {
struct tagALARM *next;
struct tagALARM *prev;
MBX *mbx;
MSG *msg;
uint BaseTimeout;
uint timeout;
uint repeat;
byte resv[8]; // padding to 64 bytes
} ALARM;
 
#endif
/thor/trunk/software/FMTK/source/kernel/IOFocusc.c
0,0 → 1,168
#include "types.h"
#include "proto.h"
 
extern JCB *IOFocusNdx;
extern int IOFocusTbl[4];
extern int iof_sema;
 
hMBX hFocusSwitchMbx = -1;
 
void FocusSwitcher()
{
int d1,d2,d3;
 
if firstcall {
FMTK_AllocMbx(&hFocusSwitchMbx);
}
forever {
FMTK_WaitMsg(hFocusSwitchMbx, &d1, &d2, &d3, 0x7FFFFFFFFFFFFFFFL);
SwitchIOFocus();
}
}
 
 
void ForceIOFocus(JCB *j)
{
RequestIOFocus(j); // In case it isn't requested yet.
if (LockSemaphore(&iof_sema,-1)) {
if (j != IOFocusNdx) {
CopyScreenToVirtualScreen();
j->pVidMem = j->pVirtVidMem;
IOFocusNdx = j;
j->pVidMem = 0xFFD00000;
CopyVirtualScreenToScreen();
}
UnlockSemaphore(&iof_sema);
}
}
 
 
// First check if it's even possible to switch the focus to another
// task. The I/O focus list could be empty or there may be only a
// single task in the list. In either case it's not possible to
// switch.
void SwitchIOFocus()
{
JCB *j, *p;
 
if (LockSemaphore(&iof_sema,-1)) {
j = IOFocusNdx;
if (j) {
p = IOFocusNdx->iof_next;
if (p <> IOFocusNdx) {
if (p) {
CopyScreenToVirtualScreen();
j->pVidMem = j->pVirtVidMem;
IOFocusNdx = p;
p->pVidMem = 0xFFD00000;
CopyVirtualScreenToScreen();
}
}
}
UnlockSemaphore(&iof_sema);
}
}
 
//-----------------------------------------------------------------------------
// The I/O focus list is an array indicating which jobs are requesting the
// I/O focus. The I/O focus is user controlled by pressing ALT-TAB on the
// keyboard.
//-----------------------------------------------------------------------------
 
void RequestIOFocus(JCB *j)
{
int nj;
int stat;
 
nj = j->number;
if (LockSemaphore(&iof_sema,-1)) {
stat = (IOFocusTbl[0] >> nj) & 1;
if (!stat) {
if (IOFocusNdx==null) {
IOFocusNdx = j;
j->iof_next = j;
j->iof_prev = j;
}
else {
j->iof_prev = IOFocusNdx->iof_prev;
j->iof_next = IOFocusNdx;
IOFocusNdx->iof_prev->iof_next = j;
IOFocusNdx->iof_prev = j;
}
IOFocusTbl[0] |= (1 << nj);
}
UnlockSemaphore(&iof_sema);
}
}
//-----------------------------------------------------------------------------
// Release the IO focus for the current job.
//-----------------------------------------------------------------------------
void ReleaseIOFocus()
{
ForceReleaseIOFocus(GetJCBPtr());
}
 
//-----------------------------------------------------------------------------
// Releasing the I/O focus causes the focus to switch if the running job
// had the I/O focus.
// ForceReleaseIOFocus forces the release of the IO focus for a job
// different than the one currently running.
//-----------------------------------------------------------------------------
 
void ForceReleaseIOFocus(JCB * j)
{
JCB *p;
if (LockSemaphore(&iof_sema,-1)) {
if (IOFocusTbl[0] & (1 << (int)j->number)) {
IOFocusTbl[0] &= ~(1 << j->number);
if (j == IOFocusNdx)
SwitchIOFocus();
p = j->iof_next;
if (p) {
if (p <> j) {
p->iof_prev = j->iof_prev;
j->iof_prev->iof_next = p;
}
else {
IOFocusNdx = null;
}
j->iof_next = null;
j->iof_prev = null;
}
}
UnlockSemaphore(&iof_sema);
}
}
 
void CopyVirtualScreenToScreen()
{
short int *p, *q;
JCB *j;
int nn, pos;
 
j = IOFocusNdx;
p = j->pVidMem;
q = j->pVirtVidMem;
nn = j->VideoRows * j->VideoCols;
for (; nn >= 0; nn--)
p[nn] = q[nn];
pos = j->CursorRow * j->VideoCols + j->CursorCol;
SetVideoReg(11,pos);
}
 
void CopyScreenToVirtualScreen()
{
short int *p, *q;
JCB *j;
int nn;
 
j = IOFocusNdx;
p = j->pVidMem;
q = j->pVirtVidMem;
nn = j->VideoRows * j->VideoCols;
for (; nn >= 0; nn--)
q[nn] = p[nn];
}
 
/thor/trunk/software/FMTK/source/kernel/config.h
0,0 → 1,9
#ifndef CONFIG_H
#define CONFIG_H
 
#define NR_JCB 51
#define NR_TCB 256
#define NR_MBX 1024
#define NR_MSG 16384
 
#endif
/thor/trunk/software/FMTK/source/kernel/PIC.c
0,0 → 1,50
 
#define PIC 0xFFDC0FC0
#define PIC_IE 0xFFDC0FC8
#define PIC_ES 0xFFDC0FE0
#define PIC_RSTE 0xFFDC0FE8
 
// ----------------------------------------------------------------------------
// Get the vector base register
// ----------------------------------------------------------------------------
 
unsigned int *GetVBR()
{
asm {
mfspr r1,c12
}
}
 
 
// ----------------------------------------------------------------------------
// Set an IRQ vector
// ----------------------------------------------------------------------------
 
pascal void set_vector(unsigned int vecno, unsigned int rout)
{
if (vecno > 255) return;
if (rout == 0) return;
asm __leafs {
lw r2,32[bp]
lw r1,40[bp]
jsr set_vector
}
// GetVBR()[vecno] = rout;
}
 
// ----------------------------------------------------------------------------
// 0 is highest priority, 15 is lowest
// 0 NMI (parity error)
// 1 1024 Hz timer interrupt
// 2 30Hz timer interrupt
// 3 Keyboard interrupt
// ...
// 15
//
// ----------------------------------------------------------------------------
void InitPIC()
{
outh(PIC_ES, 0x0007); // nmi,timer interrupt(s) are edge sensitive
outh(PIC_IE, 0x000F); //enable keyboard reset, timer interrupts
}
 
/thor/trunk/software/FMTK/source/kernel/const.h
0,0 → 1,61
#ifndef CONST_H
#define CONST_H
 
#define TRUE 1
#define FALSE 0
 
#define null (void *)0
#define MAX_UINT 0xFFFFFFFFFFFFFFFFL
#define TS_NONE 0
#define TS_TIMEOUT 1
#define TS_WAITMSG 2
#define TS_PREEMPT 4
#define TS_RUNNING 8
#define TS_READY 16
#define TS_GIVEAWAY 32
 
#define MQS_UNLIMITED 0
#define MQS_OLDEST 1
#define MQS_NEWEST 2
 
#define MBT_DATA 2
// message types
#define MT_NONE 0 // not a message
#define MT_FREE 1
 
enum {
E_Ok = 0,
E_BadHandle,
E_BadTCBHandle,
E_BadPriority,
E_BadCallno,
E_Arg,
E_BadMbx,
E_QueFull,
E_NoThread,
E_NotAlloc,
E_NoMsg,
E_Timeout,
E_BadAlarm,
E_NotOwner,
E_QueStrategy,
E_DCBInUse,
//; Device driver errors
E_BadDevNum = 0x20,
E_NoDev,
E_BadDevOp,
E_ReadError,
E_WriteError,
E_BadBlockNum,
E_TooManyBlocks,
 
// resource errors
E_NoMoreMbx = 0x40,
E_NoMoreMsgBlks,
E_NoMoreAlarmBlks,
E_NoMoreTCBs,
E_NoMem,
E_TooManyTasks
};
 
#endif
/thor/trunk/software/FMTK/source/kernel/LockSemaphore.c
0,0 → 1,50
// ============================================================================
// __
// \\__/ o\ (C) 2012-2016 Robert Finch, Stratford
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// LockSemaphore.c
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ============================================================================
//
pascal int LockSemaphore(int *sema, int retries)
{
asm {
ldi r1,#1
br .0005
lw r1,32[bp] ; r1 = pointer to semaphore
lw r2,40[bp] ; r2 = #retries
.0001:
tst p0,r2 ; timeout expired ?
p0.eq mov r1,r0 ; if yes, return 0
p0.eq br .0005
subui r2,r2,#1 ; decrement timeout
lvwar r3,[r1] ; load and reserve address
tst p0,r3
p0.lt br .0003 ; branch if free
cmp p0,r3,tr ; test if already locked by this task
p0.eq br .0002
;chk r3,r0,#256 ; check if locked by a valid task
.0003:
swcr tr,[r1] ; try and lock it
p0.ne br .0001 ; lock failed, go try again
.0002:
ldi r1,#1
.0005:
}
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.