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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_47/] [or1ksim/] [testbench/] [uos/] [uos.c] - Blame information for rev 1782

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 1024 simons
                printf("MCB len=%u origintask=%u ", mcb->length, mcb->origin);
60
                printf("msg:%s\n", mcb->msg);
61 222 markom
        }
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 1024 simons
                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[IEE]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_IEE);
74
                printf("SR[TEE]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_TEE);
75
                printf("SR[SM]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_SM);
76 222 markom
                for(i = 1; i < GPRS; i++) {
77
                        if (i % 4 == 0)
78 1024 simons
                                printf("\n");
79
                        printf("r%d=0x%.8x ", i, (unsigned)tasks[t].regs.gprs[i]);
80 222 markom
                }
81 1024 simons
                printf("\n");
82 222 markom
                kernel_show_mcbs(tasks[t].waiting_msgs);
83
        }
84 1024 simons
        printf("\n");
85 222 markom
}
86
 
87
/* Simple round-robin scheduler that directly calls dispatcher. It is
88
   called by low level external interrupt exception handler or by
89
   kernel_syscall if KERNEL_SYSCALL_SCHED is defined. */
90
void kernel_sched()
91
{
92
        if ((++curtask > MAX_TASKS) || !(tasks[curtask].regs.pc & ~0x3))
93
                curtask = 1;
94
        task_context = (unsigned long *)&tasks[curtask].regs;
95
 
96
#if KERNEL_OUTPUT
97 1024 simons
        printf("kernel_sched(): entry number %d, ", ++kernel_sched_cnt);
98
        printf("dispatching task TID=%d, time %u cycles", curtask, timestamp());
99 222 markom
 
100
        kernel_show_contexts();
101
#endif
102
 
103
        dispatch();
104
}
105
 
106
/* System call uos_msgsnd. */
107
int uos_msgsnd(tid_t desttask, char *buf, int len)
108
{
109
        asm("l.sys 1");
110
        asm("l.nop");
111
}
112
 
113
/* System call uos_msgrcv. */
114
int uos_msgrcv(tid_t origintask, char *buf, int len)
115
{
116
        asm("l.sys 2");
117
        asm("l.nop");
118
}
119
 
120
/* Handles system call uos_msgsnd. */
121
void kernel_msgsnd(tid_t tid)
122
{
123
        struct mcb *mcb;
124
        struct mcb **dstmq;
125
        struct tcb *task;
126
 
127
        task = &tasks[tid];
128
 
129
        /* Sanity checks. */
130
 
131
        /* Does destination task exist? */
132
        if (!task->regs.gprs[1] || (task->regs.gprs[1] > MAX_TASKS)) {
133
        task->regs.gprs[9] = IPC_ENOTASK;
134
                return;
135
        }
136
 
137
        /* Are there any free MCBs? */
138
        if (!free_mcbs) {
139
                task->regs.gprs[9] = IPC_EOUTOFMCBS;
140
                return;
141
        }
142
 
143
        /* Is message too big to fit into MCB's message buffer? */
144
        if (task->regs.gprs[3] > MAX_MSGLEN) {
145
                task->regs.gprs[9] = IPC_ETOOBIG;
146
                return;
147
        }
148
 
149
        /* OK, send the message. */
150
 
151
        /* First, allocate MCB. */
152
        mcb = free_mcbs;
153
        free_mcbs = mcb->next;
154
 
155
        /* Second, copy message to the MCB. */
156
        memcpy(mcb->msg, (void *)task->regs.gprs[2], task->regs.gprs[3]);
157
        mcb->origin = tid;
158
        mcb->length = task->regs.gprs[3];
159
        mcb->next = NULL;
160
 
161
        /* Insert MCB into destination task's message queue at
162
           the end. */
163
        dstmq = &tasks[task->regs.gprs[1]].waiting_msgs;
164
        for(;*dstmq;)
165
                dstmq = &((*dstmq)->next);
166
        *dstmq = mcb;
167
 
168
        task->regs.gprs[9] = IPC_NOERR;
169
        return;
170
}
171
 
