1 |
22 |
dgisselq |
////////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//
|
3 |
|
|
// Filename: kernel.c
|
4 |
|
|
//
|
5 |
|
|
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
|
6 |
|
|
//
|
7 |
|
|
// Purpose: If you are looking for a main() program associated with the
|
8 |
|
|
// ZipOS, this is it. This is the main program for the supervisor
|
9 |
|
|
// task. It handles interrupt processing, creating tasks, context swaps,
|
10 |
|
|
// creating tasks, and ... just about everything else a kernel must handle.
|
11 |
|
|
//
|
12 |
|
|
// Creator: Dan Gisselquist, Ph.D.
|
13 |
|
|
// Gisselquist Technology, LLC
|
14 |
|
|
//
|
15 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
16 |
|
|
//
|
17 |
|
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
18 |
|
|
//
|
19 |
|
|
// This program is free software (firmware): you can redistribute it and/or
|
20 |
|
|
// modify it under the terms of the GNU General Public License as published
|
21 |
|
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
22 |
|
|
// your option) any later version.
|
23 |
|
|
//
|
24 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
25 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
26 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
27 |
|
|
// for more details.
|
28 |
|
|
//
|
29 |
|
|
// You should have received a copy of the GNU General Public License along
|
30 |
|
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
31 |
|
|
// target there if the PDF file isn't present.) If not, see
|
32 |
|
|
// <http://www.gnu.org/licenses/> for a copy.
|
33 |
|
|
//
|
34 |
|
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
35 |
|
|
// http://www.gnu.org/licenses/gpl.html
|
36 |
|
|
//
|
37 |
|
|
//
|
38 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
39 |
|
|
//
|
40 |
|
|
//
|
41 |
|
|
|
42 |
|
|
#include "zipsys.h"
|
43 |
|
|
#include "board.h"
|
44 |
|
|
#include "ksched.h"
|
45 |
|
|
#include "kfildes.h"
|
46 |
|
|
#include "taskp.h"
|
47 |
|
|
#include "syspipe.h"
|
48 |
|
|
#include "ktraps.h"
|
49 |
|
|
#include "errno.h"
|
50 |
|
|
#include "swint.h"
|
51 |
|
|
|
52 |
|
|
extern void kpanic(void);
|
53 |
|
|
extern void raw_put_uart(int val);
|
54 |
|
|
|
55 |
|
|
unsigned int nresets = 0;
|
56 |
|
|
|
57 |
|
|
extern int kntasks(void);
|
58 |
|
|
extern void kinit(TASKP *tasklist);
|
59 |
|
|
extern void restore_context(int *), save_context(int *);
|
60 |
|
|
SYSPIPE *rxpipe, *txpipe, *keypipe, *lcdpipe, *pwmpipe, *cmdpipe;
|
61 |
|
|
KDEVICE *pipedev, *txdev, *pwmdev;
|
62 |
|
|
void *heap; // = _top_of_heap; // Need to wait on startup to set this
|
63 |
|
|
|
64 |
|
|
#define CONTEXT_LENGTH 100000 // 1ms
|
65 |
|
|
#define TICKS_PER_SECOND 1000
|
66 |
|
|
|
67 |
|
|
void kwrite_audio(TASKP tsk, int dev, int *dst, int len);
|
68 |
|
|
void kwrite_txuart(TASKP tsk, int dev, int *dst, int len);
|
69 |
|
|
int kpost(TASKP *task, unsigned events, int milliseconds);
|
70 |
|
|
TASKP kschedule(int LAST_TASK, TASKP *tasklist, TASKP last);
|
71 |
|
|
|
72 |
|
|
int LAST_TASK;
|
73 |
|
|
|
74 |
|
|
void kernel_entry(void) {
|
75 |
|
|
int nheartbeats= 0, tickcount = 0, milliseconds=0, ticks = 0;
|
76 |
|
|
int audiostate = 0;
|
77 |
|
|
TASKP *tasklist, current;
|
78 |
|
|
int *last_context;
|
79 |
|
|
IOSPACE *sys = (IOSPACE *)IOADDR;
|
80 |
|
|
sys->io_spio = 0x0f0;
|
81 |
|
|
sys->io_timb = 0; // Turn off the watchdog timer
|
82 |
|
|
LAST_TASK = kntasks();
|
83 |
|
|
heap = _top_of_heap;
|
84 |
|
|
|
85 |
|
|
pipedev = sys_malloc(sizeof(KDEVICE));
|
86 |
|
|
pipedev->write = (RWFDFUN)kwrite_syspipe;
|
87 |
|
|
pipedev->read = (RWFDFUN)kread_syspipe;
|
88 |
|
|
pipedev->close = NULL;
|
89 |
|
|
|
90 |
|
|
/*
|
91 |
|
|
txdev = sys_malloc(sizeof(KDEVICE));
|
92 |
|
|
txdev->write = (RWFDFUN)kwrite_txuart;
|
93 |
|
|
txdev->read = (RWFDFUN)kread_syspipe;
|
94 |
|
|
txdev->close = NULL;
|
95 |
|
|
|
96 |
|
|
pwmdev = sys_malloc(sizeof(KDEVICE));
|
97 |
|
|
pwmdev->write = (RWFDFUN)kwrite_audio;
|
98 |
|
|
pwmdev->read = (RWFDFUN)kread_syspipe;
|
99 |
|
|
pwmdev->close = NULL;
|
100 |
|
|
*/
|
101 |
|
|
|
102 |
|
|
txdev = pwmdev = pipedev;
|
103 |
|
|
|
104 |
|
|
rxpipe = new_syspipe(16); //rxpipe->m_wrtask=INTERRUPT_WRITE_TASK;
|
105 |
|
|
txpipe = new_syspipe(16); txpipe->m_rdtask = INTERRUPT_READ_TASK;
|
106 |
|
|
keypipe = new_syspipe(16);
|
107 |
|
|
lcdpipe = new_syspipe(16);
|
108 |
|
|
pwmpipe = new_syspipe(256); pwmpipe->m_rdtask= INTERRUPT_READ_TASK;
|
109 |
|
|
cmdpipe = new_syspipe(16);
|
110 |
|
|
|
111 |
|
|
tasklist = sys_malloc(sizeof(TASKP)*(1+LAST_TASK));
|
112 |
|
|
kinit(tasklist);
|
113 |
|
|
tasklist[LAST_TASK] = new_task(2, idle_task);
|
114 |
|
|
|
115 |
|
|
|
116 |
|
|
// current = tasklist[0];
|
117 |
|
|
current = tasklist[LAST_TASK];
|
118 |
|
|
restore_context(current->context);
|
119 |
|
|
last_context = current->context;
|
120 |
|
|
|
121 |
|
|
// Turn all interrupts off, acknowledge all at the same time
|
122 |
|
|
sys->io_pic = 0x7fff7fff;
|
123 |
|
|
unsigned enableset =
|
124 |
|
|
INT_ENABLEV(INT_BUTTON)
|
125 |
|
|
|INT_ENABLEV(INT_TIMA)
|
126 |
|
|
// |INT_ENABLEV(INT_UARTRX)
|
127 |
|
|
// |INT_ENABLEV(INT_UARTTX) // Needs to be turned on by driver
|
128 |
|
|
// |INT_ENABLEV(INT_AUDIO // Needs to be turned on by driver)
|
129 |
|
|
// |INT_ENABLEV(INT_GPIO)
|
130 |
|
|
// |INT_ENABLEV(INT_TIMB);
|
131 |
|
|
;
|
132 |
|
|
// Then selectively turn some of them back on
|
133 |
|
|
sys->io_pic = INT_ENABLE | enableset;
|
134 |
|
|
|
135 |
|
|
sys->io_tima = CONTEXT_LENGTH | TM_REPEAT;
|
136 |
|
|
|
137 |
|
|
sys->io_spio = 0x0f1;
|
138 |
|
|
if (1) {
|
139 |
|
|
// Reset our wishbone scope for debug later
|
140 |
|
|
SCOPE *scope = (SCOPE *)SCOPEADDR;
|
141 |
|
|
scope->s_control = 12;
|
142 |
|
|
}
|
143 |
|
|
|
144 |
|
|
if (0) {
|
145 |
|
|
// Wait on a button press before starting
|
146 |
|
|
while((sys->io_spio & 0x0f0)==0)
|
147 |
|
|
;
|
148 |
|
|
sys->io_spio = 0xf3;
|
149 |
|
|
for(int i=0; i<0x40000; i++)
|
150 |
|
|
sys->io_spio = ((i>>14)&2)|0x20;
|
151 |
|
|
sys->io_spio = 0xf7;
|
152 |
|
|
}
|
153 |
|
|
sys->io_pic = 0x7fff|INT_ENABLE;
|
154 |
|
|
|
155 |
|
|
do {
|
156 |
|
|
int need_resched = 0, context_has_been_saved, pic;
|
157 |
|
|
nheartbeats++;
|
158 |
|
|
|
159 |
|
|
if (0) {
|
160 |
|
|
int v = 0xe4, p = sys->io_pic;
|
161 |
|
|
if (p < 0) // LED 4 if interrupts enabled
|
162 |
|
|
v &= ~4;
|
163 |
|
|
if(p & 0x8000) // LED 8 if any already active
|
164 |
|
|
v |= 8;
|
165 |
|
|
sys->io_spio = v;
|
166 |
|
|
}
|
167 |
|
|
|
168 |
|
|
// if (sys->io_timb == 0)
|
169 |
|
|
// sys->io_timb = 1600000000; // CONTEXT_LENGTH;
|
170 |
|
|
// sys->io_timb = (sys->io_tima & 0x7fffffff) + 350;
|
171 |
|
|
// sys->io_spio = 0x0e0;
|
172 |
|
|
zip_rtu();
|
173 |
|
|
// sys->io_spio = 0xe2;
|
174 |
|
|
// sys->io_timb = CONTEXT_LENGTH;
|
175 |
|
|
|
176 |
|
|
last_context = current->context;
|
177 |
|
|
context_has_been_saved = 0;
|
178 |
|
|
pic = sys->io_pic;
|
179 |
|
|
|
180 |
|
|
if (pic & 0x8000) { // If there's an active interrupt
|
181 |
|
|
// Interrupt processing
|
182 |
|
|
sys->io_spio = 0x44;
|
183 |
|
|
|
184 |
|
|
// First, turn off pending interrupts
|
185 |
|
|
// Although we migt just write 0x7fff7fff to the
|
186 |
|
|
// interrupt controller, how do we know another
|
187 |
|
|
// interrupt hasn't taken place since we read it?
|
188 |
|
|
// Thus we turn off the pending interrupts that we
|
189 |
|
|
// know about.
|
190 |
|
|
pic &= 0x7fff;
|
191 |
|
|
// Acknowledge current ints, and turn off pending ints
|
192 |
|
|
sys->io_pic = INT_DISABLEV(pic)|(INT_CLEAR(pic));
|
193 |
|
|
if(pic&INT_TIMA) {
|
194 |
|
|
milliseconds++;
|
195 |
|
|
if (++ticks >= TICKS_PER_SECOND) {//(pic & SYSINT_PPS)
|
196 |
|
|
// Toggle the low order LED
|
197 |
|
|
tickcount++;
|
198 |
|
|
ticks = 0;
|
199 |
|
|
sys->io_spio = ((sys->io_spio&1)^1)|0x010;
|
200 |
|
|
pic |= SWINT_CLOCK;
|
201 |
|
|
}
|
202 |
|
|
}
|
203 |
|
|
//
|
204 |
|
|
if (pic&INT_BUTTON) {
|
205 |
|
|
// Need to turn the button interrupt off
|
206 |
|
|
enableset &= ~(INT_ENABLEV(INT_BUTTON));
|
207 |
|
|
if ((sys->io_spio&0x0f0)==0x030)
|
208 |
|
|
kpanic();
|
209 |
|
|
} else // We can turn it back on when the button
|
210 |
|
|
// is released
|
211 |
|
|
enableset |= INT_ENABLEV(INT_BUTTON);
|
212 |
|
|
if (pic & INT_UARTRX) {
|
213 |
|
|
int v = sys->io_uart;
|
214 |
|
|
|
215 |
|
|
if ((v & (~0x7f))==0) {
|
216 |
|
|
kpush_syspipe(rxpipe, v);
|
217 |
|
|
|
218 |
|
|
// Local Echo
|
219 |
|
|
if (pic & INT_UARTTX)
|
220 |
|
|
sys->io_uart = v;
|
221 |
|
|
}
|
222 |
|
|
} if (pic & INT_UARTTX) {
|
223 |
|
|
if (kpop_syspipe(txpipe, (int *)&sys->io_uart)==0) {
|
224 |
|
|
enableset |= (INT_ENABLEV(INT_UARTTX));
|
225 |
|
|
sys->io_pic = INT_UARTTX;
|
226 |
|
|
} else {
|
227 |
|
|
if (txpipe->m_wrtask)
|
228 |
|
|
txpipe->m_wrtask->state = SCHED_READY;
|
229 |
|
|
enableset &= ~(INT_ENABLEV(INT_UARTTX));
|
230 |
|
|
}
|
231 |
|
|
} if (audiostate) {
|
232 |
|
|
if (pic & INT_AUDIO) {
|
233 |
|
|
int v;
|
234 |
|
|
// States:
|
235 |
|
|
// 0 -- not in use
|
236 |
|
|
// 1 -- First sample, buffer empty
|
237 |
|
|
// time to read a new sample
|
238 |
|
|
// 2 -- second sample, to read new
|
239 |
|
|
// 3 -- Need to turn off
|
240 |
|
|
if ((audiostate & 3)==2) {
|
241 |
|
|
sys->io_pwm_audio = (audiostate>>2)&0x0ffff;
|
242 |
|
|
audiostate = 1;
|
243 |
|
|
} else if (kpop_syspipe(pwmpipe, &v)==0) {
|
244 |
|
|
audiostate = (2|(v<<2))&0x03ffff;
|
245 |
|
|
sys->io_pwm_audio = (v>>16)&0x0ffff;
|
246 |
|
|
} else {
|
247 |
|
|
audiostate = 0;
|
248 |
|
|
// Turn the device off
|
249 |
|
|
sys->io_pwm_audio = 0x10000;
|
250 |
|
|
// Turn the interrupts off
|
251 |
|
|
enableset &= ~(INT_ENABLEV(INT_AUDIO));
|
252 |
|
|
sys->io_spio = 0x020;
|
253 |
|
|
}
|
254 |
|
|
|
255 |
|
|
// This particular interrupt cannot be cleared
|
256 |
|
|
// until the port has been written to. Hence,
|
257 |
|
|
// now that we've written to the port, we clear
|
258 |
|
|
// it now.
|
259 |
|
|
sys->io_pic = INT_AUDIO;
|
260 |
|
|
}} else { // if (audiostate == 0)
|
261 |
|
|
int v;
|
262 |
|
|
if (kpop_syspipe(pwmpipe, &v)==0) {
|
263 |
|
|
audiostate = (2|(v<<2))&0x03ffff;
|
264 |
|
|
sys->io_pwm_audio = 0x310000 | ((v>>16)&0x0ffff);
|
265 |
|
|
enableset |= (INT_ENABLEV(INT_AUDIO));
|
266 |
|
|
sys->io_spio = 0x022;
|
267 |
|
|
sys->io_pic = INT_AUDIO;
|
268 |
|
|
} // else sys->io_spio = 0x020;
|
269 |
|
|
} milliseconds = kpost(tasklist, pic, milliseconds);
|
270 |
|
|
|
271 |
|
|
// Restart interrupts
|
272 |
|
|
enableset &= (~0x0ffff); // Keep the bottom bits off
|
273 |
|
|
sys->io_pic = INT_ENABLE|enableset;
|
274 |
|
|
} else {
|
275 |
|
|
sys->io_pic = INT_ENABLE; // Make sure interrupts are on
|
276 |
|
|
int v;
|
277 |
|
|
|
278 |
|
|
// Check for the beginning of an audio pipe. If the
|
279 |
|
|
// interrupt is not enabled, we still might need to
|
280 |
|
|
// enable it.
|
281 |
|
|
if ((audiostate==0)&&(kpop_syspipe(pwmpipe, &v)==0)) {
|
282 |
|
|
audiostate = (2|(v<<2))&0x03ffff;
|
283 |
|
|
sys->io_pwm_audio = 0x310000 | ((v>>16)&0x0ffff);
|
284 |
|
|
enableset |= (INT_ENABLEV(INT_AUDIO));
|
285 |
|
|
sys->io_spio = 0x022;
|
286 |
|
|
} // else sys->io_spio = 0x020;
|
287 |
|
|
|
288 |
|
|
// Or the beginning of a transmit pipe.
|
289 |
|
|
if (pic & INT_UARTTX) {
|
290 |
|
|
if (kpop_syspipe(txpipe, (int *)&sys->io_uart)==0) {
|
291 |
|
|
enableset |= (INT_ENABLEV(INT_UARTTX));
|
292 |
|
|
sys->io_pic = INT_UARTTX;
|
293 |
|
|
} else {
|
294 |
|
|
if (txpipe->m_wrtask)
|
295 |
|
|
txpipe->m_wrtask = SCHED_READY;
|
296 |
|
|
enableset &= ~(INT_ENABLEV(INT_UARTTX));
|
297 |
|
|
}
|
298 |
|
|
}
|
299 |
|
|
|
300 |
|
|
// What if the interrupt bit for the buttons is off?
|
301 |
|
|
if ((sys->io_spio & 0x0f0)==0)
|
302 |
|
|
enableset |= INT_ENABLEV(INT_BUTTON);
|
303 |
|
|
|
304 |
|
|
// What if someone left interrupts off?
|
305 |
|
|
// This might happen as part of a wait trap call, such
|
306 |
|
|
// as syspipe() accomplishes within uwrite_syspipe()
|
307 |
|
|
// (We also might've just turned them off ... ooops)
|
308 |
|
|
enableset &= (~0x0ffff); // Keep the bottom bits off
|
309 |
|
|
sys->io_pic = INT_ENABLE | enableset;
|
310 |
|
|
}
|
311 |
|
|
sys->io_spio = 0x40;
|
312 |
|
|
|
313 |
|
|
int zcc = zip_ucc();
|
314 |
|
|
if (zcc & CC_TRAPBIT) {
|
315 |
|
|
// sys->io_spio = 0x0ea;
|
316 |
|
|
|
317 |
|
|
context_has_been_saved = 1;
|
318 |
|
|
save_context(last_context);
|
319 |
|
|
last_context[14] = zcc & (~CC_TRAPBIT);
|
320 |
|
|
// Do trap handling
|
321 |
|
|
switch(last_context[1]) {
|
322 |
|
|
case TRAPID_WAIT:
|
323 |
|
|
{ // The task wishes to wait on an interrupt
|
324 |
|
|
int ilist, timeout;
|
325 |
|
|
ilist = last_context[2];
|
326 |
|
|
timeout= last_context[3];
|
327 |
|
|
if (current->pending & ilist) {
|
328 |
|
|
last_context[1] = ilist & current->pending;
|
329 |
|
|
// Clear upon any read
|
330 |
|
|
current->pending &= (~last_context[1]);
|
331 |
|
|
} else {
|
332 |
|
|
current->waitsig = ilist;
|
333 |
|
|
if (timeout != 0) {
|
334 |
|
|
current->state = SCHED_WAITING;
|
335 |
|
|
need_resched = 1;
|
336 |
|
|
if (timeout > 0) {
|
337 |
|
|
current->timeout=milliseconds+timeout;
|
338 |
|
|
current->waitsig |= SWINT_TIMEOUT;
|
339 |
|
|
}
|
340 |
|
|
}
|
341 |
|
|
}} break;
|
342 |
|
|
case TRAPID_CLEAR:
|
343 |
|
|
{ unsigned timeout;
|
344 |
|
|
// The task wishes to clear any pending
|
345 |
|
|
// interrupts, in a likely attempt to create
|
346 |
|
|
// them soon.
|
347 |
|
|
last_context[1] = last_context[2] & current->pending;
|
348 |
|
|
// Clear upon any read
|
349 |
|
|
current->pending &= (~last_context[1]);
|
350 |
|
|
timeout = (unsigned)last_context[2];
|
351 |
|
|
if (timeout) {
|
352 |
|
|
if ((int)timeout < 0)
|
353 |
|
|
current->pending &= (~SWINT_TIMEOUT);
|
354 |
|
|
else
|
355 |
|
|
current->timeout = milliseconds+timeout;
|
356 |
|
|
}} break;
|
357 |
|
|
case TRAPID_POST:
|
358 |
|
|
kpost(tasklist, last_context[2]&(~0x07fff),
|
359 |
|
|
milliseconds);
|
360 |
|
|
break;
|
361 |
|
|
case TRAPID_YIELD:
|
362 |
|
|
need_resched = 1;
|
363 |
|
|
break;
|
364 |
|
|
case TRAPID_READ:
|
365 |
|
|
{
|
366 |
|
|
KFILDES *fd = NULL;
|
367 |
|
|
if ((unsigned)last_context[2]
|
368 |
|
|
< (unsigned)MAX_KFILDES)
|
369 |
|
|
fd = current->fd[last_context[2]];
|
370 |
|
|
if ((!fd)||(!fd->dev))
|
371 |
|
|
last_context[1] = -EBADF;
|
372 |
|
|
else
|
373 |
|
|
fd->dev->read(current, fd->id,
|
374 |
|
|
(void *)last_context[3], last_context[4]);
|
375 |
|
|
} break;
|
376 |
|
|
case TRAPID_WRITE:
|
377 |
|
|
{ KFILDES *fd = NULL;
|
378 |
|
|
if ((unsigned)last_context[2]
|
379 |
|
|
< (unsigned)MAX_KFILDES)
|
380 |
|
|
fd = current->fd[last_context[2]];
|
381 |
|
|
else { kpanic(); zip_halt(); }
|
382 |
|
|
if ((!fd)||(!fd->dev))
|
383 |
|
|
last_context[1] = -EBADF;
|
384 |
|
|
else
|
385 |
|
|
fd->dev->write(current, fd->id,
|
386 |
|
|
(void *)last_context[3], last_context[4]);
|
387 |
|
|
} break;
|
388 |
|
|
case TRAPID_TIME:
|
389 |
|
|
last_context[1] = tickcount;
|
390 |
|
|
break;
|
391 |
|
|
case TRAPID_MALLOC:
|
392 |
|
|
last_context[1] = (int)sys_malloc(last_context[2]);
|
393 |
|
|
break;
|
394 |
|
|
case TRAPID_FREE:
|
395 |
|
|
// Our current malloc cannot free
|
396 |
|
|
// sys_free(last_context[2])
|
397 |
|
|
break;
|
398 |
|
|
case TRAPID_EXIT:
|
399 |
|
|
current->state = SCHED_EXIT;
|
400 |
|
|
need_resched = 1;
|
401 |
|
|
kpanic();
|
402 |
|
|
zip_halt();
|
403 |
|
|
break;
|
404 |
|
|
default:
|
405 |
|
|
current->state = SCHED_ERR;
|
406 |
|
|
need_resched = 1;
|
407 |
|
|
kpanic();
|
408 |
|
|
zip_halt();
|
409 |
|
|
break;
|
410 |
|
|
}
|
411 |
|
|
|
412 |
|
|
restore_context(last_context);
|
413 |
|
|
} else if (zcc & (CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_ILL)) {
|
414 |
|
|
current->state = SCHED_ERR;
|
415 |
|
|
// current->errno = -EBUS;
|
416 |
|
|
current->errno = (int)sys->io_buserr;
|
417 |
|
|
save_context(last_context);
|
418 |
|
|
context_has_been_saved = 1;
|
419 |
|
|
kpanic();
|
420 |
|
|
zip_halt();
|
421 |
|
|
}
|
422 |
|
|
|
423 |
|
|
if ((need_resched)||(current->state != SCHED_READY)
|
424 |
|
|
||(current == tasklist[LAST_TASK]))
|
425 |
|
|
current = kschedule(LAST_TASK, tasklist, current);
|
426 |
|
|
|
427 |
|
|
if (current->context != last_context) {
|
428 |
|
|
// Swap contexts
|
429 |
|
|
if (!context_has_been_saved)
|
430 |
|
|
save_context(last_context);
|
431 |
|
|
restore_context(current->context);
|
432 |
|
|
}
|
433 |
|
|
} while(1);
|
434 |
|
|
}
|
435 |
|
|
|
436 |
|
|
TASKP kschedule(int LAST_TASK, TASKP *tasklist, TASKP last) {
|
437 |
|
|
TASKP current = tasklist[LAST_TASK];
|
438 |
|
|
int nxtid = 0, i;
|
439 |
|
|
|
440 |
|
|
// What task were we just running?
|
441 |
|
|
for(i=0; i<=LAST_TASK; i++) {
|
442 |
|
|
if (last == tasklist[i]) {
|
443 |
|
|
// If we found it, then let's run the next one
|
444 |
|
|
nxtid = i+1;
|
445 |
|
|
break;
|
446 |
|
|
}
|
447 |
|
|
}
|
448 |
|
|
|
449 |
|
|
// Now let's see if we can find the next ready task to run
|
450 |
|
|
for(; nxtid<LAST_TASK; nxtid++)
|
451 |
|
|
if (tasklist[nxtid]->state == SCHED_READY) {
|
452 |
|
|
current=tasklist[nxtid];
|
453 |
|
|
break;
|
454 |
|
|
}
|
455 |
|
|
// The last task (the idle task) doesn't count
|
456 |
|
|
if (nxtid >= LAST_TASK) {
|
457 |
|
|
nxtid = 0; // Don't automatically run idle task
|
458 |
|
|
for(; nxtid<LAST_TASK; nxtid++)
|
459 |
|
|
if (tasklist[nxtid]->state == SCHED_READY) {
|
460 |
|
|
break;
|
461 |
|
|
}
|
462 |
|
|
// Now we stop at the idle task, if nothing else is ready
|
463 |
|
|
current = tasklist[nxtid];
|
464 |
|
|
}
|
465 |
|
|
return current;
|
466 |
|
|
}
|
467 |
|
|
|
468 |
|
|
int kpost(TASKP *tasklist, unsigned events, int milliseconds) {
|
469 |
|
|
int i;
|
470 |
|
|
if (events & INT_TIMA)
|
471 |
|
|
milliseconds++;
|
472 |
|
|
if (milliseconds<0) {
|
473 |
|
|
milliseconds -= 0x80000000;
|
474 |
|
|
for(i=0; i<=LAST_TASK; i++) {
|
475 |
|
|
if(tasklist[i]->timeout) {
|
476 |
|
|
tasklist[i]->timeout -= 0x80000000;
|
477 |
|
|
if (tasklist[i]->timeout==0)
|
478 |
|
|
tasklist[i]->timeout++;
|
479 |
|
|
if ((int)tasklist[i]->timeout < milliseconds) {
|
480 |
|
|
tasklist[i]->pending |= SWINT_TIMEOUT;
|
481 |
|
|
tasklist[i]->timeout = 0;
|
482 |
|
|
}
|
483 |
|
|
}
|
484 |
|
|
}
|
485 |
|
|
} else {
|
486 |
|
|
for(i=0; i<=LAST_TASK; i++) {
|
487 |
|
|
if(tasklist[i]->timeout) {
|
488 |
|
|
if (tasklist[i]->timeout < (unsigned)milliseconds) {
|
489 |
|
|
tasklist[i]->pending |= SWINT_TIMEOUT;
|
490 |
|
|
tasklist[i]->timeout = 0;
|
491 |
|
|
}
|
492 |
|
|
}
|
493 |
|
|
}
|
494 |
|
|
} for(i=0; i<=LAST_TASK; i++) {
|
495 |
|
|
tasklist[i]->pending |= events;
|
496 |
|
|
if ((tasklist[i]->state == SCHED_WAITING)
|
497 |
|
|
&&(tasklist[i]->waitsig&tasklist[i]->pending)) {
|
498 |
|
|
tasklist[i]->state = SCHED_READY;
|
499 |
|
|
tasklist[i]->context[1] = tasklist[i]->waitsig & tasklist[i]->pending;
|
500 |
|
|
tasklist[i]->pending &= (~tasklist[i]->context[1]);
|
501 |
|
|
tasklist[i]->waitsig = 0;
|
502 |
|
|
}
|
503 |
|
|
} return milliseconds;
|
504 |
|
|
}
|
505 |
|
|
|
506 |
|
|
void kuserexit(int a) {
|
507 |
|
|
syscall(TRAPID_EXIT, a, 0, 0);
|
508 |
|
|
}
|
509 |
|
|
|
510 |
|
|
void *sys_malloc(int sz) {
|
511 |
|
|
{
|
512 |
|
|
SCOPE *s = (SCOPE *)SCOPEADDR;
|
513 |
|
|
s->s_control = TRIGGER_SCOPE_NOW | (s->s_control & 0x0ffff);
|
514 |
|
|
}
|
515 |
|
|
|
516 |
|
|
void *res = heap;
|
517 |
|
|
heap += sz;
|
518 |
|
|
if ((int)heap > ((int)&res)-32) {
|
519 |
|
|
IOSPACE *sys = (IOSPACE *)IOADDR;
|
520 |
|
|
sys->io_spio = 0xf3;
|
521 |
|
|
asm("break 0");
|
522 |
|
|
}
|
523 |
|
|
return res;
|
524 |
|
|
}
|
525 |
|
|
|
526 |
|
|
/*
|
527 |
|
|
// This won't work. Once we apply an rtu(), there will be an immediate
|
528 |
|
|
// interrupt before the task has had a chance to fill in a first value. By
|
529 |
|
|
// instead waiting until the task comes back from it's first task swap, perhaps
|
530 |
|
|
// having stalled it's pipe, then we can get our interrupt up and running.
|
531 |
|
|
// Not only that, but at that time we'll have plenty of info to stuff into the
|
532 |
|
|
// interrupt as well.
|
533 |
|
|
void kwrite_audio(TASKP tsk, int dev, int *dst, int len) {
|
534 |
|
|
kwrite_syspipe(tsk,dev,dst,len);
|
535 |
|
|
if (tsk->context[15] == (int)uwrite_syspipe) {
|
536 |
|
|
IOSPACE *io = (IOSPACE *)IOADDR;
|
537 |
|
|
// Turn our audio interrupt on.
|
538 |
|
|
io->pic = INT_ENABLEV(INT_AUDIO);
|
539 |
|
|
}
|
540 |
|
|
}
|
541 |
|
|
|
542 |
|
|
void kwrite_txuart(TASKP tsk, int dev, int *dst, int len) {
|
543 |
|
|
kwrite_syspipe(tsk,dev,dst,len);
|
544 |
|
|
if (tsk->context[15] == (int)uwrite_syspipe) {
|
545 |
|
|
IOSPACE *io = (IOSPACE *)IOADDR;
|
546 |
|
|
// Turn our UART transmit interrupt on.
|
547 |
|
|
io->pic = INT_ENABLEV(INT_UARTTX);
|
548 |
|
|
}
|
549 |
|
|
}
|
550 |
|
|
|
551 |
|
|
*/
|
552 |
|
|
|