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

Subversion Repositories s6soc

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

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
#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
 

powered by: WebSVN 2.1.0

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