15

Nuoeriris · 2021年05月20日

MM32F013x——IEC60730-1 B类认证软件设计指南(二)

在上一章节中我们介绍了主要介绍了ClassB软件的作用、框架和流程等,本章节将给大家介绍CPU寄存器检测实现方法。

1. 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。

2. CPU寄存器测试原理

在mm32\_cpu\_startKeil.s与mm32\_cpu\_runKeil.s文件中会对CPU寄存器进行测试,其中mm32\_cpu\_startKeil.s文件中的测试为启动过程中对CPU寄存器进行的测试,mm32\_cpu\_runKeil.s文件中的测试为运行自检流程中的CPU寄存器测试,其原理为对寄存器每一位写0和写1操作,对比是否有错误。

具体实现:分别写入0xAAAAAAAA和0x55555555再进行比较是否为写入的值。

3. 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函数,直接提醒错误报警,或可以添加对应的处理机制。

推荐阅读
关注数
6143
内容数
276
灵动MM32 MCU相关技术知识,欢迎关注~
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息