在上一章节中我们介绍了主要介绍了ClassB软件的作用、框架和流程等,本章节将给大家介绍CPU寄存器检测实现方法。
01、CPU寄存器自检
R0 ~ R12我们称为通用寄存器,其中寄存器R0 ~ R7我们称为低寄存器,寄存器R8 ~ R12我们称为高寄存器,可用于数据操作。
在对R0 ~ R12寄存器进行操作时需要注意:绝大多数 16 位 Thumb 指令只能访问 R0‐R7,而 32 位 Thumb‐2 指令可以访问所有寄存器。
R13作为堆栈指针 SP,SP有两个:
主堆栈指针(MSP):复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包括中断服务例程)。
进程堆栈指针(PSP):由用户的应用程序代码使用。
R14连接寄存器:当呼叫一个子程序时,由 R14 存储返回地址。
CPU自检在启动时和运行时都会进行,在启动时,所有寄存器(R0~R12,PSP,MSP)和标记的功能测试都会进行一次自检;运行时,周期性自检,不检测R13,R14,仅检测寄存器R0~R12。
02、CPU寄存器测试原理
在mm32_cpu_startKeil.s与mm32_cpu_runKeil.s文件中会对CPU寄存器进行测试,其中mm32_cpu_startKeil.s文件中的测试为启动过程中对CPU寄存器进行的测试,mm32_cpu_runKeil.s文件中的测试为运行自检流程中的CPU寄存器测试,其原理为对寄存器每一位写0和写1操作,对比是否有错误。
具体实现:分别写入0xAAAAAAAA和0x55555555再进行比较是否为写入的值。
03、CPU寄存器测试实现
以启动时CPU自检程序为例进行分析,将conAA数据定义为0xAAAAAAAA,将con55定义为0x55555555,并使用EXPORT指令进行声明。
conAA DCD 0xAAAAAAAA con55 DCD 0x55555555 con80 DCD 0x80000000 conA8 DCD 0xAAAAAAA8 con54 DCD 0x55555554 EXPORT conAA EXPORT con55
声明函数ClassB_StartUpCPUTest函数,并进行CPU寄存器中的R1寄存器的检测,先将conAA的数据赋值给R0寄存器,然后赋值给R1寄存器,然后比较R0与R1寄存器的数据,如果两者的数据相同则将con55分别赋值给R1与R0寄存器进行比较,否则会跳转执行CPUTestFail函数,如果两者的数据相同则将0x01赋值给R1寄存器,否则将会跳转到CPUTestFail函数中。
; Register R1 LDR R0, =conAA LDR R1,[R0] LDR R0,[R0] CMP R0,R1 BNE CPUTestFail LDR R0, =con55 LDR R1,[R0] LDR R0,[R0] CMP R0,R1 BNE CPUTestFail MOVS R1, #0x1 ; For ramp test
在汇编程序中大家可以看到,如果检测失败,会跳转到CPUTestFail函数执行,如果检测成功则进行下一步的检测。
依次针对R2 ,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12寄存器进行与R1一样的操作,在上述的寄存器比较完成以后相应的寄存器会被赋予新的数据。
Class_StartUpCPUTest PROC EXPORT Class_StartUpCPUTest PUSH {R4-R6} ; Safe critical registers MOVS R0, #0x00 UXTB R0,R0 ADDS R0,#0 ; Set Z(ero) Flag BNE CPUTestFail ; Fails if Z clear BMI CPUTestFail ; Fails if N is set SUBS R0,#1 ; Set N(egative) Flag BPL CPUTestFail ; Fails if N clear ADDS R0,#2 ; Set C(arry) Flag and do not set Z BCC CPUTestFail ; Fails if C clear BEQ CPUTestFail ; Fails if Z is set BMI CPUTestFail ; Fails if N is set LDR R0,=con80 ; Prepares Overflow test LDR R0,[R0] ADDS R0, R0, R0 ; Set V(overflow) Flag BVC CPUTestFail ; Fails if V clear ; This is for control flow test (ENTRY point) LDR R0,=CtrlFlowCnt LDR R1,[R0] ADDS R1,R1,#0x3 ; CtrlFlowCnt += OxO3 STR R1,[R0] ; Register R1 LDR R0, =conAA LDR R1,[R0] LDR R0,[R0] CMP R0,R1 BNE CPUTestFail LDR R0, =con55 LDR R1,[R0] LDR R0,[R0] CMP R0,R1 BNE CPUTestFail MOVS R1, #0x1 ; For ramp test ; Register R2 LDR R0, =conAA LDR R2,[R0] LDR R0,[R0] CMP R0,R2 BNE CPUTestFail LDR R0, =con55 LDR R2,[R0] LDR R0,[R0] CMP R0,R2 BNE CPUTestFail MOVS R2, #0x2 ; For ramp test ; Register R3 LDR R0, =conAA LDR R3,[R0] LDR R0,[R0] CMP R0,R3 BNE CPUTestFail LDR R0, =con55 LDR R3,[R0] LDR R0,[R0] CMP R0,R3 BNE CPUTestFail MOVS R3, #0x3 ; For ramp test ; Register R4 LDR R0, =conAA LDR R4,[R0] LDR R0,[R0] CMP R0,R4 BNE CPUTestFail LDR R0, =con55 LDR R4,[R0] LDR R0,[R0] CMP R0,R4 BNE CPUTestFail MOVS R4, #0x4 ; For ramp test ; Register R5 LDR R0, =conAA LDR R5,[R0] LDR R0,[R0] CMP R0,R5 BNE CPUTestFail LDR R0, =con55 LDR R5,[R0] LDR R0,[R0] CMP R0,R5 BNE CPUTestFail MOVS R5, #0x5 ; For ramp test ; Register R6 LDR R0, =conAA LDR R6,[R0] LDR R0,[R0] CMP R0,R6 BNE CPUTestFail LDR R0, =con55 LDR R6,[R0] LDR R0,[R0] CMP R0,R6 BNE CPUTestFail MOVS R6, #0x6 ; For ramp test ; Register R7 LDR R0, =conAA LDR R7,[R0] LDR R0,[R0] CMP R0,R7 BNE CPUTestFail LDR R0, =con55 LDR R7,[R0] LDR R0,[R0] CMP R0,R7 BNE CPUTestFail MOVS R7, #0x7 ; For ramp test ; Register R8 LDR R0, =conAA LDR R0,[R0] MOV R8,R0 CMP R0,R8 BNE CPUTestFail LDR R0, =con55 LDR R0,[R0] MOV R8,R0 CMP R0,R8 BNE CPUTestFail MOVS R0, #0x08 ; For ramp test MOV R8,R0 BAL CPUTstCont CPUTestFail BLAL FailSafePOR CPUTstCont ; Register R9 LDR R0, =conAA LDR R0,[R0] MOV R9,R0 CMP R0,R9 BNE CPUTestFail LDR R0, =con55 LDR R0,[R0] MOV R9,R0 CMP R0,R9 BNE CPUTestFail MOVS R0, #0x09 ; For ramp test MOV R9,R0 ; Register R10 LDR R0, =conAA LDR R0,[R0] MOV R10,R0 CMP R0,R10 BNE CPUTestFail LDR R0, =con55 LDR R0,[R0] MOV R10,R0 CMP R0,R10 BNE CPUTestFail MOVS R0, #0x0A ; For ramp test MOV R10,R0 ; Register R11 LDR R0, =conAA LDR R0,[R0] MOV R11,R0 CMP R0,R11 BNE CPUTestFail LDR R0, =con55 LDR R0,[R0] MOV R11,R0 CMP R0,R11 BNE CPUTestFail MOVS R0, #0x0B ; For ramp test MOV R11,R0 ; Register R12 LDR R0, =conAA LDR R0,[R0] MOV R12,R0 CMP R0,R12 BNE CPUTestFail LDR R0, =con55 LDR R0,[R0] MOV R12,R0 CMP R0,R12 BNE CPUTestFail MOVS R0, #0x0C ; For ramp test MOV R12,R0 LDR R0, =CPUTstCont
R1~R12寄存器比较完成以后会在Ramp中做进一步的判断,判断R1寄存器的数值是否为0x01,R2寄存器的数值是否为0x02,依次判断到R12寄存器,如果以上的判断都是正确的则说明R1~R12寄存器验证通过。
; Ramp pattern verification (R0 is not tested) CMP R1, #0x01 BNE CPUTestFail CMP R2, #0x02 BNE CPUTestFail CMP R3, #0x03 BNE CPUTestFail CMP R4, #0x04 BNE CPUTestFail CMP R5, #0x05 BNE CPUTestFail CMP R6, #0x06 BNE CPUTestFail CMP R7, #0x07 BNE CPUTestFail MOVS R0, #0x08 CMP R0,R8 BNE CPUTestFail MOVS R0, #0x09 CMP R0,R9 BNE CPUTestFail MOVS R0, #0x0A CMP R0,R10 BNE CPUTestFail MOVS R0, #0x0B CMP R0,R11 BNE CPUTestFail MOVS R0, #0x0C CMP R0,R12 BNE CPUTestFail
对R13的自检功能与通用寄存器的操作不同,需要先保存堆栈到R0,操作如下:
; Process Stack pointer (banked Register R13) MRS R0,PSP ; Save process stack value LDR R1, =conA8 ; Test is different (PSP is word aligned, 2 LSB cleared) LDR R1,[R1] MSR PSP,R1 ; load process stack value MRS R2,PSP ; Get back process stack value CMP R2,R1 ; Verify value BNE CPUTestFail LDR R1, =con54 ; Test is different (PSP is word aligned, 2 LSB cleared) LDR R1,[R1] MSR PSP,R1 ; load process stack value MRS R2,PSP ; Get back process stack value CMP R2,R1 ; Verify value BNE CPUTestFail MSR PSP, R0 ; Restore process stack value ; Stack pointer (Register R13) MRS R0,MSP ; Save stack pointer value LDR R1, =conA8 ; Test is different (SP is word aligned, 2 LSB cleared) LDR R1,[R1] MSR MSP,R1 ; load SP value MRS R2,MSP ; Get back SP value CMP R2,R1 ; Verify value BNE CPUTestFail LDR R1, =con54 LDR R1,[R1] ; load SP value MSR MSP,R1 ; Get back SP value MRS R2,MSP ; Verify value CMP R2,R1 BNE CPUTestFail MSR MSP,R0 ; Restore stack pointer value ; Control flow test (EXIT point) LDR R0,=CtrlFlowCntInv LDR R1,[R0] SUBS R1,R1,#0x3 ; CtrlFlowCntInv -= OxO3 STR R1,[R0] POP {R4-R6} ; Restore critical registers ; If next instruction is not executed, R0 will hold a value different from 0 MOVS R0, #0x1 ; CPUTEST_SUCCESS BX LR ; return to the caller ALIGN ENDP END
以上代码是在启动时CPU寄存器自检的汇编代码,在运行时CPU寄存器自检功能与启动自检的代码原理相同,只是对寄存器操作个数有差异,运行时不用对R13\14进行操作。
在汇编程序中我们会使用CMP指令进行判断,后面会跟着BNE指令,其作用就是判断如果CMP判断的两个寄存器不相等,则直接执行BNE指令后面的CPUTestFail函数,直接提醒错误报警,或可以添加对应的处理机制。
来源:灵动微电子
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。