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

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [testbench/] [uos/] [uos.c] - Blame information for rev 343

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

Line No. Rev Author Line
1 222 markom
/* This file is part of test microkernel for OpenRISC 1000. */
2
/* (C) 2000 Damjan Lampret, lampret@opencores.org */
3
 
4
#include "support.h"
5
#include "spr_defs.h"
6
#include "uos.h"
7
#include "ipc.h"
8
#include "int.h"
9
 
10
/* External functions prototypes */
11
int tick_init(unsigned long period, void (* inf)(void));
12
 
13
/* Pointers to contexts used by except_or32.S routines */
14
unsigned long *task_context;
15
unsigned long *kernel_context;
16
 
17
/* TCBs for all tasks in the system */
18
struct tcb tasks[MAX_TASKS+1];
19
 
20
/* Stacks for the tasks (stacks[0] is kernel stack) */
21
unsigned char stacks[MAX_TASKS+1][STACK_SIZE];
22
 
23
/* MCBs for IPC messages */
24
struct mcb msgs[MAX_MSGS];
25
 
26
/* Pointer to linked list of free MCBs. */
27
struct mcb *free_mcbs;
28
 
29
/* TID of the current user task */
30
tid_t curtask = 0;
31
 
32
/* Statistics */
33
int kernel_sched_cnt = 0;
34
int kernel_syscall_cnt = 0;
35
 
36
/* Timestamp via or1ksim (CPU cycle number). */
37
unsigned long timestamp()
38
{
39
        register unsigned long cycles asm("r3");
40
        asm("l.sys 201");
41
        return cycles;
42
}
43
 
44
/* Standard function for filling memory with a constant byte. */
45 343 erez
void *memset(void *dst, int c, size_t size)
46 222 markom
{
47
        char *tmp = dst;
48
 
49
        for(;tmp && (tmp < (char *)dst + size); tmp++)
50
                *(char *)tmp = (char)c;
51
 
52
        return dst;
53
}
54
 
55
/* Traverse linked list of MCBs and show individual messages. */
56
void kernel_show_mcbs(struct mcb *mcb)
57
{
58
        for(;mcb; mcb = mcb->next) {
59
                printf("MCB len=%u origintask=%u ", mcb->length, mcb->origin);
60
                printf("msg:%s\n", mcb->msg);
61
        }
62
}
63
 
64
/* Show all contexts. */
65
void kernel_show_contexts()
66
{
67
        int i;
68
        tid_t t;
69
 
70
        for(t = 1; t <= MAX_TASKS; t++) {
71
                printf("\ntask TID=%d: PC=0x%x ", t, (unsigned)tasks[t].regs.pc & ~0x3);
72
                printf("SP(r1)=0x%x ", (unsigned)tasks[t].regs.sp);
73
                printf("SR[EXR]=%d ", (unsigned)(tasks[t].regs.pc & SPR_SR_EXR) >> 1);
74
                printf("SR[SUPV]=%d\n", (unsigned)tasks[t].regs.pc & SPR_SR_SUPV);
75
                for(i = 1; i < GPRS; i++) {
76
                        if (i % 4 == 0)
77
                                printf("\n");
78
                        printf("r%d=0x%.8x ", i, (unsigned)tasks[t].regs.gprs[i]);
79
                }
80
                printf("\n");
81
                kernel_show_mcbs(tasks[t].waiting_msgs);
82
        }
83
        printf("\n");
84
}
85
 
86
/* Simple round-robin scheduler that directly calls dispatcher. It is
87
   called by low level external interrupt exception handler or by
88
   kernel_syscall if KERNEL_SYSCALL_SCHED is defined. */
89
void kernel_sched()
90
{
91
        if ((++curtask > MAX_TASKS) || !(tasks[curtask].regs.pc & ~0x3))
92
                curtask = 1;
93
        task_context = (unsigned long *)&tasks[curtask].regs;
94
 
95
#if KERNEL_OUTPUT
96
        printf("kernel_sched(): entry number %d, ", ++kernel_sched_cnt);
97
        printf("dispatching task TID=%d, time %u cycles", curtask, timestamp());
98
 
99
        kernel_show_contexts();
100
#endif
101
 
102
        dispatch();
103
}
104
 
