zoukankan      html  css  js  c++  java
  • 漫谈LiteOS-LiteOS SDK支持RISC-V架构

    【摘要】 本文首先对RISC-V的架构做了简要的介绍,在此基础上实现了LiteOS在RISC-V架构上的适配过程的具体步骤,希望对你有所帮助。

    1 RISC-V架构简介

    RISC-V是一个基于精简指令集(RISC)原则的开源指令集架构(ISA)。

    与大多数指令集相比,RISC-V指令集可以自由地用于任何目的,允许任何人设计、制造和销售RISC-V芯片和软件而不必支付给任何公司专利费。RISC-V指令集的设计考虑了小型、快速、低功耗的现实情况来实做,但并没有对特定的微架构做过度的设计。

    RISC-V的Spec文档可以在RISC-C官网https://riscv.org/specifications/ 上下载。主要看riscv-privileged.pdf和riscv-spec.pdf。

    主要精读的内容包括:

    RV32ICM Instruction Set

        I:RV32I Base Integer Instruction Set

        C:Standard Extension for Compressed Instructions

        M:Standard Extension for Integer Multiplication and Division

    Privilege Levels

    Control and Status Registers (CSRs)

    Machine-Level ISA

    在了解通用的RV32架构之后,由于RV32是开源的ISA架构,所以实际芯片都会在此基础上做一些定制化,因此需要再读一下芯片手册,LiteOS的RISC-V架构支持使用的芯片是GD32VF103,请下载GD32VF103 的Spec进行阅览。

    2 LiteOS支持一种处理器

    RTOS支持一种新的处理器架构,最主要的修改有以下几个方面:

    1.启动汇编的适配

    2.适配系统调度汇编

    3.Tick的适配

    4.根据芯片设置系统相关参数

    5.适配中断管理模块

    6.编译链接脚本的调整

    那么,对应到LiteOS,主要修改的目录和文件是:

    LiteOS_Labiot_linkosliteosarch iscvsrc中

    los_dispatch.S

    los_hw.c

    los_hw_tick.c

    los_hwi.c

    和对应芯片target目录下的start.S启动汇编以及ld链接脚本。

    步骤如下:

    1. start.S

    A. 和RISC-V的异常中断处理密切相关,注意向量表的对齐

      vector_base:
            j _start
            .align     2
            .word     0
            .word     0
            .word     osInterrupt #eclic_msip_handler
            .word     0
            .word     0
            .word    0
            .word    osInterrupt #eclic_mtip_handler

    B. 设置中断,异常等的入口地址

    _start0800:
        
            /* Set the the NMI base to share with mtvec by setting CSR_MMISC_CTL */
            li t0, 0x200
            csrs CSR_MMISC_CTL, t0
        
            /* Intial the mtvt*/
            la t0, vector_base
            csrw CSR_MTVT, t0
        
            /* Intial the mtvt2 and enable it*/
            la t0, irq_entry
            csrw CSR_MTVT2, t0
            csrs CSR_MTVT2, 0x1
        
            /* Intial the CSR MTVEC for the Trap ane NMI base addr*/
            la t0, trap_entry
            csrw CSR_MTVEC, t0

    C.设置gp,sp,初始化data和bss section,然后跳转到main函数

        .option push
            .option norelax
            la gp, __global_pointer$
            .option pop
            la sp, _sp
        
            /* Load data section */
            la a0, _data_lma
            la a1, _data
            la a2, _edata
            bgeu a1, a2, 2f
        1:
            lw t0, (a0)
            sw t0, (a1)
            addi a0, a0, 4
            addi a1, a1, 4
            bltu a1, a2, 1b
        2:
            /* Clear bss section */
            la a0, __bss_start
            la a1, _end
            bgeu a0, a1, 2f
        1:
            sw zero, (a0)
            addi a0, a0, 4
            bltu a0, a1, 1b

    2. 适配系统调度汇编(los_dispatch.s),主要修改函数LOS_StartToRun、LOS_IntLock、LOS_IntUnLock、TaskSwitch等;

    任务栈的设计,在osTskStackInit中针对RISC-V的寄存器的定义,做出context的设计:

        pstContext->ra = (UINT32)osTaskExit;
        pstContext->sp = 0x02020202L;
        pstContext->gp = 0x03030303L;
        pstContext->tp = 0x04040404L;
        pstContext->t0 = 0x05050505L;
        pstContext->t1 = 0x06060606L;
        pstContext->t2 = 0x07070707L;
        pstContext->s0 = 0x08080808L;
        pstContext->s1 = 0x09090909L;
        pstContext->a0 = pstTaskCB->uwTaskID;         //a0 first argument
        pstContext->a1 = 0x11111111L;
        pstContext->a2 = 0x12121212L;
        pstContext->a3 = 0x13131313L;
        pstContext->a4 = 0x14141414L;
        pstContext->a5 = 0x15151515L;
        pstContext->a6 = 0x16161616L;
        pstContext->a7 = 0x17171717L;
        pstContext->s2 = 0x18181818L;
        pstContext->s3 = 0x19191919L;
        pstContext->s4 = 0x20202020L;
        pstContext->s5 = 0x21212121L;
        pstContext->s6 = 0x22222222L;
        pstContext->s7 = 0x23232323L;
        pstContext->s8 = 0x24242424L;
        pstContext->s9 = 0x25252525L;
        pstContext->s10 = 0x26262626L;
        pstContext->s11 = 0x27272727L;
        pstContext->t3 = 0x28282828L;
        pstContext->t4 = 0x29292929L;
        pstContext->t5 = 0x30303030L;
        pstContext->t6 = 0x31313131L;
        pstContext->mepc =(UINT32)osTaskEntry;

    LOS_IntLock的实现:

      LOS_IntLock:
            csrr    a0, mstatus
            li      t0, 0x08
            csrrc   zero, mstatus, t0
            ret

    LOS_IntUnLock的实现:

    LOS_IntUnLock:
            csrr    a0, mstatus
            li      t0, 0x08
            csrrs   zero, mstatus, t0
            ret

    TaskSwitch的实现:

    TaskSwitch:
            la      t0, g_stLosTask
            lw      t1, 0(t0)
            csrr    t2, mscratch
            sw      t2, 0(t1)
        
            //Clear the task running bit of pstRunTask.
            la      t0, g_stLosTask
            lw      t1, (t0)
            lb      t2, 0x4(t1)
            andi    t2, t2, OS_TASK_STATUS_NOT_RUNNING
            sb      t2, 0x4(t1)
        
            //copy pstNewTask into pstRunTask
            la      t0, g_stLosTask
            lw      t1, 0x4(t0)
            sw      t1, 0x0(t0)
        
            //set the task running bit=1
            lh      t2, 0x4(t1)
            ori     t2, t2, OS_TASK_STATUS_RUNNING
            sh      t2, 0x4(t1)
        
            //retireve stack pointer
            lw      sp, (t1)
        
            //retrieve the address at which exception happened
            lw      t0, 31 * 4(sp)
            csrw    mepc, t0
        
            li     t0, 0x1800
            csrs   mstatus, t0
        
            //retrieve the registers
            lw      ra, 0 * 4(sp)
        
            lw      t0, 4 * 4(sp)
            lw      t1, 5 * 4(sp)
            lw      t2, 6 * 4(sp)
            lw      s0, 7 * 4(sp)
            lw      s1, 8 * 4(sp)
            lw      a0, 9 * 4(sp)
            lw      a1, 10 * 4(sp)
            lw      a2, 11 * 4(sp)
            lw      a3, 12 * 4(sp)
            lw      a4, 13 * 4(sp)
            lw      a5, 14 * 4(sp)
            lw      a6, 15 * 4(sp)
            lw      a7, 16 * 4(sp)
            lw      s2, 17 * 4(sp)
            lw      s3, 18 * 4(sp)
            lw      s4, 19 * 4(sp)
            lw      s5, 20 * 4(sp)
            lw      s6, 21 * 4(sp)
            lw      s7, 22 * 4(sp)
            lw      s8, 23 * 4(sp)
            lw      s9, 24 * 4(sp)
            lw      s10, 25 * 4(sp)
            lw      s11, 26 * 4(sp)
            lw      t3, 27 * 4(sp)
            lw      t4, 28 * 4(sp)
            lw      t5, 29 * 4(sp)
            lw      t6, 30 * 4(sp)
        
            addi    sp, sp, 4 * 32
        
            mret

    3. Tick的适配

    osTickStart的启动:

    MTIMECMP和MTIME寄存器的设定,TIMER中断的使能,TIMER中断处理函数的注册

     LITE_OS_SEC_TEXT_INIT UINT32 osTickStart(VOID)
        {
            UINT32 uwRet;
        
            g_uwCyclesPerTick = OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND;
            g_ullTickCount = 0;
        
            *(UINT64 *)(TIMER_CTRL_ADDR + TIMER_MTIMECMP) = OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND / 4;
        
            *(UINT64 *)(TIMER_CTRL_ADDR + TIMER_MTIME) = 0;
            eclic_irq_enable(CLIC_INT_TMR, 1, 1);
            LOS_HwiCreate(CLIC_INT_TMR, 3, 0, eclic_mtip_handler, 0);
        
            g_bSysTickStart = TRUE;
        
            return LOS_OK;
        }

    4. 根据芯片设置系统相关参数(时钟频率,tick中断配置,los_config.h系统参数配置(内存池大小、信号量、队列、互斥锁,软件定时器数量等));

    根据实际开发板的资源和实际使用需求,配置target_config.h的参数和选项。

    5. 适配中断管理模块,LiteOS的中断向量表由m_pstHwiForm[OS_VECTOR_CNT]数组管理,需要根据芯片配置中断使能,重定向等;

    A.在los_hwi.c和los_hwi.h中根据实际芯片的中断向量数目和驱动做一些调整

    B.在entry.S中设计irq_entry的处理,需要注意的是需要单独在irq stack中处理中断嵌套:

     irq_entry: // -------------> This label will be set to MTVT2 register
            // Allocate the stack space
            
            SAVE_CONTEXT// Save 16 regs
            
            //------This special CSR read operation, which is actually use mcause as operand to directly store it to memory
            csrrwi  x0, CSR_PUSHMCAUSE, 17
            //------This special CSR read operation, which is actually use mepc as operand to directly store it to memory
            csrrwi  x0, CSR_PUSHMEPC, 18
            //------This special CSR read operation, which is actually use Msubm as operand to directly store it to memory
            csrrwi  x0, CSR_PUSHMSUBM, 19
            
            la t0, g_int_cnt
            lw t1, 0(t0)
            addi t1, t1, 1
            sw t1, 0(t0)
            li t2, 1
            bgtu t1,t2,service_loop
            
            csrw mscratch, sp
            la sp, __irq_stack_top

    service_loop:

    //------This special CSR read/write operation, which is actually Claim the CLIC to find its pending highest
            // ID, if the ID is not 0, then automatically enable the mstatus.MIE, and jump to its vector-entry-label, and
            // update the link register 
            csrrw ra, CSR_JALMNXTI, ra 
       
            //RESTORE_CONTEXT_EXCPT_X5
            
            la t0, g_int_cnt
            lw t1, 0(t0)
            addi t1, t1, -1
            sw t1, 0(t0)
            bnez t1, _rfi
            
            csrr sp, mscratch
            
            DISABLE_MIE # Disable interrupts
            
            LOAD x5,  19*REGBYTES(sp)
            csrw CSR_MSUBM, x5
            LOAD x5,  18*REGBYTES(sp)
            csrw CSR_MEPC, x5
            LOAD x5,  17*REGBYTES(sp)
            csrw CSR_MCAUSE, x5
            
            la t0, g_usLosTaskLock
            lw t1, 0(t0)
            bnez t1, _rfi
            
            la      t0, g_stLosTask
            lw      t1, 0x4(t0)
            lw      t2, 0x0(t0)
            beq  t1, t2, _rfi
            
            RESTORE_CONTEXT
            
            push_reg
            csrr t0, mepc
            sw t0, 31*4(sp)
            csrw mscratch, sp
            j TaskSwitch

    _rfi:

    RESTORE_CONTEXT
            // Return to regular code
            mret

    6. 编译链接脚本的调整

    几个关键的设置:

    irq stack内存区域:

     __stack_size = DEFINED(__stack_size) ? __stack_size : 2K;
            __irq_stack_size = DEFINED(__irq_stack_size) ? __irq_stack_size : 2K;
            __heap_size = DEFINED(__heap_size) ? __heap_size : 0xc00;

    gp初始值的设定:gp用于代码的优化,因为请合理选择__global_pointer的初值:

       PROVIDE( __global_pointer$ = . + 0x800);

    堆栈的设定:

      .stack : ALIGN(0x10)
        {
            . += __stack_size;  
            PROVIDE( _sp = . ); 
            . = ALIGN(0x10);
            PROVIDE( __irq_stack_bottom = . );
            . += __irq_stack_size;
            PROVIDE( __irq_stack_top = . );
        } >ram AT>ram 
        
        .heap : ALIGN(0x10)
        {
            PROVIDE( __los_heap_addr_start__ = . );
            . = __heap_size;
            . = __heap_size == 0 ? 0 : ORIGIN(ram) + LENGTH(ram);
            PROVIDE( __los_heap_addr_end__ = . );
            PROVIDE( _heap_end = . );
        } >ram AT>ram

    主要的步骤已经整体讲述了,顺利移植的主要前提条件是对RISC-V处理器架构的全面理解和LiteOS任务调度的设计,所以再次提醒精读riscv-privileged.pdf和riscv-spec.pdf的相关章节。在移植过程中,会遇到很多问题,建议使用IoT Studio的开发调试环境,方便的进行汇编级的单步调试,另外把串口驱动和printf打印调通,也是一种较重要的调试手段。

    作者:星辰27

  • 相关阅读:
    LeetCode 109 Convert Sorted List to Binary Search Tree
    LeetCode 108 Convert Sorted Array to Binary Search Tree
    LeetCode 107. Binary Tree Level Order Traversal II
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 103 Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 104. Maximum Depth of Binary Tree
    接口和多态性
    C# 编码规范
  • 原文地址:https://www.cnblogs.com/2020-zhy-jzoj/p/13164967.html
Copyright © 2011-2022 走看看