/*
 * File      : cpuport.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2012, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE
 *
 * Change Logs:
 * Date         Author      Notes
 * 2012-02-13   mojingxian  first version
 */

#include <rtthread.h>

/* flag in interrupt handling */
rt_uint32_t rt_interrupt_from_thread;
rt_uint32_t rt_interrupt_to_thread;
rt_uint32_t rt_thread_switch_interrupt_flag;

/**
 * initializes stack of thread
 */
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
    rt_uint8_t *stack_addr, void *texit)
{
    unsigned char i;
    unsigned long *stk;

    stk    = (unsigned long *)stack_addr;     /* Load stack pointer                                    */

                                              /* Simulate a function call to the task with an argument */
    stk   -= 3;                               /* 3 words assigned for incoming args (R0, R1, R2)       */

                                              /* Now simulating vectoring to an ISR                    */
    *--stk = (unsigned long)parameter;        /* R0 value - caller's incoming argument #1              */
    *--stk = (unsigned long)0;                /* P1 value - value irrelevant                           */

    *--stk = (unsigned long)texit;            /* RETS value - NO task should return with RTS.          */
                                              /* however OS_CPU_Invalid_Task_Return is a safety        */
                                              /* catch-allfor tasks that return with an RTS            */

    *--stk = (unsigned long)parameter;        /* R1 value - caller's incoming argument #2              */
                                              /* (not relevant in current test example)                */
    *--stk = (unsigned long)parameter;        /* R2 value - caller's incoming argument #3              */
                                              /* (not relevant in current test example)                */
    *--stk = (unsigned long)0;                /* P0 value - value irrelevant                           */
    *--stk = (unsigned long)0;                /* P2 value - value irrelevant                           */
    *--stk = (unsigned long)0;                /* ASTAT value - caller's ASTAT value - value            */
                                              /* irrelevant                                            */

    *--stk = (unsigned long)tentry;           /* RETI value- pushing the start address of the task     */

    for (i = 0; i < 35; i++)                  /* remaining reg values - R7:3, P5:3,                    */
    {                                         /* 4 words of A1:0(.W,.X), LT0, LT1,                     */
        *--stk = (unsigned long)0;            /* LC0, LC1, LB0, LB1,I3:0, M3:0, L3:0, B3:0,            */
    }                                         /* All values irrelevant                                 */

    return (rt_uint8_t *)stk;                 /* Return top-of-stack                                   */
}

void rt_hw_context_switch(rt_uint32_t from, rt_uint32_t to)
{
    if (rt_thread_switch_interrupt_flag != 1)
    {
        rt_thread_switch_interrupt_flag = 1;
        rt_interrupt_from_thread = from;
    }

    rt_interrupt_to_thread = to;
    asm("raise 14;");                     // Raise Interrupt 14 (trap)
}

void rt_hw_context_switch_interrupt(rt_uint32_t from, rt_uint32_t to)
{
    if (rt_thread_switch_interrupt_flag != 1)
    {
        rt_thread_switch_interrupt_flag = 1;
        rt_interrupt_from_thread = from;
    }

    rt_interrupt_to_thread = to;
    asm("raise 14;");                     // Raise Interrupt 14 (trap)
}

void rt_hw_context_switch_to(rt_uint32_t to)
{
    rt_thread_switch_interrupt_flag = 1;
    rt_interrupt_from_thread = 0;
    rt_interrupt_to_thread = to;
    asm("raise 14;");                     // Raise Interrupt 14 (trap)
}