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

Subversion Repositories s6soc

[/] [s6soc/] [trunk/] [sw/] [zipos/] [kernel.c] - Blame information for rev 45

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
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 37 dgisselq
#define CONTEXT_LENGTH  80000   // 1ms
65 22 dgisselq
#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 27 dgisselq
extern TASKP    *ksetup(void);
72 22 dgisselq
 
73
int     LAST_TASK;
74
 
75 45 dgisselq
extern void txstr(const char *);
76
 
77 22 dgisselq
void    kernel_entry(void) {
78
        int     nheartbeats= 0, tickcount = 0, milliseconds=0, ticks = 0;
79 27 dgisselq
        int     audiostate = 0, buttonstate = 0;
80 22 dgisselq
        TASKP   *tasklist, current;
81
        int     *last_context;
82
 
83 27 dgisselq
        tasklist = ksetup();
84 22 dgisselq
 
85 27 dgisselq
        current = tasklist[0];
86 22 dgisselq
        restore_context(current->context);
87
        last_context = current->context;
88
 
89
        unsigned enableset =
90
                INT_ENABLEV(INT_BUTTON)
91 45 dgisselq
                |INT_ENABLEV(INT_TIMER)
92 22 dgisselq
                // |INT_ENABLEV(INT_UARTRX)
93
                // |INT_ENABLEV(INT_UARTTX) // Needs to be turned on by driver
94
                // |INT_ENABLEV(INT_AUDIO // Needs to be turned on by driver)
95
                // |INT_ENABLEV(INT_GPIO)
96
                ;
97
        // Then selectively turn some of them back on
98 45 dgisselq
        _sys->io_pic = INT_ENABLE | enableset | 0x07fff;
99 22 dgisselq
 
100 45 dgisselq
        txstr("HEAP: "); txhex(heap);
101
 
102 22 dgisselq
        do {
103
                int need_resched = 0, context_has_been_saved, pic;
104
                nheartbeats++;
105
 
106
                zip_rtu();
107
 
108
                last_context = current->context;
109
                context_has_been_saved = 0;
110 45 dgisselq
                pic = _sys->io_pic;
111 22 dgisselq
 
112
                if (pic & 0x8000) { // If there's an active interrupt
113
                        // Interrupt processing
114 45 dgisselq
                        _sys->io_spio = 0x44;
115 22 dgisselq
 
116
                        // First, turn off pending interrupts
117
                        // Although we migt just write 0x7fff7fff to the
118
                        // interrupt controller, how do we know another
119
                        // interrupt hasn't taken place since we read it?
120
                        // Thus we turn off the pending interrupts that we
121
                        // know about.
122
                        pic &= 0x7fff;
123
                        // Acknowledge current ints, and turn off pending ints
124 45 dgisselq
                        _sys->io_pic = INT_DISABLEV(pic)|(INT_CLEAR(pic));
125
                        if(pic&INT_TIMER) {
126 22 dgisselq
                                if (++ticks >= TICKS_PER_SECOND) {//(pic & SYSINT_PPS)
127
                                        // Toggle the low order LED
128
                                        tickcount++;
129
                                        ticks = 0;
130 45 dgisselq
                                        _sys->io_spio = ((_sys->io_spio&1)^1)|0x010;
131 22 dgisselq
                                        pic |= SWINT_CLOCK;
132
                                }
133 27 dgisselq
                                if (buttonstate)
134
                                        buttonstate--;
135 45 dgisselq
                                else if ((_sys->io_spio & 0x0f0)==0)
136 27 dgisselq
                                        enableset |= INT_ENABLEV(INT_BUTTON);
137 22 dgisselq
                        }
138
                        // 
139
                        if (pic&INT_BUTTON) {
140
                                // Need to turn the button interrupt off
141
                                enableset &= ~(INT_ENABLEV(INT_BUTTON));
142 45 dgisselq
                                if ((_sys->io_spio&0x0f0)==0x030)
143 22 dgisselq
                                        kpanic();
144 45 dgisselq
                                if (buttonstate)
145
                                        pic &= ~INT_BUTTON;
146
                                buttonstate = 50;
147 27 dgisselq
                        }
148 22 dgisselq
                        if (pic & INT_UARTRX) {
149 45 dgisselq
                                int v = _sys->io_uart;
150 22 dgisselq
 
151
                                if ((v & (~0x7f))==0) {
152
                                        kpush_syspipe(rxpipe, v);
153
 
154
                                        // Local Echo
155 27 dgisselq
                                        if (pic & INT_UARTTX) {
156 45 dgisselq
                                                _sys->io_uart = v;
157
                                                _sys->io_pic = INT_UARTTX;
158 27 dgisselq
                                                pic &= ~INT_UARTTX;
159
                                        }
160 22 dgisselq
                                }
161
                        } if (pic & INT_UARTTX) {
162 45 dgisselq
                                char    ch;
163
                                if (kpop_syspipe(txpipe, &ch)==0) {
164
                                        unsigned        v = ch;
165 22 dgisselq
                                        enableset |= (INT_ENABLEV(INT_UARTTX));
166 45 dgisselq
                                        _sys->io_uart= v;
167
                                        _sys->io_pic = INT_UARTTX;
168 27 dgisselq
                                        // if (v == 'W')
169 45 dgisselq
                                                // sys->io_watchdog = 5;
170 27 dgisselq
                                                // 75k was writing the 'e'
171
                                } else
172 45 dgisselq
                                        enableset&= ~(INT_DISABLEV(INT_UARTTX));
173 22 dgisselq
                        } if (audiostate) {
174
                                if (pic & INT_AUDIO) {
175 45 dgisselq
                                unsigned short  sample;
176
 
177 22 dgisselq
                                // States: 
178
                                //      0 -- not in use
179 45 dgisselq
                                //      1 -- in use
180
 
181
                                if (kpop_short_syspipe(pwmpipe, &sample)==0) {
182
                                        _sys->io_pwm_audio = sample;
183
                                        _sys->io_spio = 0x022;
184
                                        // audiostate = 1;
185 22 dgisselq
                                } else {
186
                                        audiostate = 0;
187
                                        // Turn the device off
188 45 dgisselq
                                        _sys->io_pwm_audio = 0x10000;
189 22 dgisselq
                                        // Turn the interrupts off
190
                                        enableset &= ~(INT_ENABLEV(INT_AUDIO));
191 45 dgisselq
                                        _sys->io_spio = 0x020;
192 22 dgisselq
                                }
193
 
194
                                // This particular interrupt cannot be cleared
195
                                // until the port has been written to.  Hence,
196
                                // now that we've written to the port, we clear
197 27 dgisselq
                                // it now.  If it needs retriggering, the port
198
                                // will retrigger itself -- despite being
199
                                // cleared here.
200 45 dgisselq
                                _sys->io_pic = INT_AUDIO;
201
                        }}
202
/*
203
                        else { // if (audiostate == 0)
204
                                unsigned short  sample;
205
 
206
                                if (kpop_short_syspipe(pwmpipe, &sample)==0) {
207
                                        audiostate = 1;
208
                                        _sys->io_pwm_audio = 0x310000 | sample;
209 22 dgisselq
                                        enableset |= (INT_ENABLEV(INT_AUDIO));
210 45 dgisselq
                                        _sys->io_spio = 0x022;
211
                                        _sys->io_pic = INT_AUDIO;
212 22 dgisselq
                                } // else sys->io_spio = 0x020;
213 29 dgisselq
                        }
214 45 dgisselq
*/
215 29 dgisselq
                        milliseconds = kpost(tasklist, pic, milliseconds);
216 22 dgisselq
 
217
                        // Restart interrupts
218
                        enableset &= (~0x0ffff); // Keep the bottom bits off
219 45 dgisselq
                        _sys->io_pic = INT_ENABLE|enableset;
220 22 dgisselq
                } else {
221 45 dgisselq
                        _sys->io_pic = INT_ENABLE; // Make sure interrupts are on
222
                        unsigned short  sample;
223 22 dgisselq
 
224
                        // Check for the beginning of an audio pipe.  If the
225
                        // interrupt is not enabled, we still might need to
226
                        // enable it.
227 45 dgisselq
 
228
                        if ((audiostate==0)&&(kpop_short_syspipe(pwmpipe, &sample)==0)) {
229
                                audiostate = 1;
230
                                _sys->io_pwm_audio = 0x310000 | (sample);
231
                                _sys->io_pic = INT_AUDIO;
232 22 dgisselq
                                enableset |= (INT_ENABLEV(INT_AUDIO));
233 45 dgisselq
                                _sys->io_spio = 0x022;
234 22 dgisselq
                        } // else sys->io_spio = 0x020;
235
 
236
                        // Or the beginning of a transmit pipe.  
237
                        if (pic & INT_UARTTX) {
238 45 dgisselq
                                char    ch;
239
                                if (kpop_syspipe(txpipe, &ch)==0) {
240
                                        unsigned        v = ch;
241 22 dgisselq
                                        enableset |= (INT_ENABLEV(INT_UARTTX));
242 45 dgisselq
                                        _sys->io_uart = v;
243
                                        _sys->io_pic = INT_UARTTX;
244 27 dgisselq
                                } else
245 22 dgisselq
                                        enableset &= ~(INT_ENABLEV(INT_UARTTX));
246
                        }
247
 
248
                        // What if someone left interrupts off?
249
                        // This might happen as part of a wait trap call, such
250
                        // as syspipe() accomplishes within uwrite_syspipe()
251
                        // (We also might've just turned them off ... ooops)
252
                        enableset &= (~0x0ffff); // Keep the bottom bits off
253 45 dgisselq
                        _sys->io_pic = INT_ENABLE | enableset;
254 22 dgisselq
                }
255 45 dgisselq
                _sys->io_spio = 0x40;
256 22 dgisselq
 
257
                int zcc = zip_ucc();
258
                if (zcc & CC_TRAPBIT) {
259
                        // sys->io_spio = 0x0ea;
260
 
261
                        context_has_been_saved = 1;
262
                        save_context(last_context);
263
                        last_context[14] = zcc & (~CC_TRAPBIT);
264
                        // Do trap handling
265
                        switch(last_context[1]) {
266
                        case TRAPID_WAIT:
267
                                { // The task wishes to wait on an interrupt
268
                                int ilist, timeout;
269
                                ilist = last_context[2];
270
                                timeout= last_context[3];
271 44 dgisselq
                                last_context[1] = ilist & current->pending;
272 22 dgisselq
                                if (current->pending & ilist) {
273
                                        // Clear upon any read
274
                                        current->pending &= (~last_context[1]);
275
                                } else {
276
                                        current->waitsig = ilist;
277
                                        if (timeout != 0) {
278
                                                current->state = SCHED_WAITING;
279
                                                need_resched = 1;
280
                                                if (timeout > 0) {
281
                                                        current->timeout=milliseconds+timeout;
282
                                                        current->waitsig |= SWINT_TIMEOUT;
283
                                                }
284
                                        }
285
                                }} break;
286
                        case TRAPID_CLEAR:
287
                                { unsigned timeout;
288
                                // The task wishes to clear any pending
289
                                // interrupts, in a likely attempt to create
290
                                // them soon.
291
                                last_context[1] = last_context[2] & current->pending;
292
                                // Clear upon any read
293
                                current->pending &= (~last_context[1]);
294
                                timeout = (unsigned)last_context[2];
295
                                if (timeout) {
296
                                        if ((int)timeout < 0)
297 44 dgisselq
                                                // Turn off any pending timeout
298 22 dgisselq
                                                current->pending &= (~SWINT_TIMEOUT);
299
                                        else
300 44 dgisselq
                                                // Otherwise, start a timeout
301
                                                // counter
302 22 dgisselq
                                                current->timeout = milliseconds+timeout;
303
                                }} break;
304
                        case TRAPID_POST:
305
                                kpost(tasklist, last_context[2]&(~0x07fff),
306
                                                milliseconds);
307
                                break;
308
                        case TRAPID_YIELD:
309
                                need_resched = 1;
310
                                break;
311
                        case TRAPID_READ:
312
                                {
313
                                KFILDES *fd = NULL;
314
                                if ((unsigned)last_context[2]
315
                                                < (unsigned)MAX_KFILDES)
316
                                        fd = current->fd[last_context[2]];
317
                                if ((!fd)||(!fd->dev))
318
                                        last_context[1] = -EBADF;
319
                                else
320
                                        fd->dev->read(current, fd->id,
321
                                           (void *)last_context[3], last_context[4]);
322
                                } break;
323
                        case TRAPID_WRITE:
324
                                { KFILDES       *fd = NULL;
325
                                if ((unsigned)last_context[2]
326
                                                < (unsigned)MAX_KFILDES)
327
                                        fd = current->fd[last_context[2]];
328
                                else { kpanic(); zip_halt(); }
329
                                if ((!fd)||(!fd->dev))
330
                                        last_context[1] = -EBADF;
331 29 dgisselq
                                else {
332 22 dgisselq
                                        fd->dev->write(current, fd->id,
333
                                           (void *)last_context[3], last_context[4]);
334 29 dgisselq
                                }}
335
                                break;
336 22 dgisselq
                        case TRAPID_TIME:
337
                                last_context[1] = tickcount;
338
                                break;
339
                        case TRAPID_MALLOC:
340
                                last_context[1] = (int)sys_malloc(last_context[2]);
341
                                break;
342
                        case TRAPID_FREE:
343
                                // Our current malloc cannot free
344
                                // sys_free(last_context[2])
345
                                break;
346
                        case TRAPID_EXIT:
347
                                current->state = SCHED_EXIT;
348
                                need_resched = 1;
349
                                kpanic();
350
                                zip_halt();
351
                                break;
352
                        default:
353
                                current->state = SCHED_ERR;
354
                                need_resched = 1;
355
                                kpanic();
356
                                zip_halt();
357
                                break;
358
                        }
359
 
360
                        restore_context(last_context);
361
                } else if (zcc & (CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_ILL)) {
362
                        current->state = SCHED_ERR;
363 45 dgisselq
                        current->errno = (int)_sys->io_buserr;
364 22 dgisselq
                        save_context(last_context);
365
                        context_has_been_saved = 1;
366
                        kpanic();
367
                        zip_halt();
368
                }
369
 
370
                if ((need_resched)||(current->state != SCHED_READY)
371
                        ||(current == tasklist[LAST_TASK]))
372
                        current = kschedule(LAST_TASK, tasklist, current);
373
 
374
                if (current->context != last_context) {
375
                        // Swap contexts
376
                        if (!context_has_been_saved)
377
                                save_context(last_context);
378
                        restore_context(current->context);
379
                }
380
        } while(1);
381
}
382
 