105
/* System call uos_msgsnd. */
106
int uos_msgsnd(tid_t desttask, char *buf, int len)
107
{
108
        asm("l.sys 1");
109
        asm("l.nop");
110
}
111
 
112
/* System call uos_msgrcv. */
113
int uos_msgrcv(tid_t origintask, char *buf, int len)
114
{
115
        asm("l.sys 2");
116
        asm("l.nop");
117
}
118
 
119
/* Handles system call uos_msgsnd. */
120
void kernel_msgsnd(tid_t tid)
121
{
122
        struct mcb *mcb;
123
        struct mcb **dstmq;
124
        struct tcb *task;
125
 
126
        task = &tasks[tid];
127
 
128
        /* Sanity checks. */
129
 
130
        /* Does destination task exist? */
131
        if (!task->regs.gprs[1] || (task->regs.gprs[1] > MAX_TASKS)) {
132
        task->regs.gprs[9] = IPC_ENOTASK;
133
                return;
134
        }
135
 
136
        /* Are there any free MCBs? */
137
        if (!free_mcbs) {
138
                task->regs.gprs[9] = IPC_EOUTOFMCBS;
139
                return;
140
        }
141
 
142
        /* Is message too big to fit into MCB's message buffer? */
143
        if (task->regs.gprs[3] > MAX_MSGLEN) {
144
                task->regs.gprs[9] = IPC_ETOOBIG;
145
                return;
146
        }
147
 
148
        /* OK, send the message. */
149
 
150
        /* First, allocate MCB. */
151
        mcb = free_mcbs;
152
        free_mcbs = mcb->next;
153
 
154
        /* Second, copy message to the MCB. */
155
        memcpy(mcb->msg, (void *)task->regs.gprs[2], task->regs.gprs[3]);
156
        mcb->origin = tid;
157
        mcb->length = task->regs.gprs[3];
158
        mcb->next = NULL;
159
 
160
        /* Insert MCB into destination task's message queue at
161
           the end. */
162
        dstmq = &tasks[task->regs.gprs[1]].waiting_msgs;
163
        for(;*dstmq;)
164
                dstmq = &((*dstmq)->next);
165
        *dstmq = mcb;
166
 
167
        task->regs.gprs[9] = IPC_NOERR;
168
        return;
169
}
170
 
171
/* Handles system call uos_msgrcv. */
172
void kernel_msgrcv(tid_t tid)
173
{
174
        struct mcb *mcb;
175
        struct mcb *curmsg, **linkp;
176
        struct tcb *task;
177
 
178
        task = &tasks[tid];
179
 
180
        /* Sanity checks. */
181
 
182
        /* Does origin task exist? */
183
        if (task->regs.gprs[1] > MAX_TASKS) {
184
                task->regs.gprs[9] = IPC_ENOTASK;
185
                return;
186
        }
187
 
188
        /* Are there any messages waiting for reception? */
189
        if (!task->waiting_msgs) {
190
                task->regs.gprs[9] = IPC_ENOMSGS;
191
                return;
192
        }
193
 
194
        /* OK, receive the message. */
195
 
196
        /* Search waiting messages for one coming from origintask. If
197
           origintask is zero then grab the first message. */
198
        curmsg = task->waiting_msgs;
199
        linkp = &task->waiting_msgs;
200
        for(;task->regs.gprs[1] && curmsg->next && curmsg->origin != task->regs.gprs[1];) {
201
                linkp = &curmsg->next;
202
                curmsg = curmsg->next;
203
        }
204
 
205
        /* Is receive buffer too small for receiving message? */
206
        if (task->regs.gprs[3] < curmsg->length) {
207
                task->regs.gprs[9] = IPC_ETOOBIG;
208
                return;
209
        }
210
 
211
        /* Now copy the message from the MCB. */
212
        memcpy((void *)task->regs.gprs[2], curmsg->msg, task->regs.gprs[3]);
213
 
214
        /* Remove MCB from task's waiting queue and place it
215
           back into free MCBs queue. */
216
        *linkp = curmsg->next;
217
        curmsg->next = free_mcbs;
218
        free_mcbs = curmsg;
219
 
220
        task->regs.gprs[9] = IPC_NOERR;
221
        return;
222
}
223
 
