H8/3664のソフトウェアリセット

 BLOGにメモ書きでH8/3664のソフトウェアリセットに関して記述しておいたところ、 アクセスキーワードに「H8 ソフトウェアリセット」が増えてきたのでちょっとした解説ページを作りました。


マイコン版CTRL+ALT+DEL

 最近の(windows)コンピュータでは別の動作が割り当てられていますが、 昔のパソコンなら、CTRLキー、ALTキー、DELキーを同時に押すとリセットが掛かりました。 マイコンでも、例えば、キーの特定操作を割り込みで検出しておいて、 その操作が行われたときに、リセットシーケンスに入るというのは、入れておきたい機能です。  割り込み機能さえまともに動作していたら、大抵の場合うまく動作することでしょう。

C言語で実行アドレスを扱う

 最近はC++やオブジェクト指向などが大流行で、いわゆる「ドロくさい」処理についての解説は少なくなりました。 でも、100%自由の海でプログラミングできる1チップマイコンの世界では、ドロくさい処理もOKです。 C言語で、実行アドレスを扱うには、関数のポインタを使う方法と、スタックを操作する方法がありますが、 「ドロくささ」の少ない関数ポインタのほうを使って実装することにします。

void (*_rst)(void);

 上のようなコードを記述すると、「関数のポインタ」なるものが宣言できます。 宣言の名前の前に "(*"をつける、後ろに、")"をつける。それだけです。 引数なども自由に設定できますが、今回は必要ないので、void,voidにしておきます。 (そもそも、リセットするので、戻り値もなにも、戻ってきません)
 すると、_rstの値を参照したり、代入したり、_rstを関数として実行したりすることができます。

    _rst = 0;		// 値を代入する
  pnt = (unsigned short)_rst;	// 値を読み出す
    _rst();		// 実行する!

 これを使えば、任意のアドレスにJUMPできます。 実際にはCALL命令が使用されるので、スタックにゴミが残りますが、 リセットベクタをコールすれば、その後RUNTIMEにより適正にスタックは設定されるハズです。

H8/3664のリセットベクタは0番地に書かれている値

 次に、H8のリファレンスマニュアルを見てみると、リセットベクタは0番地にあることがわかります。 このアドレスはROMエリアなので問題ありませんが、NULLポインタに代入すると、 (RAMであった場合)リセットベクタが書き換わるという仕様になっています。 C言語での開発の場合、NULLポインタは(エラー用戻り値などとして)使用することも多いので、 デバック時の問題軽減のため、せめて2〜4バイト場所を確保しておいて欲しかったところです。 3664の場合、ROMなので問題ありません。
 すると、リセットを行うには、
(1)関数のポインタを宣言しておく
(2)0番地を指す別ポインタを用意し、0番地(から2バイト)に書かれている値を関数ポインタに設定する
(3)その関数を実行する
という処理でなんとかなりそうです。実際動作確認を行ったところ、良好に実行できています。

void(*_rst)(void);

void reset(void ) 
    {
    WORD * vct;
    vct = (WORD*)0; // for H8/300H
    _rst = vct[0]; // リセットベクタを取り込む
    _rst();		// リセット実行!
	// ここには戻ってこない
    }

無作為研究所トップページに戻る

copyright(c)2007 by MUSAKUI-LABO