383
TASKP   kschedule(int LAST_TASK, TASKP *tasklist, TASKP last) {
384
        TASKP   current = tasklist[LAST_TASK];
385
        int nxtid = 0, i;
386
 
387
        // What task were we just running?
388
        for(i=0; i<=LAST_TASK; i++) {
389
                if (last == tasklist[i]) {
390
                        // If we found it, then let's run the next one
391
                        nxtid = i+1;
392
                        break;
393
                }
394
        }
395
 
396
        // Now let's see if we can find the next ready task to run
397 29 dgisselq
        for(; nxtid<LAST_TASK; nxtid++) {
398 22 dgisselq
                if (tasklist[nxtid]->state == SCHED_READY) {
399
                        current=tasklist[nxtid];
400
                        break;
401
                }
402 29 dgisselq
        }
403 22 dgisselq
        // The last task (the idle task) doesn't count
404
        if (nxtid >= LAST_TASK) {
405
                nxtid = 0; // Don't automatically run idle task
406
                for(; nxtid<LAST_TASK; nxtid++)
407
                        if (tasklist[nxtid]->state == SCHED_READY) {
408
                                break;
409
                        }
410
                // Now we stop at the idle task, if nothing else is ready
411
                current = tasklist[nxtid];
412 29 dgisselq
        } return current;
413 22 dgisselq
}
414
 