224
/* Handles all uOS system calls. It is called by low level system call
225
   exception handler. */
226
void kernel_syscall()
227
{
228
        unsigned short syscall_num;
229
 
230
#if KERNEL_OUTPUT
231
        printf("kernel_syscall(): entry number %d, ", ++kernel_syscall_cnt);
232
        printf("current TID=%d, time %u cycles", curtask, timestamp());
233
 
234
        kernel_show_contexts();
235
#endif  
236
        syscall_num = *(unsigned short *)((tasks[curtask].regs.pc & ~0x3) - 6);
237
 
238
        switch(syscall_num) {
239
                case IPC_MSGSND:
240
                        kernel_msgsnd(curtask);
241
                        break;
242
                case IPC_MSGRCV:
243
                        kernel_msgrcv(curtask);
244
                        break;
245
                default:
246
                        printf("kernel_syscall(): unknown syscall (%u)\n", syscall_num);
247
        }
248
 
249
#if KERNEL_SYSCALL_SCHED
250
        kernel_sched();
251
#endif
252
        dispatch();
253
}
254
 
255
/* Called by reset exception handler to initialize the kernel and start
256
   rolling first task. */
257
int kernel_init()
258
{
259
        tid_t t;
260
        int i;
261
 
262
        printf("Initializing kernel:\n");
263
 
264
        printf("  Clearing kernel structures...\n");
265
        memset(tasks, 0, sizeof(tasks));
266
        memset(stacks, 0, sizeof(stacks));
267
        memset(msgs, 0, sizeof(msgs));
268
 
269
        printf("  Initializing MCBs... %d MCB(s)\n", MAX_MSGS);
270
        for(i = 0; i < (MAX_MSGS - 1); i++)
271
                msgs[i].next = &msgs[i+1];
272
        free_mcbs = &msgs[0];
273
 
274
        printf("  Initializing TCBs... %d user task(s)\n", MAX_TASKS);
275
 
276
        tasks_entries();
277
 
278
        for(t = 0; t <= MAX_TASKS; t++) {
279
                tasks[t].regs.sp = (unsigned long)stacks[t] + STACK_SIZE - 4;
280
                /* Disable EXR for kernel context */
281
                tasks[t].regs.sr |= (t == 0 ? SPR_SR_SUPV : SPR_SR_EXR | SPR_SR_EIR);
282
                tasks[t].regs.gprs[1] = t;
283
        }
284
 
285
        /* First task runs in seprvisor mode */
286
        tasks[1].regs.sr |= SPR_SR_SUPV;
287
 
288
        /* TID=0 is reserved for kernel use */
289
        kernel_context = (unsigned long *)&tasks[0].regs;
290
 
291
        /* First task to be scheduled is task TID=1 */
292
        task_context = (unsigned long *)&tasks[1].regs;
293
 
294
        /* Initialize initrrupt controller */
295
        int_init();
296
 
297
        printf("  Exceptions will be enabled when first task is dispatched.\n");
298
        printf("Kernel initalized. Starting first user task.\n");
299
 
300
#if KERNEL_SYSCALL_SCHED
301
        kernel_sched();         /* Lets schedule and dispatch our first task */
302
#else
303
        tick_init(TICK_PERIOD, kernel_sched);
304
        kernel_sched();         /* Lets schedule and dispatch our first task */
305
#endif  
306
        /* ... */               /* We never get here */
307
}
308
 
309
int main ()
310
{
311
  kernel_init();
312
  return 0;
313
}

powered by: WebSVN 2.1.0

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