/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017-07-31     tanek        first implementation
 */

#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;

struct stack_frame
{
    rt_ubase_t epc;     /* epc - epc    - program counter                     */
    rt_ubase_t ra;      /* x1  - ra     - return address for jumps            */
    rt_ubase_t mstatus; /*              - machine status register             */
    rt_ubase_t gp;      /* x3  - gp     - global pointer                      */
    rt_ubase_t tp;      /* x4  - tp     - thread pointer                      */
    rt_ubase_t t0;      /* x5  - t0     - temporary register 0                */
    rt_ubase_t t1;      /* x6  - t1     - temporary register 1                */
    rt_ubase_t t2;      /* x7  - t2     - temporary register 2                */
    rt_ubase_t s0_fp;   /* x8  - s0/fp  - saved register 0 or frame pointer   */
    rt_ubase_t s1;      /* x9  - s1     - saved register 1                    */
    rt_ubase_t a0;      /* x10 - a0     - return value or function argument 0 */
    rt_ubase_t a1;      /* x11 - a1     - return value or function argument 1 */
    rt_ubase_t a2;      /* x12 - a2     - function argument 2                 */
    rt_ubase_t a3;      /* x13 - a3     - function argument 3                 */
    rt_ubase_t a4;      /* x14 - a4     - function argument 4                 */
    rt_ubase_t a5;      /* x15 - a5     - function argument 5                 */
    rt_ubase_t a6;      /* x16 - a6     - function argument 6                 */
    rt_ubase_t a7;      /* x17 - s7     - function argument 7                 */
    rt_ubase_t s2;      /* x18 - s2     - saved register 2                    */
    rt_ubase_t s3;      /* x19 - s3     - saved register 3                    */
    rt_ubase_t s4;      /* x20 - s4     - saved register 4                    */
    rt_ubase_t s5;      /* x21 - s5     - saved register 5                    */
    rt_ubase_t s6;      /* x22 - s6     - saved register 6                    */
    rt_ubase_t s7;      /* x23 - s7     - saved register 7                    */
    rt_ubase_t s8;      /* x24 - s8     - saved register 8                    */
    rt_ubase_t s9;      /* x25 - s9     - saved register 9                    */
    rt_ubase_t s10;     /* x26 - s10    - saved register 10                   */
    rt_ubase_t s11;     /* x27 - s11    - saved register 11                   */
    rt_ubase_t t3;      /* x28 - t3     - temporary register 3                */
    rt_ubase_t t4;      /* x29 - t4     - temporary register 4                */
    rt_ubase_t t5;      /* x30 - t5     - temporary register 5                */
    rt_ubase_t t6;      /* x31 - t6     - temporary register 6                */
};

/**
 * This function will initialize thread stack
 *
 * @param tentry the entry of thread
 * @param parameter the parameter of entry
 * @param stack_addr the beginning stack address
 * @param texit the function will be called when thread exit
 *
 * @return stack address
 */
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
                             rt_uint8_t *stack_addr, void *texit)
{
    struct stack_frame *stack_frame;
    rt_uint8_t         *stk;
    int                 i;

    stk  = stack_addr + sizeof(rt_uint32_t);
    stk  = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
    stk -= sizeof(struct stack_frame);

    stack_frame = (struct stack_frame *)stk;

    for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_ubase_t); i++)
    {
        ((rt_ubase_t *)stack_frame)[i] = 0xdeadbeef;
    }

    stack_frame->ra  = (rt_ubase_t)texit;
    stack_frame->a0  = (rt_ubase_t)parameter;
    stack_frame->epc = (rt_ubase_t)tentry;

    // force to machine mode(MPP=11) and set MPIE to 1
    stack_frame->mstatus = 0x00001880;

    return stk;
}
