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: |
} |
} |