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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_47/] [or1ksim/] [testbench/] [uos/] [uos.c] - Diff between revs 1024 and 1419

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 1024 Rev 1419
/* This file is part of test microkernel for OpenRISC 1000. */
/* This file is part of test microkernel for OpenRISC 1000. */
/* (C) 2000 Damjan Lampret, lampret@opencores.org */
/* (C) 2000 Damjan Lampret, lampret@opencores.org */
 
 
#include "support.h"
#include "support.h"
#include "spr_defs.h"
#include "spr_defs.h"
#include "uos.h"
#include "uos.h"
#include "ipc.h"
#include "ipc.h"
#include "int.h"
#include "int.h"
 
 
/* External functions prototypes */
/* External functions prototypes */
int tick_init(unsigned long period, void (* inf)(void));
int tick_init(unsigned long period, void (* inf)(void));
 
 
/* Pointers to contexts used by except_or32.S routines */
/* Pointers to contexts used by except_or32.S routines */
unsigned long *task_context;
unsigned long *task_context;
unsigned long *kernel_context;
unsigned long *kernel_context;
 
 
/* TCBs for all tasks in the system */
/* TCBs for all tasks in the system */
struct tcb tasks[MAX_TASKS+1];
struct tcb tasks[MAX_TASKS+1];
 
 
/* Stacks for the tasks (stacks[0] is kernel stack) */
/* Stacks for the tasks (stacks[0] is kernel stack) */
unsigned char stacks[MAX_TASKS+1][STACK_SIZE];
unsigned char stacks[MAX_TASKS+1][STACK_SIZE];
 
 
/* MCBs for IPC messages */
/* MCBs for IPC messages */
struct mcb msgs[MAX_MSGS];
struct mcb msgs[MAX_MSGS];
 
 
/* Pointer to linked list of free MCBs. */
/* Pointer to linked list of free MCBs. */
struct mcb *free_mcbs;
struct mcb *free_mcbs;
 
 
/* TID of the current user task */
/* TID of the current user task */
tid_t curtask = 0;
tid_t curtask = 0;
 
 
/* Statistics */
/* Statistics */
int kernel_sched_cnt = 0;
int kernel_sched_cnt = 0;
int kernel_syscall_cnt = 0;
int kernel_syscall_cnt = 0;
 
 
/* Timestamp via or1ksim (CPU cycle number). */
/* Timestamp via or1ksim (CPU cycle number). */
unsigned long timestamp()
unsigned long timestamp()
{
{
        register unsigned long cycles asm("r3");
        register unsigned long cycles asm("r3");
        asm("l.sys 201");
        asm("l.sys 201");
        return cycles;
        return cycles;
}
}
 
 
/* Standard function for filling memory with a constant byte. */
/* Standard function for filling memory with a constant byte. */
void *memset(void *dst, int c, size_t size)
void *memset(void *dst, int c, size_t size)
{
{
        char *tmp = dst;
        char *tmp = dst;
 
 
        for(;tmp && (tmp < (char *)dst + size); tmp++)
        for(;tmp && (tmp < (char *)dst + size); tmp++)
                *(char *)tmp = (char)c;
                *(char *)tmp = (char)c;
 
 
        return dst;
        return dst;
}
}
 
 
/* Traverse linked list of MCBs and show individual messages. */
/* Traverse linked list of MCBs and show individual messages. */
void kernel_show_mcbs(struct mcb *mcb)
void kernel_show_mcbs(struct mcb *mcb)
{
{
        for(;mcb; mcb = mcb->next) {
        for(;mcb; mcb = mcb->next) {
                printf("MCB len=%u origintask=%u ", mcb->length, mcb->origin);
                printf("MCB len=%u origintask=%u ", mcb->length, mcb->origin);
                printf("msg:%s\n", mcb->msg);
                printf("msg:%s\n", mcb->msg);
        }
        }
}
}
 
 
/* Show all contexts. */
/* Show all contexts. */
void kernel_show_contexts()
void kernel_show_contexts()
{
{
        int i;
        int i;
        tid_t t;
        tid_t t;
 
 
        for(t = 1; t <= MAX_TASKS; t++) {
        for(t = 1; t <= MAX_TASKS; t++) {
                printf("\ntask TID=%d: PC=0x%x ", t, (unsigned)tasks[t].regs.pc & ~0x3);
                printf("\ntask TID=%d: PC=0x%x ", t, (unsigned)tasks[t].regs.pc & ~0x3);
                printf("SP(r1)=0x%x ", (unsigned)tasks[t].regs.sp);
                printf("SP(r1)=0x%x ", (unsigned)tasks[t].regs.sp);
                printf("SR[IEE]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_IEE);
                printf("SR[IEE]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_IEE);
                printf("SR[TEE]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_TEE);
                printf("SR[TEE]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_TEE);
                printf("SR[SM]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_SM);
                printf("SR[SM]=%d\n", (unsigned)tasks[t].regs.sr & SPR_SR_SM);
                for(i = 1; i < GPRS; i++) {
                for(i = 1; i < GPRS; i++) {
                        if (i % 4 == 0)
                        if (i % 4 == 0)
                                printf("\n");
                                printf("\n");
                        printf("r%d=0x%.8x ", i, (unsigned)tasks[t].regs.gprs[i]);
                        printf("r%d=0x%.8x ", i, (unsigned)tasks[t].regs.gprs[i]);
                }
                }
                printf("\n");
                printf("\n");
                kernel_show_mcbs(tasks[t].waiting_msgs);
                kernel_show_mcbs(tasks[t].waiting_msgs);
        }
        }
        printf("\n");
        printf("\n");
}
}
 
 
/* Simple round-robin scheduler that directly calls dispatcher. It is
/* Simple round-robin scheduler that directly calls dispatcher. It is
   called by low level external interrupt exception handler or by
   called by low level external interrupt exception handler or by
   kernel_syscall if KERNEL_SYSCALL_SCHED is defined. */
   kernel_syscall if KERNEL_SYSCALL_SCHED is defined. */
void kernel_sched()
void kernel_sched()
{
{
        if ((++curtask > MAX_TASKS) || !(tasks[curtask].regs.pc & ~0x3))
        if ((++curtask > MAX_TASKS) || !(tasks[curtask].regs.pc & ~0x3))
                curtask = 1;
                curtask = 1;
        task_context = (unsigned long *)&tasks[curtask].regs;
        task_context = (unsigned long *)&tasks[curtask].regs;
 
 
#if KERNEL_OUTPUT
#if KERNEL_OUTPUT
        printf("kernel_sched(): entry number %d, ", ++kernel_sched_cnt);
        printf("kernel_sched(): entry number %d, ", ++kernel_sched_cnt);
        printf("dispatching task TID=%d, time %u cycles", curtask, timestamp());
        printf("dispatching task TID=%d, time %u cycles", curtask, timestamp());
 
 
        kernel_show_contexts();
        kernel_show_contexts();
#endif
#endif
 
 
        dispatch();
        dispatch();
}
}
 
 
/* System call uos_msgsnd. */
/* System call uos_msgsnd. */
int uos_msgsnd(tid_t desttask, char *buf, int len)
int uos_msgsnd(tid_t desttask, char *buf, int len)
{
{
        asm("l.sys 1");
        asm("l.sys 1");
        asm("l.nop");
        asm("l.nop");
}
}
 
 
/* System call uos_msgrcv. */
/* System call uos_msgrcv. */
int uos_msgrcv(tid_t origintask, char *buf, int len)
int uos_msgrcv(tid_t origintask, char *buf, int len)
{
{
        asm("l.sys 2");
        asm("l.sys 2");
        asm("l.nop");
        asm("l.nop");
}
}
 
 
/* Handles system call uos_msgsnd. */
/* Handles system call uos_msgsnd. */
void kernel_msgsnd(tid_t tid)
void kernel_msgsnd(tid_t tid)
{
{
        struct mcb *mcb;
        struct mcb *mcb;
        struct mcb **dstmq;
        struct mcb **dstmq;
        struct tcb *task;
        struct tcb *task;
 
 
        task = &tasks[tid];
        task = &tasks[tid];
 
 
        /* Sanity checks. */
        /* Sanity checks. */
 
 
        /* Does destination task exist? */
        /* Does destination task exist? */
        if (!task->regs.gprs[1] || (task->regs.gprs[1] > MAX_TASKS)) {
        if (!task->regs.gprs[1] || (task->regs.gprs[1] > MAX_TASKS)) {
        task->regs.gprs[9] = IPC_ENOTASK;
        task->regs.gprs[9] = IPC_ENOTASK;
                return;
                return;
        }
        }
 
 
        /* Are there any free MCBs? */
        /* Are there any free MCBs? */
        if (!free_mcbs) {
        if (!free_mcbs) {
                task->regs.gprs[9] = IPC_EOUTOFMCBS;
                task->regs.gprs[9] = IPC_EOUTOFMCBS;
                return;
                return;
        }
        }
 
 
        /* Is message too big to fit into MCB's message buffer? */
        /* Is message too big to fit into MCB's message buffer? */
        if (task->regs.gprs[3] > MAX_MSGLEN) {
        if (task->regs.gprs[3] > MAX_MSGLEN) {
                task->regs.gprs[9] = IPC_ETOOBIG;
                task->regs.gprs[9] = IPC_ETOOBIG;
                return;
                return;
        }
        }
 
 
        /* OK, send the message. */
        /* OK, send the message. */
 
 
        /* First, allocate MCB. */
        /* First, allocate MCB. */
        mcb = free_mcbs;
        mcb = free_mcbs;
        free_mcbs = mcb->next;
        free_mcbs = mcb->next;
 
 
        /* Second, copy message to the MCB. */
        /* Second, copy message to the MCB. */
        memcpy(mcb->msg, (void *)task->regs.gprs[2], task->regs.gprs[3]);
        memcpy(mcb->msg, (void *)task->regs.gprs[2], task->regs.gprs[3]);
        mcb->origin = tid;
        mcb->origin = tid;
        mcb->length = task->regs.gprs[3];
        mcb->length = task->regs.gprs[3];
        mcb->next = NULL;
        mcb->next = NULL;
 
 
        /* Insert MCB into destination task's message queue at
        /* Insert MCB into destination task's message queue at
           the end. */
           the end. */
        dstmq = &tasks[task->regs.gprs[1]].waiting_msgs;
        dstmq = &tasks[task->regs.gprs[1]].waiting_msgs;
        for(;*dstmq;)
        for(;*dstmq;)
                dstmq = &((*dstmq)->next);
                dstmq = &((*dstmq)->next);
        *dstmq = mcb;
        *dstmq = mcb;
 
 
        task->regs.gprs[9] = IPC_NOERR;
        task->regs.gprs[9] = IPC_NOERR;
        return;
        return;
}
}
 
 
/* Handles system call uos_msgrcv. */
/* Handles system call uos_msgrcv. */
void kernel_msgrcv(tid_t tid)
void kernel_msgrcv(tid_t tid)
{
{
        struct mcb *mcb;
        struct mcb *mcb;
        struct mcb *curmsg, **linkp;
        struct mcb *curmsg, **linkp;
        struct tcb *task;
        struct tcb *task;
 
 
        task = &tasks[tid];
        task = &tasks[tid];
 
 
        /* Sanity checks. */
        /* Sanity checks. */
 
 
        /* Does origin task exist? */
        /* Does origin task exist? */
        if (task->regs.gprs[1] > MAX_TASKS) {
        if (task->regs.gprs[1] > MAX_TASKS) {
                task->regs.gprs[9] = IPC_ENOTASK;
                task->regs.gprs[9] = IPC_ENOTASK;
                return;
                return;
        }
        }
 
 
        /* Are there any messages waiting for reception? */
        /* Are there any messages waiting for reception? */
        if (!task->waiting_msgs) {
        if (!task->waiting_msgs) {
                task->regs.gprs[9] = IPC_ENOMSGS;
                task->regs.gprs[9] = IPC_ENOMSGS;
                return;
                return;
        }
        }
 
 
        /* OK, receive the message. */
        /* OK, receive the message. */
 
 
        /* Search waiting messages for one coming from origintask. If
        /* Search waiting messages for one coming from origintask. If
           origintask is zero then grab the first message. */
           origintask is zero then grab the first message. */
        curmsg = task->waiting_msgs;
        curmsg = task->waiting_msgs;
        linkp = &task->waiting_msgs;
        linkp = &task->waiting_msgs;
        for(;task->regs.gprs[1] && curmsg->next && curmsg->origin != task->regs.gprs[1];) {
        for(;task->regs.gprs[1] && curmsg->next && curmsg->origin != task->regs.gprs[1];) {
                linkp = &curmsg->next;
                linkp = &curmsg->next;
                curmsg = curmsg->next;
                curmsg = curmsg->next;
        }
        }
 
 
        /* Is receive buffer too small for receiving message? */
        /* Is receive buffer too small for receiving message? */
        if (task->regs.gprs[3] < curmsg->length) {
        if (task->regs.gprs[3] < curmsg->length) {
                task->regs.gprs[9] = IPC_ETOOBIG;
                task->regs.gprs[9] = IPC_ETOOBIG;
                return;
                return;
        }
        }
 
 
        /* Now copy the message from the MCB. */
        /* Now copy the message from the MCB. */
        memcpy((void *)task->regs.gprs[2], curmsg->msg, task->regs.gprs[3]);
        memcpy((void *)task->regs.gprs[2], curmsg->msg, task->regs.gprs[3]);
 
 
        /* Remove MCB from task's waiting queue and place it
        /* Remove MCB from task's waiting queue and place it
           back into free MCBs queue. */
           back into free MCBs queue. */
        *linkp = curmsg->next;
        *linkp = curmsg->next;
        curmsg->next = free_mcbs;
        curmsg->next = free_mcbs;
        free_mcbs = curmsg;
        free_mcbs = curmsg;
 
 
        task->regs.gprs[9] = IPC_NOERR;
        task->regs.gprs[9] = IPC_NOERR;
        return;
        return;
}
}
 
 
/* Handles all uOS system calls. It is called by low level system call
/* Handles all uOS system calls. It is called by low level system call
   exception handler. */
   exception handler. */
void kernel_syscall()
void kernel_syscall()
{
{
        unsigned short syscall_num;
        unsigned short syscall_num;
 
 
#if KERNEL_OUTPUT
#if KERNEL_OUTPUT
        printf("kernel_syscall(): entry number %d, ", ++kernel_syscall_cnt);
        printf("kernel_syscall(): entry number %d, ", ++kernel_syscall_cnt);
        printf("current TID=%d, time %u cycles", curtask, timestamp());
        printf("current TID=%d, time %u cycles", curtask, timestamp());
 
 
        kernel_show_contexts();
        kernel_show_contexts();
#endif  
#endif  
        syscall_num = *(unsigned short *)((tasks[curtask].regs.pc & ~0x3) - 6);
        syscall_num = *(unsigned short *)((tasks[curtask].regs.pc & ~0x3) - 6);
 
 
        switch(syscall_num) {
        switch(syscall_num) {
                case IPC_MSGSND:
                case IPC_MSGSND:
                        kernel_msgsnd(curtask);
                        kernel_msgsnd(curtask);
                        break;
                        break;
                case IPC_MSGRCV:
                case IPC_MSGRCV:
                        kernel_msgrcv(curtask);
                        kernel_msgrcv(curtask);
                        break;
                        break;
                default:
                default:
                        printf("kernel_syscall(): unknown syscall (%u)\n", syscall_num);
                        printf("kernel_syscall(): unknown syscall (%u)\n", syscall_num);
        }
        }
 
 
#if KERNEL_SYSCALL_SCHED
#if KERNEL_SYSCALL_SCHED
        kernel_sched();
        kernel_sched();
#endif
#endif
        dispatch();
        dispatch();
}
}
 
 
/* Called by reset exception handler to initialize the kernel and start
/* Called by reset exception handler to initialize the kernel and start
   rolling first task. */
   rolling first task. */
int kernel_init()
int kernel_init()
{
{
        tid_t t;
        tid_t t;
        int i;
        int i;
 
 
        printf("Initializing kernel:\n");
        printf("Initializing kernel:\n");
 
 
        printf("  Clearing kernel structures...\n");
        printf("  Clearing kernel structures...\n");
        memset(tasks, 0, sizeof(tasks));
        memset(tasks, 0, sizeof(tasks));
        memset(stacks, 0, sizeof(stacks));
        memset(stacks, 0, sizeof(stacks));
        memset(msgs, 0, sizeof(msgs));
        memset(msgs, 0, sizeof(msgs));
 
 
        printf("  Initializing MCBs... %d MCB(s)\n", MAX_MSGS);
        printf("  Initializing MCBs... %d MCB(s)\n", MAX_MSGS);
        for(i = 0; i < (MAX_MSGS - 1); i++)
        for(i = 0; i < (MAX_MSGS - 1); i++)
                msgs[i].next = &msgs[i+1];
                msgs[i].next = &msgs[i+1];
        free_mcbs = &msgs[0];
        free_mcbs = &msgs[0];
 
 
        printf("  Initializing TCBs... %d user task(s)\n", MAX_TASKS);
        printf("  Initializing TCBs... %d user task(s)\n", MAX_TASKS);
 
 
        tasks_entries();
        tasks_entries();
 
 
        for(t = 0; t <= MAX_TASKS; t++) {
        for(t = 0; t <= MAX_TASKS; t++) {
                tasks[t].regs.sp = (unsigned long)stacks[t] + STACK_SIZE - 4;
                tasks[t].regs.sp = (unsigned long)stacks[t] + STACK_SIZE - 4;
                /* Disable EXR for kernel context */
                /* Disable EXR for kernel context */
                tasks[t].regs.sr |= (t == 0 ? SPR_SR_SM : SPR_SR_TEE | SPR_SR_IEE);
                tasks[t].regs.sr |= (t == 0 ? SPR_SR_SM : SPR_SR_TEE | SPR_SR_IEE);
                tasks[t].regs.gprs[1] = t;
                tasks[t].regs.gprs[1] = t;
        }
        }
 
 
        /* First task runs in seprvisor mode */
        /* First task runs in seprvisor mode */
        tasks[1].regs.sr |= SPR_SR_SM;
        tasks[1].regs.sr |= SPR_SR_SM;
 
 
        /* TID=0 is reserved for kernel use */
        /* TID=0 is reserved for kernel use */
        kernel_context = (unsigned long *)&tasks[0].regs;
        kernel_context = (unsigned long *)&tasks[0].regs;
 
 
        /* First task to be scheduled is task TID=1 */
        /* First task to be scheduled is task TID=1 */
        task_context = (unsigned long *)&tasks[1].regs;
        task_context = (unsigned long *)&tasks[1].regs;
 
 
        /* Initialize initrrupt controller */
        /* Initialize initrrupt controller */
        int_init();
        int_init();
 
 
        printf("  Exceptions will be enabled when first task is dispatched.\n");
        printf("  Exceptions will be enabled when first task is dispatched.\n");
        printf("Kernel initalized. Starting first user task.\n");
        printf("Kernel initalized. Starting first user task.\n");
 
 
#if KERNEL_SYSCALL_SCHED
#if KERNEL_SYSCALL_SCHED
        kernel_sched();         /* Lets schedule and dispatch our first task */
        kernel_sched();         /* Lets schedule and dispatch our first task */
#else
#else
        tick_init(TICK_PERIOD, kernel_sched);
        tick_init(TICK_PERIOD, kernel_sched);
        kernel_sched();         /* Lets schedule and dispatch our first task */
        kernel_sched();         /* Lets schedule and dispatch our first task */
#endif  
#endif  
        /* ... */               /* We never get here */
        /* ... */               /* We never get here */
}
}
 
 
int main ()
int main ()
{
{
  kernel_init();
  kernel_init();
  return 0;
  return 0;
}
}
 
 

powered by: WebSVN 2.1.0

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