int flag;
void cmp_val(int a,int b)
{
volatile int tmp[10];
tmp[0] = a;
if(tmp[0] > b)
{
flag = 1;
}else{
flag = 0;
}
}
int main()
{
int a = 1;
int b = ;
cmp_val(a,b);
return 0;
}
我们写好的程序会保存在Flash上。
其它类似汇编指令
SUB R0,R0,#4 R0 = R0-4
B LR 放入LR寄存器
局部变量保存在栈里。
SUB sp,sp,#0x28 sp=sp-40;
为什么要SP要减去40?数组是int类型,刚好有10个,所以是40。
STR r0,[sp,#0x00] 将r0的值保存进sp指针现在所指向的位置
C语言中的函数,传入的第一个参数就保存在R0中,第二个参数保存在R1中。
LDR r2,[sp,#0x00] 将sp指针现在指向的存储位置的值保存进入r2寄存器中。
CMP r2,r1 比较两个寄存器中的值,结果保存在PSR(程序状态寄存器)中。
BLE 0x08000166 如果比较结果小于等于,就跳转到地址0x08000166
MOVS r2,#0x00 把r2赋值为0
STR r2,[r3,#0x00] 把r2赋值给r3指向的变量(flag)
切换线程时要保存所有寄存器的值。
除了R13,其余都要保存,R13是栈,一般在其它地方中保存。(16个)
16个寄存器保存在栈中。
保存在线程的栈中。
发生Tick中断时,16个寄存器中有一些是硬件直接保存的,剩下的是软件保存。
上下文切换
rt_hw_context_switch((rt_ubase_t)&from_thread->sp, (rt_ubase_t)&to_thread->sp);
.global rt_hw_context_switch_to
.type rt_hw_context_switch_to, %function
rt_hw_context_switch_to:
LDR R1, =rt_interrupt_to_thread
STR R0, [R1]
/* set from thread to 0 */
LDR R1, =rt_interrupt_from_thread
MOV R0, #0
STR R0, [R1]
/* set interrupt flag to 1 */
LDR R1, =rt_thread_switch_interrupt_flag
MOV R0, #1
STR R0, [R1]
/* set the PendSV exception priority */
LDR R0, =SHPR3
LDR R1, =PENDSV_PRI_LOWEST
LDR.W R2, [R0,#0] /* read */
ORR R1, R1, R2 /* modify */
STR R1, [R0] /* write-back */
LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */ //触发一个PendSV异常,异常发生后,异常处理函数就会被调用
LDR R1, =PENDSVSET_BIT
STR R1, [R0]
/* restore MSP */
LDR r0, =SCB_VTOR
LDR r0, [r0]
LDR r0, [r0]
NOP
MSR msp, r0
/* enable interrupts at processor level */
CPSIE F
CPSIE I
利用PendSV异常,来进行任务的切换
PendSV_Handler:
/* disable interrupt to protect context switch */
MRS R2, PRIMASK
CPSID I
/* get rt_thread_switch_interrupt_flag */
LDR R0, =rt_thread_switch_interrupt_flag
LDR R1, [R0]
CBZ R1, pendsv_exit /* pendsv aLReady handled */
/* clear rt_thread_switch_interrupt_flag to 0 */
MOV R1, #0
STR R1, [R0]
LDR R0, =rt_interrupt_from_thread
LDR R1, [R0]
CBZ R1, switch_to_thread /* skip register save at the first time */
MRS R1, PSP /* get from thread stack pointer */ //获取线程A的栈
STMFD R1!, {R4 - R11} /* push R4 - R11 register */ //软件保存剩余寄存器
LDR R0, [R0]
STR R1, [R0] /* update from thread stack pointer */
switch_to_thread:
LDR R1, =rt_interrupt_to_thread
LDR R1, [R1]
LDR R1, [R1] /* load thread stack pointer */ //获取线程B的栈
LDMFD R1!, {R4 - R11} /* pop R4 - R11 register */ //从栈里恢复R4-R11,软件恢复
MSR PSP, R1 /* update stack pointer */
STMFD:Store Multi Full Dec
中断时,硬件保存的寄存器
恢复时,软件恢复一部分寄存器,硬件恢复一部分寄存器。
创建线程时,分配一个栈空间,同时要为栈空间预存放的寄存器空间赋值。将PC寄存器存放的位置赋值为thread2_entry,当线程运行时,将栈空间存放的各个寄存器的值赋值到对应的寄存器,此时CPU就可以开始运行thread2_entry。
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;
unsigned long 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); //stk-64
stack_frame = (struct stack_frame *)stk;
/* init all register */
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
{
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
}
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */ //参数
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */ //函数入口地址
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
/* return task's current stack address */
return stk;
}
首先栈要先减去stack_frame的空间
struct stack_frame
{
/* r4 ~ r11 register */
rt_uint32_t r4;
rt_uint32_t r5;
rt_uint32_t r6;
rt_uint32_t r7;
rt_uint32_t r8;
rt_uint32_t r9;
rt_uint32_t r10;
rt_uint32_t r11;
struct exception_stack_frame exception_stack_frame;
};
struct exception_stack_frame
{
rt_uint32_t r0;
rt_uint32_t r1;
rt_uint32_t r2;
rt_uint32_t r3;
rt_uint32_t r12;
rt_uint32_t lr;
rt_uint32_t pc;
rt_uint32_t psr;
};