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

Subversion Repositories s6soc

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

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

powered by: WebSVN 2.1.0

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