415
int     kpost(TASKP *tasklist, unsigned events, int milliseconds) {
416
        int     i;
417 45 dgisselq
        if (events & INT_TIMER)
418 22 dgisselq
                milliseconds++;
419
        if (milliseconds<0) {
420
                milliseconds -= 0x80000000;
421
                for(i=0; i<=LAST_TASK; i++) {
422
                        if(tasklist[i]->timeout) {
423
                                tasklist[i]->timeout -= 0x80000000;
424
                                if (tasklist[i]->timeout==0)
425
                                        tasklist[i]->timeout++;
426
                                if ((int)tasklist[i]->timeout < milliseconds) {
427
                                        tasklist[i]->pending |= SWINT_TIMEOUT;
428
                                        tasklist[i]->timeout = 0;
429
                                }
430
                        }
431
                }
432
        } else {
433
                for(i=0; i<=LAST_TASK; i++) {
434
                        if(tasklist[i]->timeout) {
435
                                if (tasklist[i]->timeout < (unsigned)milliseconds) {
436
                                        tasklist[i]->pending |= SWINT_TIMEOUT;
437
                                        tasklist[i]->timeout = 0;
438
                                }
439
                        }
440
                }
441
        } for(i=0; i<=LAST_TASK; i++) {
442
                tasklist[i]->pending |= events;
443
                if ((tasklist[i]->state == SCHED_WAITING)
444
                                &&(tasklist[i]->waitsig&tasklist[i]->pending)) {
445
                        tasklist[i]->state = SCHED_READY;
446
                        tasklist[i]->context[1] = tasklist[i]->waitsig & tasklist[i]->pending;
447
                        tasklist[i]->pending &= (~tasklist[i]->context[1]);
448
                        tasklist[i]->waitsig = 0;
449
                }
450
        } return milliseconds;
451
}
452
 
453
 

powered by: WebSVN 2.1.0

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