FR60 マイコン基板 (12) -- 0 円 48 MHz オシレータ (4)

前回掲載した HEX (モトローラ S フォーマット) ファイルの作成方法について説明します。
インターフェース誌の Web サイトのダウンロードページにある「USBtgt.LZH」に含まれる、プログラム本体「CQFRKFR60_DEMO.mhx」のことを、これ以降「元のプログラム」と略記します。
元のプログラムでは、外部バスインターフェースの初期化は CS0 領域と CS1 領域 (USB ホスト機能) しか行っていないようなので、前に掲載した PPG/OSDC 設定プログラムの最初の部分に下のリストに示す処理を追加しました。

//
// for OSDC (16bit)
//
  IO_EBUS.IO_ACR3.hword = 0x0421;
  IO_EBUS.IO_ASR3       = 0x0007;
  IO_EBUS.IO_AWR3       = 0x0098;
//
  IO_EBUS.IO_CSER.byte  |= 0x08;

元のプログラムに PPG/OSDC 設定処理を追加するのは、次のような方針で行っています。

  1. PPG/OSDC 設定プログラムは、元のプログラムの未使用領域に配置する
  2. 元のプログラムでの関数呼び出しのアドレスを書き換え、PPG/OSDC 設定プログラムに飛ぶようにする
  3. PPG/OSDC 設定プログラムの最後で、元のプログラムの本来の関数へジャンプさせる
プログラムの配置位置指定

元のプログラムが占めるプログラム領域は HEX ファイルの S2 レコードのアドレス部分を見れば分かります。
0x087475 が最終アドレスですから、切りがいいアドレスとして、0x088000 以降に PPG/OSDC 設定プログラムを置くことにしました。
この位置にプログラムを配置する方法は、いくつかありますが、C プログラム中に次のような #pragma 文を置くのが一番簡単だと思います。

#pragma section CODE=code2,attr=CODE,locate=0x088000

これは、デフォルトでは「CODE」と名付けられているコード・セクションに新しい名前「code2」を付け、0x088000 以降に配置することを指示するものです。
デフォルトの設定が有効な「startup.asm」のコードは 0x080000 から配置され、main() 関数だけが 0x088000 以降に配置されます。
コンパイル結果の HEX ファイルの 0x080000 に配置されている部分と、割り込みベクタテーブルである 0x0FFC00 〜 0xFFFFF の部分を削除し、 0x088000 からの部分だけを残します。

シミュレータデバッガによる逆アセンブル

追加プログラムを呼び出す部分を決定するために、HEX ファイルしかない元のプログラムの内容を調べようとすると、逆アセンブラが必要になります。
その目的のために、Softune のシミュレータデバッガを利用することができます。
Softune のヘルプの「2.12 デバッグのみを行う場合」の記述に従って、ワークスペース/プロジェクトを作成します。
このとき、デバッガ種別は「simulator Debugger」を選びます。
デバッガには HEX ファイルをロードする機能はないので、あらかじめ Softune 付属ユーティリティの「m2bs」を使って HEX ファイルをバイナリファイルに変換しておきます。
メニューの「表示(V)/コマンド(C)」で開くコマンドウィンドウから、次のコマンドを入力してバイナリファイルをロードします。

load/binary CQFRKFR60_DEMO.bin,0x080000

あとは、「表示(V)/逆アセンブル(A)」で逆アセンブルウィンドウを開き、「デバッグ(D)/MCU のリセット(T)」でリセット時の PC のアドレスに移動しますから、そこから順にプログラム内部を調べて行きます。

パッチを当てる関数の決定

元のプログラム内部を、ざっと見て、次の部分にパッチを当てることにしました。

00080244: 9F8C00080700     LDI:32   #0x080700,R12
0008024A: 971C             CALL     @R12

アドレス 0x080246 からの 4 バイトを「0x00088000」と書き換え、0x088000 番地以降に配置した PPG/OSDC 設定プログラムが呼び出されるようにします。
PPG/OSDC 設定プログラムの最後で、0x080700 にある本来の関数にジャンプするように、プログラムの最後に

  __asm(" LDI:32 #0x080700,R12");
  __asm(" NOP");

を付け加えています。
また、前のプログラムは、48 MHz クロック発生の確認用なので、最後の部分は無限ループになっていますが、元のプログラムに組み込むために、無限ループは削除しています。
結局、最後の部分の逆アセンブルリストは

000880B0: 9F8C00080700     LDI:32   #0x080700,R12
000880B6: 9FA0             NOP      
000880B8: 8D07             LDM1     (R8,R9,R10)
000880BA: 9720             RET      

となります。
「LDM1」でレジスタをリストアしている部分は、コンパイラの最適化レベルを変えると変化します。 これは「最適化レベル 1」、「外部シンボルサイズ 20 ビット」の設定の場合です。
この最後の「RET」命令を「JMP @R12」命令 (0x970C) に変えて、元のプログラムの本来の関数に分岐させます。
このパッチ部分が、前回の HEX ファイルの最後の 2 行

S2060880BA970C14
S208080246000880001F

です。