freeRtos中操作pxCurrentTCB部分汇编指令的理解

关于freeRtos中操作pxCurrentTCB部分汇编指令的理解

__asm void vPortSVCHandler( void )
{
/* *INDENT-OFF* */
    PRESERVE8

    ldr r3, = pxCurrentTCB   /* Restore the context. */
    ldr r1, [ r3 ] /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
    ldr r0, [ r1 ]           /* The first item in pxCurrentTCB is the task top of stack. */
    ldmia r0 !, { r4 - r11 } /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
    msr psp, r0 /* Restore the task stack pointer. */
    isb
    mov r0, # 0
    msr basepri, r0
    orr r14, # 0xd
    bx r14
/* *INDENT-ON* */
}

一直对于这些指令莫名的脑袋浆糊,后来用stm32中freertos的demo代码中keil5中做简单的调试,对此感觉有了一点理解,做一下记录,代码还是要动手操练。

   ldr r3, = pxCurrentTCB   /* Restore the context. */

pxCurrentTCB 是个全局的结构体指针变量,这个指令的意思是取 指针变量的地址赋值给 r3
在c语言中,定义一个指针变量,直接对这个指针变量赋值操作,实际编译成汇编文件怎么处理的也不懂,但是在汇编语言中,ldr指令获取的是这个变量的链接地址。

 ldr r1, [ r3 ] /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */

获取pxCurrentTCB的值,比如定义一个int *p, a=100,这条指令意思相当于p=&a

 ldr r0, [ r1 ]           /* The first item in pxCurrentTCB is the task top of stack. */

pxCurrentTCB 是一个结构体指针,r0的值就是获取pxCurrentTCB指向的结构体的第一个元素,即栈顶指针pxTopOfStack,相当于获取*p的值,对于一个结构体变量就是第一项的值。

struct Test{
   int a;
   int b;
   int c;
}
struct Test test;
struct Test *ptest=NULL;
void fun(void)
{
   ptest = &test;
   test.a = 1;
   test b = 2;
   test c = 3;
}
    ldr r3, = pxCurrentTCB   /*  */
    ldr r1, [ r3 ] 			/*  上面一步取的是pxCurrentTCB指针变量的地址,这两步相于  ptest = &test; */
    ldr r0, [ r1 ]          /* 结构体变量中第一个元素的值,即test.a 的值  */

xPortPendSVHandler中的任务切换的实现

__asm void xPortPendSVHandler( void )
{
    extern uxCriticalNesting;
    extern pxCurrentTCB;
    extern vTaskSwitchContext;

/* *INDENT-OFF* */
    PRESERVE8

    mrs r0, psp
    isb

    ldr r3, =pxCurrentTCB /* 获取pxCurrentTCB变量的指针地址 */
    ldr r2, [ r3 ] /* 获取当前正在运行的task的tcb指针 */

    stmdb r0 !, { r4 - r11 } /* 保存现场寄存器压栈 */
    str r0, [ r2 ] /* 保持当前栈的位置到tcb结构体的第一项中 即pxTopOfStack */

    stmdb sp !, { r3, r14 } /* 下面有函数调用,防止r3,r14被更改,先保存到栈中 */
    mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
    msr basepri, r0 /* 屏蔽中断 */
    dsb /* 数据同步 */
    isb /* 指令中断 */
    bl vTaskSwitchContext  /* 进入此函数中查找需要切换到的就绪状态的最高优先级任务 ,然后更新pxCurrentTCB的值 */
    mov r0, #0
    msr basepri, r0 /* 开中断 */
    ldmia sp !, { r3, r14 } /* 恢复r3,r14的值,r3保存的pxCurrentTCB的地址 */

    ldr r1, [ r3 ] /* 获取pxCurrentTCB的值,在vTaskSwitchContext中pxCurrentTCB可能已经被赋予新的值,下面将进入一个新的任务的运行空间 */
    ldr r0, [ r1 ] /* 获取新任务的栈的位置 */
    ldmia r0 !, { r4 - r11 } /* 恢复现场,恢复寄存器的值 */
    msr psp, r0 /* 把当前任务栈的指针赋值给psp寄存器 */
    isb
    bx r14 /* 硬件会自动把PC指针出堆栈(因为此时psp为新任务的堆栈顶指针所以出堆栈也是新任务的寄存器) */
    nop
/* *INDENT-ON* */
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值