SSブログ

ColdFire でアセンブラ (5) - タスク・コンテキストを作らせる [ColdFire (ColdeFire) V1]このエントリーを含むはてなブックマーク#

ColdFire で割り込み(例外)が発生すると、スーパバイザモードに移行します。 割り込み処理ルーチンでタスク・コンテキストを切り替える処理を考えます。

ステートメント・レベルで記述する

最初の例は、コンテキストの退避と復帰だけをアセンブラで記述したものです。

dword count;

void trap_content(void) {
  count++;
}

dword *this_SSP;
dword *system_SSP;

__interrupt VectorNumber_Vtrap0 trap0_isr (void) {
  __asm {
    lea     -64(a7),a7        // スタックフレームの確保
    movem   d0-d7/a0-a6,(a7)  // レジスタを退避する
    move    usp,a0            // USPを取り出す
    move    a0,60(a7)         // USPを退避させる
    move    a7,this_SSP       // SSPを退避させる
    move    system_SSP,a7     // システムSSPを設定する
  }
    trap_content();           // 処理の実体
  __asm {
    move    this_SSP,a7       // SSPを復帰させる
    move    60(a7),a0         // USPを取り出す
    move    a0,usp            // USPを復帰させる
    movem   (a7),d0-d7/a0-a6  // レジスタを復帰させる
    lea     64(a7),a7         // スタックフレームの解放
  }
}

これをコンパイルすると、関数の最初と最後の部分は、このようになります。

;   28: __interrupt VectorNumber_Vtrap0 trap0_isr (void) { 
;   28:                                                  { 
;   29:                                                    __asm { 
0x00000000                    _trap0_isr:
;                             trap0_isr:
0x00000000  0x2F08                   move.l   a0,-(a7)
0x00000002  0x2F01                   move.l   d1,-(a7)
;
;   30:     lea     -64(a7),a7        // スタックフレームの確保 
0x00000004  0x4FEFFFC0               lea      -64(a7),a7
;
;   31:     movem   d0-d7/a0-a6,(a7)  // レジスタを退避する 
0x00000008  0x48D77FFF               movem.l  d0-d7/a0-a6,(a7)

     :

;   42:     movem   (a7),d0-d7/a0-a6  // レジスタを復帰させる 
0x00000034  0x4CD77FFF               movem.l  (a7),d0-d7/a0-a6
;
;   43:     lea     64(a7),a7         // スタックフレームの解放 
;   44:       } 
0x00000038  0x4FEF0040               lea      64(a7),a7
;
;   45: } 
0x0000003C  0x221F                   move.l   (a7)+,d1
0x0000003E  0x205F                   movea.l  (a7)+,a0
0x00000040  0x4E73                   rte      
0x00000042  0x51FC                   trapf    

このようにタスク・コンテキストを構築する前に 作業領域として使用しているD1とA0を退避させるコードが作成されてしまい、 タスク・コンテキストとして使えなくなってしまいます。

キーワードnakedを使う

勝手に作業領域を確保させないためには、 nakedというキーワードを付けます。

__interrupt VectorNumber_Vtrap1 trap1_isr (void) {
  __asm {
    naked
    lea     -64(a7),a7        // スタックフレームの確保
    movem   d0-d7/a0-a6,(a7)  // レジスタを退避する
    move    usp,a0            // USPを取り出す
    move    a0,60(a7)         // USPを退避させる
    move    a7,this_SSP       // SSPを退避させる
    move    system_SSP,a7     // システムSSPを設定する
  }
    trap_content();           // 処理の実体
  __asm {
    move    this_SSP,a7       // SSPを復帰させる
    move    60(a7),a0         // USPを取り出す
    move    a0,usp            // USPを復帰させる
    movem   (a7),d0-d7/a0-a6  // レジスタを復帰させる
    lea     64(a7),a7         // スタックフレームの解放
    rte                       // 例外処理の終了
  }
}

このキーワードを付けると、 最後のRTE命令さえも生成してくれないので、 注意が必要です。 コンパイルするとこうなります。

;   47: __interrupt VectorNumber_Vtrap1 trap1_isr (void) { 
;   48:   __asm { 
;   49:     naked 
;   50:     lea     -64(a7),a7        // スタックフレームの確保 
0x00000000                    _trap1_isr:
;                             trap1_isr:
0x00000000  0x4FEFFFC0               lea      -64(a7),a7
;
;   51:     movem   d0-d7/a0-a6,(a7)  // レジスタを退避する 
0x00000004  0x48D77FFF               movem.l  d0-d7/a0-a6,(a7)

    :

;   62:     movem   (a7),d0-d7/a0-a6  // レジスタを復帰させる 
0x00000030  0x4CD77FFF               movem.l  (a7),d0-d7/a0-a6
;
;   63:     lea     64(a7),a7         // スタックフレームの解放 
0x00000034  0x4FEF0040               lea      64(a7),a7
;
;   64:     rte                       // 例外処理の終了 
;   65:       } 
0x00000038  0x4E73                   rte      
;
;   66: } 
0x0000003A  0x51FC                   trapf    

前処理と後処理は、全く生成されないので、 ユーザの責任で確実にレジスタを退避させる必要があります。

関数レベルで記述する

上の二つの例では、処理の実体をCで書きたいがために、 ステートメントレベルでアセンブラ記述にしていました。 ところが、アセンブラでスタックを切り替えていることから、 局所変数などのスタックを使用する文などは事実上使用できません。 それだったら、全部アセンブラで書いてしまえというのが、次の例です。

__asm __interrupt VectorNumber_Vtrap2 trap2_isr (void) {
  lea     -64(a7),a7        // スタックフレームの確保
  movem   d0-d7/a0-a6,(a7)  // レジスタを退避する
  move    usp,a0            // USPを取り出す
  move    a0,60(a7)         // USPを退避させる
  move    a7,this_SSP       // SSPを退避させる
  move    system_SSP,a7     // システムSSPを設定する
  jsr     trap_content      // 処理の実体
  move    this_SSP,a7       // SSPを復帰させる
  move    60(a7),a0         // USPを取り出す
  move    a0,usp            // USPを復帰させる
  movem   (a7),d0-d7/a0-a6  // レジスタを復帰させる
  lea     64(a7),a7         // スタックフレームの解放
  rte                       // 例外処理の終了
}

この例では、引数も返り値もない関数trap_contentを使っていますが、 単純なもの数個でよければ、受け渡しをすることもできます。 コンパイル結果は、このようになります。

;   68: __asm __interrupt VectorNumber_Vtrap2 trap2_isr (void) { 
;   69:   lea     -64(a7),a7        // スタックフレームの確保 
0x00000000                    _trap2_isr:
;                             trap2_isr:
0x00000000  0x4FEFFFC0               lea      -64(a7),a7
;
;   70:   movem   d0-d7/a0-a6,(a7)  // レジスタを退避する 
0x00000004  0x48D77FFF               movem.l  d0-d7/a0-a6,(a7)

    :

;   79:   movem   (a7),d0-d7/a0-a6  // レジスタを復帰させる 
0x0000002A  0x4CD77FFF               movem.l  (a7),d0-d7/a0-a6
;
;   80:   lea     64(a7),a7         // スタックフレームの解放 
0x0000002E  0x4FEF0040               lea      64(a7),a7
;
;   81:   rte                       // 例外処理の終了 
0x00000032  0x4E73                   rte      

trap_contentには、 アセンブラでは書きにくいような複雑な処理を書くことができます。


nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。