172
/* Handles system call uos_msgrcv. */
173
void kernel_msgrcv(tid_t tid)
174
{
175
        struct mcb *mcb;
176
        struct mcb *curmsg, **linkp;
177
        struct tcb *task;
178
 
179
        task = &tasks[tid];
180
 
181
        /* Sanity checks. */
182
 
183
        /* Does origin task exist? */
184
        if (task->regs.gprs[1] > MAX_TASKS) {
185
                task->regs.gprs[9] = IPC_ENOTASK;
186
                return;
187
        }
188
 
189
        /* Are there any messages waiting for reception? */
190
        if (!task->waiting_msgs) {
191
                task->regs.gprs[9] = IPC_ENOMSGS;
192
                return;
193
        }
194
 
195
        /* OK, receive the message. */
196
 
197
        /* Search waiting messages for one coming from origintask. If
198
           origintask is zero then grab the first message. */
199
        curmsg = task->waiting_msgs;
200
        linkp = &task->waiting_msgs;
201
        for(;task->regs.gprs[1] && curmsg->next && curmsg->origin != task->regs.gprs[1];) {
202
                linkp = &curmsg->next;
203
                curmsg = curmsg->next;
204
        }
205
 
206
        /* Is receive buffer too small for receiving message? */
207
        if (task->regs.gprs[3] < curmsg->length) {
208
                task->regs.gprs[9] = IPC_ETOOBIG;
209
                return;
210
        }
211
 
212
        /* Now copy the message from the MCB. */
213
        memcpy((void *)task->regs.gprs[2], curmsg->msg, task->regs.gprs[3]);
214
 
215
        /* Remove MCB from task's waiting queue and place it
216
           back into free MCBs queue. */
217
        *linkp = curmsg->next;
218
        curmsg->next = free_mcbs;
219
        free_mcbs = curmsg;
220
 
221
        task->regs.gprs[9] = IPC_NOERR;
222
        return;
223
}
224
 
225
/* Handles all uOS system calls. It is called by low level system call
226
   exception handler. */
227
void kernel_syscall()
228
{
229
        unsigned short syscall_num;
230
 
231
#if KERNEL_OUTPUT
232 1024 simons
        printf("kernel_syscall(): entry number %d, ", ++kernel_syscall_cnt);
233
        printf("current TID=%d, time %u cycles", curtask, timestamp());
234 222 markom
 
235
        kernel_show_contexts();
236
#endif  
237
        syscall_num = *(unsigned short *)((tasks[curtask].regs.pc & ~0x3) - 6);
238
 
239
        switch(syscall_num) {
240
                case IPC_MSGSND:
241
                        kernel_msgsnd(curtask);
242
                        break;
243
                case IPC_MSGRCV:
244
                        kernel_msgrcv(curtask);
245
                        break;
246
                default:
247 1024 simons
                        printf("kernel_syscall(): unknown syscall (%u)\n", syscall_num);
248 222 markom
        }
249
 
250
#if KERNEL_SYSCALL_SCHED
251
        kernel_sched();
252
#endif
253
        dispatch();
254
}
255
 
256
/* Called by reset exception handler to initialize the kernel and start
257
   rolling first task. */
258
int kernel_init()
259
{
260
        tid_t t;
261
        int i;
262
 
263 1024 simons
        printf("Initializing kernel:\n");
264 222 markom
 
265 1024 simons
        printf("  Clearing kernel structures...\n");
266 222 markom
        memset(tasks, 0, sizeof(tasks));
267
        memset(stacks, 0, sizeof(stacks));
268
        memset(msgs, 0, sizeof(msgs));
269
 
270 1024 simons
        printf("  Initializing MCBs... %d MCB(s)\n", MAX_MSGS);
271 222 markom
        for(i = 0; i < (MAX_MSGS - 1); i++)
272
                msgs[i].next = &msgs[i+1];
273
        free_mcbs = &msgs[0];
274
 
275 1024 simons
        printf("  Initializing TCBs... %d user task(s)\n", MAX_TASKS);
276 222 markom
 
277
        tasks_entries();
278
 
279
        for(t = 0; t <= MAX_TASKS; t++) {
280
                tasks[t].regs.sp = (unsigned long)stacks[t] + STACK_SIZE - 4;
281
                /* Disable EXR for kernel context */
282 600 simons
                tasks[t].regs.sr |= (t == 0 ? SPR_SR_SM : SPR_SR_TEE | SPR_SR_IEE);
283 222 markom
                tasks[t].regs.gprs[1] = t;
284
        }
285
 
286
        /* First task runs in seprvisor mode */
287 600 simons
        tasks[1].regs.sr |= SPR_SR_SM;
288 222 markom
 
289
        /* TID=0 is reserved for kernel use */
290
        kernel_context = (unsigned long *)&tasks[0].regs;
291
 
292
        /* First task to be scheduled is task TID=1 */
293
        task_context = (unsigned long *)&tasks[1].regs;
294
 
295
        /* Initialize initrrupt controller */
296
        int_init();
297
 
298 1024 simons
        printf("  Exceptions will be enabled when first task is dispatched.\n");
299
        printf("Kernel initalized. Starting first user task.\n");
300 222 markom
 
301
#if KERNEL_SYSCALL_SCHED
302
        kernel_sched();         /* Lets schedule and dispatch our first task */
303
#else
304
        tick_init(TICK_PERIOD, kernel_sched);
305
        kernel_sched();         /* Lets schedule and dispatch our first task */
306
#endif  
307
        /* ... */               /* We never get here */
308
}
309
 
310
int main ()
311
{
312
  kernel_init();
313
  return 0;
314
}

powered by: WebSVN 2.1.0

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