割込みを一時禁止にする方法(割り込み禁止/許可マクロ)

SHで、処理中の割込み禁止、許可処理をどう実現すれば良いか迷っています。

SuperH C/C++コンパイラパッケージ アプリケーションノート
(RJJ05B0557-0700)には以下のコードが記載されています。

#define disable() { save_cr=get_cr(); set_imask(0x0f); }
#define enable() { set_cr(save_cr); }

この処理で疑問なのが、なぜステータスレジスタをまるごと退避、戻しを

しているのか?という点です。

禁止時はget_imaskでIビットの値を退避、許可時はset_imaskで

退避したIビットの値をIビットに戻せば良い気がするのですが。。。

みなさまはどのような処理で割込み禁止/許可を行っていますでしょうか?

 

Parents
  • > この処理で疑問なのが、なぜステータスレジスタをまるごと退避、戻しをしているのか?という点です。

    disable() 直前の割り込み許可状態を enable() で復元したいんじゃないですか。save_cr が大域変数だと上手く動作しないとは思いますが。

    割り込みが許可、あるいは禁止状態で行う処理や関数で一時的に割り込みを禁止して後に割り込み許可状態を禁止直前の状態に復元したい、ということは普通にあります。

  • 実際にはdisableが実行する前に、元のSRの内容はスタックに保存されているんですよね。

    また割り込みマスクを0xfに設定する前に、より優先度の高い割り込みが入る事を防ぐ事ができなかったりする。

  • fujita nozomu さん、@chobichan さんお返事ありがとうございます。

    すいません、質問の仕方を変えます。

    SHでの割込を一時禁止するやり方ですが、今は、

    SuperH C/C++コンパイラパッケージ アプリケーションノート

    (RJJ05B0557-0700)の以下のコード(マクロ)

    #define disable() { save_cr=get_cr(); set_imask(0x0f); }

    #define enable() { set_cr(save_cr); }

    を参考にして、以下のようなコードを書いています。

     int save_cr;

     // 割込み禁止処理

     save_cr=get_cr();

     set_imask(0x0f);

     // 割込み禁止にした状態で行いたい処理

     test_flg = 1;

     // 割込み許可処理

     set_cr(save_cr);

    上記の方法で良いのでしょうか?

    get_cr()関数ではなく、get_imask関数を使って

    以下のやり方でも良いのでしょうか?

     int save_i;

     // 割込み禁止処理

     save_i = get_imask();

     set_imask(0x0f);

     // 割込み禁止にした状態で行いたい処理

     test_flg = 1;

     // 割込み許可処理

     set_imask(save_i);    ←15/07/21 誤って「set_cr」と、していたので直しました。

  • 割込み禁止区間を設ける場合、私は「get_imaskとset_imask」を用いた方を使います。

    SRレジスタを退避しても出来そうですよね。割込みレベルのマスクビットってSRレジスタの中にある4ビットですから。

    未確認ですが、機械語レベルでみると「get_cr()とset_cr()」を用いたほうが命令数が少いかもしれません。

    ※SRレジスタ操作なのにcrというのが気に入らないんですよね。

  • 割り込み禁止/解除の方法はどっちでもいいと思うのですが、get_cr()/set_cr() のほうが get_imask()/set_imask() よりコードは短く実行も速いので有利だと思います。

    void test_cr(void)
    00001020 7FFC _test_cr ADD       #H'FC,R15
    {
        int save_cr;
        // 割込み禁止処理
        save_cr=get_cr();
    00001022 0402          STC       SR,R4
    00001024 2F42          MOV.L     R4,@R15
        set_imask(0x0f);
    00001026 0002          STC       SR,R0
    00001028 9122          MOV.W     @(H'0044:8,PC),R1
    0000102A 2019          AND       R1,R0
    0000102C CBF0          OR        #H'F0,R0
    0000102E 400E          LDC       R0,SR
    00001030 D510          MOV.L     @(H'0040:8,PC),R5
        // 割込み禁止にした状態で行いたい処理
        test_flg = 1;
    00001032 E201          MOV       #H'01,R2
    00001034 2522          MOV.L     R2,@R5
        // 割込み許可処理
        set_cr(save_cr);
    00001036 440E          LDC       R4,SR
    }
    00001038 000B          RTS       
    0000103A 7F04          ADD       #H'04,R15
    
    void test_imask(void)
    {
        int save_i;
        // 割込み禁止処理
        save_i = get_imask();
    0000103C 0002 _test_im STC       SR,R0
    0000103E 4009          SHLR2     R0
    00001040 4009          SHLR2     R0
    00001042 C90F          AND       #H'0F,R0
    00001044 6603          MOV       R0,R6
        set_imask(0x0f);
    00001046 0002          STC       SR,R0
    00001048 9512          MOV.W     @(H'0024:8,PC),R5
    0000104A 2059          AND       R5,R0
    0000104C CBF0          OR        #H'F0,R0
    0000104E 400E          LDC       R0,SR
        // 割込み禁止にした状態で行いたい処理
        test_flg = 1;
    00001052 E101          MOV       #H'01,R1
    00001054 4608          SHLL2     R6
    00001056 2412          MOV.L     R1,@R4
    00001058 4608          SHLL2     R6
    0000105A 0702          STC       SR,R7
    0000105C 2759          AND       R5,R7
    0000105E 276B          OR        R6,R7
    00001060 470E          LDC       R7,SR
        // 割込み許可処理
        set_imask(save_i);
    00001050 D408          MOV.L     @(H'0020:8,PC),R4
    00001052 E101          MOV       #H'01,R1
    00001054 4608          SHLL2     R6
    00001056 2412          MOV.L     R1,@R4
    00001058 4608          SHLL2     R6
    0000105A 0702          STC       SR,R7
    0000105C 2759          AND       R5,R7
    0000105E 276B          OR        R6,R7
    00001060 470E          LDC       R7,SR
    }
    00001062 000B          RTS       
    00001064 0009          NOP       
    
  • 皆さんとは考えが逆行しますが、安全側に倒れることを想定するなら、set_imask()/get_imask()のほうがいいと思います。

    割り込み許可までにメモリ破壊が発生したら目も当てられません。

  • Kon Nozomu(すと)さん、

    メモリ破壊とはどこのことを指してのことでしょうか? メモリの内容が破壊されても安全に動作するシステムはまた別の課題だと思いますが。

  • 退避内容が破壊されたときを考えるとリスクの少ない方がいいと思いましたが、

    メモリが(スタック、大域変数)壊れているんだったら何をやっても無駄、とも言えますね。

    私だったらコード効率よりも、よりリスクの少ない方(必要最低限の情報へのアクセス)を選択しますという意味でした。


    fujitaさんがご指摘されるようにメモリ保護は別の課題ですね。

  • fujitaさん

    結構、差がありますね。

    私も今後はget_crとset_crの組み合わせに乗り換えようと思います。

  • すとさん

    メモリ破壊ですがset_imask()/get_imask()でも値はメモリにあるわけで破壊されて動作レベル値が変わったら、割込み禁止区間から抜けた時に動作レベルは引き継げないです。ただ、割込み禁止区間中のSRレジスタの割込みマスクビット以外は継続されるということが大事だという意味でしたらset_imask()/get_imask()が有効かもしれません。

    私はC言語で記述しているだけでSRレジスタの中身まで見ないので「get_cr()/set_cr()」で良いと思います。「set_imask()/get_imask()」を使っていたのは すとさんが参照されているドキュメントを私も大昔に読んで割込みマスク設定・参照と明記されていためです。私が組込を仕事とした当初なのでget_cr()/set_cr()の組み合わせでも出来るかの判断が出来なかった。。。。判断できるようになった分、オッサンになったんだな。

  • みなさまコメントありがとうございました。

    お礼が遅くなり申し訳ありませんでした。

    コードサイズが小さいという点から

    私もget_cr/set_crを使って行こうと思います。

Reply Children
No Data