最近大家都在嚷看不懂菜高手的虫子,高手心中有乾坤,理解能力强,自然不需要注释和说明;而低手总是诚惶诚恐,一怕老师说看不懂,二怕程序以后出问题,自己都看不懂。我贴一段低手写的代码,大家看看能看懂不。 uint32_t __calculate_DDR_size(struct st_DBX_flash_tag *DBX_flash_tag) { uint32_t size,blocks,fill,flash_MAT; uint64_t u64i; struct flash_chip *chip = DBX_flash_tag->chip; //下面计算1份DDR表尺寸,方法参见本文件开头部分的说明 //粗算DDR表尺寸,可能是小数 size = 4 //ADB磨损次数基数 + 2*DBX_flash_tag->block_sum //ART磨损次数表 + 4 //FDS,fdt表首块块号 + 4*2*DBX_flash_tag->block_sum; //mat表 //下式乘法可能造成32位整数溢出,故用64位整数 u64i = chip->block_size * size + 4 * (chip->block_size-1); size = (uint32_t)(u64i / (chip->block_size-4)); //上式得到的result可能会比实际需要多(0~3),下面调整之 size = align_down_4(size); if(size > chip->block_size) //超过1块,需考虑单个条目越块边界问题 {//DDR表任意一个单项的任意一个条目不能跨块边界,下面调整之。 //调整的过程中可能引起DDR_size变化,并连带引起DBL表长度变化 //1、DBL表的起始偏移为0,表项固定为4字节,故无论DBL表占多少块, // 肯定不会有跨边界的项。 //2、DBL表结束于4字节对齐地址,FDSB不可能跨边界。 //2、FDSB结束于4字节对齐地址,磨损次数基数不可能跨边界。 //3、磨损次数基数结束于4字节对齐地址,磨损次数表不可能跨界 //4、磨损次数表结束于字节对齐地址,而MAT要求8字节对齐,故需要调整。 blocks = (size +chip->block_size -1 ) / chip->block_size; //块数 flash_MAT = 4*blocks //DBL + 4 + 4 //ARB+FDSB + 2*DBX_flash_tag->block_sum; //ART fill = align_up_8(flash_MAT) - flash_MAT; //算对齐损耗 if((fill + size)/chip->block_size != size/chip->block_size) {//因调整增加了块数 size += fill; if(fill < 4) //对齐留下的空位不够一个DBL项 size = size + 8; }else { size += fill; } } return size; }
再来段汇编的 @----中断中的上下文切换------------------------------------------------------- @功能: 保存被中断线程的上下文,切换到新线程的上下文中继续执行。本函数虽然在中 @ 断服务函数(非用户用int_isr_connect函数连接的中断服务函数)中,但在ARM @ 中,却运行在svc态 @参数: new_sp,新上下文的栈指针 @参数: old_sp,被中断线程的上下文的栈指针的指针,即&vm->stack。无需提供旧上下 @ 文栈指针,sp寄存器的当前值就是 @返回: 无 @函数原型: void __asm_switch_context_int(void *new_sp,void **old_sp); @----------------------------------------------------------------------------- .global __asm_switch_context_int __asm_switch_context_int: stmfd sp!,{r2-r12,lr} @保存正在服务的中断上下文
@以下几行把需要换出的上下文从正在服务的中断栈顶转移到虚拟机栈中 ldr r2,=IRQ_stack @取irq栈基址,这里存放着被中断线程的上下文 @ mov r11,sp ldmea r2!,{r3-r10} @按递增式空栈方式弹栈,结果: @[r2-1]=LR_irq->r10,被中断线程的PC+4 @[r2-2]=r12->r9,被中断线程的r12 @[r2-3]=r11->r8,被中断线程的PC @....... @[r2-8]=r6->r3,被中断线程的r6 sub r10,r10,#4 @中断栈中的LR_irq-4=PC
@以下三句就是取出被中断线程的SP_sys,只能通过stmfd指令间接取 mov r11,sp @下一句不能用SP,故先拷贝到r11 stmfd r11!,{sp}^ @被中断线程的SP_sys压入正在服务的中断栈中 ldmfd r11!,{r12} @从正在服务的中断栈中读取 SP_sys->R12
stmfd r12!,{r10} @保存 PC_sys stmfd r12!,{lr}^ @保存 lr_sys stmfd r12!,{r3-r9} @保存被中断线程的r12-r6到它的栈中 ldmea r2!,{r3-r9} @读被中断线程的r5-r0->r9-r4,SPSR_irq->r3,递增式空栈 stmfd r12!,{r3-r9} @保存被中断线程的r5-r0,CPSR_sys到它的栈中
str r12,[r1] @换出的上下文的栈指针-->old_sp
@以下几行把待换入的上下文copy到IRQ栈顶,r0即new_sp,保存待换入的上下文栈指针 @与递减式满栈对应,此时IRQ栈用递增式空栈的方式访问
mov r12,r0 @读取需换入的栈指针 ldmfd r12!,{r3-r11} @读取换入线程的CPSR_sys->r3 @读取换入线程的r0-r7->r4-r11 stmea r2!,{r3-r11} @保存换入线程的CPSR_sys->SPSR_irq, r0-r7到IRQ栈 ldmfd r12!,{r3-r7} @读取换入线程的r8-r12->r3-r7 stmea r2!,{r3-r7} @保存换入线程的r8-r12到IRQ栈 ldmfd r12!,{lr}^ @恢复换入线程的LR_sys到寄存器中 ldmfd r12!,{r3} @读取换入线程的PC->r3 add r3,r3,#4 @模拟IRQ保存被中断上下文PC的方式:PC+4->LR_irq stmea r2!,{r3} @保存换入线程的LR_irq到IRQ栈 stmfd r12!,{r12} @读取SP_sys到r12 ldmfd r12!,{sp}^ @恢复SP_sys mov r0,r0 @无论是否操作当前状态的SP,操作sp后,不能立即执行函数 @返回指令,否则返回指令的结果不可预知。 ldmfd sp!,{r2-r12,pc} @ end of __asm_switch_context_int
|