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

Subversion Repositories openrisc_me

[/] [openrisc/] [tags/] [or1ksim/] [or1ksim-0.4.0/] [testsuite/] [test-code-or1k/] [uos/] [uos.c] - Diff between revs 90 and 135

Only display areas with differences | Details | Blame | View Log

Rev 90 Rev 135
/* uos.c.  Microkernel for Or1ksim
/* uos.c.  Microkernel for Or1ksim
 
 
   Copyright (C) 2000 Damjan Lampret
   Copyright (C) 2000 Damjan Lampret
   Copyright (C) 2010 Embecosm Limited
   Copyright (C) 2010 Embecosm Limited
 
 
   Contributor Damjan Lampret <lampret@opencores.org>
   Contributor Damjan Lampret <lampret@opencores.org>
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
   This file is part of OpenRISC 1000 Architectural Simulator.
   This file is part of OpenRISC 1000 Architectural Simulator.
 
 
   This program is free software; you can redistribute it and/or modify it
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the Free
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 3 of the License, or (at your option)
   Software Foundation; either version 3 of the License, or (at your option)
   any later version.
   any later version.
 
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
   more details.
 
 
   You should have received a copy of the GNU General Public License along
   You should have received a copy of the GNU General Public License along
   with this program.  If not, see <http:  www.gnu.org/licenses/>.  */
   with this program.  If not, see <http:  www.gnu.org/licenses/>.  */
 
 
/* ----------------------------------------------------------------------------
/* ----------------------------------------------------------------------------
   This code is commented throughout for use with Doxygen.
   This code is commented throughout for use with Doxygen.
   --------------------------------------------------------------------------*/
   --------------------------------------------------------------------------*/
 
 
/* This file is part of test microkernel for OpenRISC 1000. */
/* This file is part of test microkernel for OpenRISC 1000. */
 
 
#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. */
void
void
uos_msgsnd(tid_t desttask, char *buf, int len)
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. */
void
void
uos_msgrcv(tid_t origintask, char *buf, int len)
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 *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. */
void
void
kernel_init()
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.