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(); // リセット実行! // ここには戻ってこない }
無作為研究所トップページに戻る