【ベアメタル開発】リセット割り込みサービス機能(アセンブリ実装)

目次

1. リセット割り込みサービス機能の実装手順

2. リセット割り込みサービス機能を実装するためのアセンブリ

1. グローバル割り込みの無効化/有効化

2.SPポインタを設定する

3. .bss セクションをクリアします

4. リセット割り込みサービス機能の完了


1. リセット割り込みサービス機能の実装手順

リセット割り込みサービス機能を実装するための基本的な手順は次のとおりです。

  • 各モードでSPポインタを設定します割り込みが発生すると対応する動作モードに移行しますが、各動作モードでプログラムを実行するにはスタックを使用する必要があるため、異なるモードでスタックポインタを初期化する必要があります。
  • BSSセグメントをクリアします。
  • メイン関数にジャンプします。

場合によっては、割り込みサービス関数の実行が他の優先度の高い割り込みによって中断されるのを防ぐために、最初にグローバル割り込みを無効にし (IRQ および FIQ 割り込みを無効にし)、最後にグローバル割り込みを有効にすることができます。

  • グローバル割り込みを無効にする
  • 各モードでSPポインタを設定します
  • bss セグメントをクリアします
  • グローバル割り込みをオンにする
  • メイン関数へジャンプ

2. リセット割り込みサービス機能を実装するためのアセンブリ

1. グローバル割り込みの無効化/有効化

ここでは、CPSR レジスタを操作してそれを実現できますが、アセンブリはグローバル割り込みを無効/有効にするためのシンプルで高速な命令を提供します。

命令 説明する
cpsid私 IRQ割り込みを無効にする
cpsie私 IRQ割り込みを有効にする
cpsid f 禁止 FIQ 中断
シープシーエフ FIQ 割り込みを有効にする

2.SPポインタを設定する

ARM には合計 9 つの動作モードがありますが、ここでは 1 つずつ設定するのではなく、SVC、IRQ、USER、SYS など、使用できるいくつかのモードのみを設定します。SYS モードと USER モードは同じ SP ポインタ、つまり同じスタックを共有するため、2 つの設定のいずれかを選択できます。(各モードのスタックのサイズは 2 M です)

各モードの SP 設定は似ています。

  • CPSRレジスタを変更して特定のモードに切り替える
  • このモードでSPポインタを設定します(R13レジスタ)

/* 切换到 SVC 模式 */
mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x13           @ 让 r0 的低五位或上 10011(0x13),结果保存到 r0
msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80200000          @ 设置栈指针

/* 切换到 SYS 模式 */
mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x1f           @ 让 r0 的低五位或上 11111(0x1f),结果保存到 r0
msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80400000          @ 设置栈指针

/* 切换到 IRQ 模式 */   
mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x12           @ 让 r0 的低五位或上 10010(0x12),结果保存到 r0
msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80600000          @ 设置栈指针

3. .bss セクションをクリアします

4. リセット割り込みサービス機能の完了

/* 复位中断 */ 
Reset_Handler:
    cpsid i                     /* 禁止IRQ */
    cpsid f                     /* 禁止FIQ */

    /* 切换到 SVC 模式 */
    mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
    bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
    orr r0, r0, #0x13           @ 让 r0 的低五位或上 10011(0x13),结果保存到 r0
    msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
    ldr sp,=0x80200000          @ 设置栈指针

    /* 切换到 SYS 模式 */
    mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
    bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
    orr r0, r0, #0x1f           @ 让 r0 的低五位或上 11111(0x1f),结果保存到 r0
    msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
    ldr sp,=0x80400000          @ 设置栈指针

    /* 切换到 IRQ 模式 */   
    mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
    bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
    orr r0, r0, #0x12           @ 让 r0 的低五位或上 10010(0x12),结果保存到 r0
    msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
    ldr sp,=0x80600000          @ 设置栈指针

    /* bss 段清零 */
    ldr r0, =__bss_start
    ldr r1, =__bss_end
    mov r2, #0
    bl bss_loop                 @ 跳转到 bss_loop,LR寄存器自动保存下一条指令地址

    cpsie f                     /* 使能FIQ */
    cpsie i                     /* 使能IRQ */

    b main                      @ 跳转到 main 函数

bss_loop:
    stmia, r0!, {0}
    cmp r0, r1
    bne bss_loop

    mov pc, lr                  @ 清零完毕后回到原位置

ジャンプ命令リファレンス:b、blジャンプ命令

おすすめ

転載: blog.csdn.net/challenglistic/article/details/131231054