ROM 化 プログラミン 考察 そして , その低水準の関数は , ほとんど の場合 , すべて C 言語のみて、 ( スタートアッ プ部は除いて ) 記述てきるのて、ある。 また , WSL C は I / O を直接操作したり , オペレーティングシステムやモニタブログ ラムなどのサービスコールを利用するため に , 独自の特別な記述方法をもっている。 lSt もっとも簡単なスタートアップの例 ( c s. s ) H8 / 532 EMS RUN-TIME-STARTUP HEADER FOR C copyright (c) 1983 by Whitesmiths, し td. copyright (c) 1989 by Advanced Dada Controls, Corp. setup bss, ca Ⅱ ma i n , then ex i t H8 ー 5 圓 . processor . pu b 1 i c start . public bsslo . external n_maln . external bsshi . external stkh i . external stklo . psect . even bsslo: bss WSL C には空間修飾子と呼ばれるものが ある。それらのひとつに@port というものが ある。 @port にはいろいろな使われ方があるの て、はまずポート変数というもの ナ・がこ、 を紹介する。 たとえば , @port char p3ddr @Oxff84 ; @port cha 「 P3dr @Oxff86 ; . psect text get control here at startup time ldc. w #0,sr enable interrupts # ー stkhi-2,sp set stack pointer mov . W #__bsslo,r5 : clear bSS area mov. W #__bsshi, r5 し 2 @r5 + し 1 start: O C— cd し 2 : main() call @n ma i n JSr sleep . end プログラムの実行前に必要なことを実際に マレシステム 行うコードが書かれる。 彡多フェイス プログラムのエントリはこのスタートア ップ部の先頭にする必要がある。この部分 だけはどうしてもアセンプリ言語て、なけれ C て、はその言語仕様以上に実行時ライプラ リが重要て、あるが , WSLC て、は , ば書けない マノレ システムインタフェイスライプラリと呼ば スタートアップ部て、は以下のことをする というように書いたとき , アセンプラには , れる , ハードウェアに直接アクセスする低 必要がある。 ① SP レジスタをスタックセグメントの 水準のいくつかのライプラリを , 必要に応 n outp3 : link fp, # 0 じて書き換えるだけて、 , すべてのライプラ ポトムにセットする mov. b # 1 , @Oxff84 ② BSS 領域 (RAM) をクリアする リ関数が使用て、きるようになっている。 ③必要であれば , 実行時ライプラリの mov. b @( 4 , (p), 「 5 れのよいところは , ない機能に関してはま 初期化用の関数を呼び出す mov. b 「 5 , @0xff86 ったく記述する必要がないということて、あ ④関数 main( ) を呼び出す unlk fp WSL C て、は後述するミニマルインタフェ たとえば , モニタ用に CRT 端末を接続 rts というように展開される。 イスライプラリの一部として , これらを行 し , シリアルポートからこれをアクセスし すなわち , 入出力ポートを特定の変数に う標準的なスタートアップ部 Crts が付属して たいといった場合 , これに対して , 1 文字書 割り付けてアクセスてきるようになってい く , 1 文字読む , というふたつの関数を書く るのて、ある。 このスタートアップ部を , 実行時に だけて、 , C の標準関数て、ある printf( ) 関数や H8 / 500 てはメモリ空間と IO 空間が同一て scanf( ) 関数などが , CRT 端末に対してすへ から実行するように ( 通常は先頭に ) , リン あるから , この機能のよさが多少薄れてし て使用て、きるようになる。 ク時に配置する ( List 2 参照 ) 。 特集 ROM 化プログラミング考察 59 outp3(ch) int ch ; p3dd 「 p3dr
List 3 域とデータ領域を , RAM に BSS 領域を割り 当てるだけのことて、ある。その際に , 0 以外 て、初期化されているデータについてリテラ ルにしてしまう必要があるのもミニマムモ デルの場合と同様て、ある。 また , 0 以外に初期化されているデータ を , スタートアップ時に ROM から RAM へ 読み込むという方法もある。この方法のよ いところは , 前述したとおり , プログラミ ングて、とくに気を使う必要がないことて、あ そして , この方法も ( ROM と RAM の容量 を気にしなければ ) 実現は , わりと簡単て、あ る。つまり , データ領域を RAM に割り当 て , スタートアップ時に ROM からロードす ればよいのて、ある。 それは , たとえば , mov # 0X6000 , 「 4 mov # datalo, 「 5 69 : rdr; *rnext 十十 if (&rbuf[sizeof rbuf] くニ rnext) 70 : rnext = rbuf; ー 0X40 : 72 : ssr & = 74 : 75 : @port void txi ( ) 76 : if (tdone = tnext) 77 : return: while (!(ssr & 0X80 ) ) 80 : tdr ニ *tdone 十十 : if (&tbuf [sizeof tbufJ くニ tdone) 82 : 83 : tdone tbuf : ー 0X80 : 84 : ssr & ニ 85 : / * TDRE * / 割り込みべクタテープル ( ebvec. c ) S , よワ 3 っ 0 ・ 4 ・戸 0 C.D 0 ー 8 0 ) . 0 0 0 0 0 0 0 0 Q. a. Q. a. 1 ーワ 0 00 ・ 4 ・戸 0 ( 0 ー 8 0 1 人 -4 ・ - -0 ^. 0 ー 0 1 よ C'O っ 0 、 4 ・ ( 0 0 ー 8 cmp # datahi, 「 5 bcc L4 mov @「 4 十 , 「 3 mov 「 3 , @「 5 十 bra L3 といったプログラムをスタートアップ中に 付け加え , この例て、はデータ領域を 0X6000 番地から ROM に焼き付けておくのて、ある。 そうすることにより , スタートアップ時に 本当のデータ領域にその初期値がロードさ れるというわけて、ある。 TabIe 1 オプジェクトフォーマットトランスレータ 味 意 インテル HEX , テクトロニクス拡張 HEX , モトローラ S レコード HP ー 64000 オプジェクトモジュールフォーマット ( HP ー OMF ) ESROFF フォーマット COFF フォーマット ソフィアシステムアプソリュートフォーマット ( SAOF ) 0xff7f 番地まて、なのて、 , このような配置にし そま、の てみた。 RO イの方法 図て、表すと Fig. 3 のようになる。 これを見てわかるように , データ領域は 最後にマキシマムモードて、の ROM 化につ 生成されなくなっている。 以上 , 駆け足て、あったが , H8 / 500 を題材 Fig. 2 て、 link の次にある hex というのは , いて簡単にふれておくことにする。 に , C プログラムの ROM 化を中心に述べ ニマムモードて、の例を挙げ 前節て、は , この場合 , モトローラ S レコードに変換する ためのユーティリティて、ある。このほかに たが , マキシマムモードて、もそう大差はな 説明不足の点も多かったかと思うが , 多 も Table 1 に示すように , いろいろなオプジ く , ー x4 て、コンパイル ( すなわち関数がテキ 少なりとも読者諸氏の参考になれば幸いて、 ェクトフォーマットに対応している (Table スト領域 , リテラルがデータ領域 , 0 初期化 ある。 1 参照 ) 。 データが BSS 領域 ) し , ROM にテキスト領 62 CMAGAZINE 1990 11 名称 h ex tOhp ts ro 幵 tcoff tosaof さしま
bo C のヒュージモデルに対応しているかど ②割り込みべクタテープルの設定 ( 1 ) スタックポインタの設定 ことを行います。 スタートアップルーチンは以下のような ズタートアップレーチン MS<eg や Turb0 C の うかは不明て、す ) 。 Fig. 18 一般的な EXE ファイルの構成 タテープルを設定します。 例外やハードウェア割り込みのためのべク 除算ェラー例外 , オーパフロー例外などの ( 3 ) 初期値をもたない領域のゼロクリア 初期値をもたない領域は通常の処理系の スタートアップルーチンて、はゼロクリアを 行っていますから , ROM 化の場合て、もゼロ ( 7 ) セグメントレジスタのセットアップ ( 6 ) ハードウェア割り込みの許可 ( 5 ) ハードウェアの初期化 RAM へ転送します。 実際は DGROUP の初期値を ROM から RAM へ転送 ④初期値をもつ領域の初期値を ROM から クリアしておきます。 通常の処理系て、は DS レジスタは DGROUP EXE ファイルヘッダ ( Tab 厄 1 ) プログラム領域 初期値をもった変数領域 シンホル情報 一般的な EXE ファイルは EX E ファイルヘッダ プログラム領域 初期値をもった変数領域 ロードモジュールのサイズ ↓ からなり , CodeView 用のシンホル情報が追加される場合には , EXE ファイルの最後に追加される。 lSt 13 : 8 : 7 : 3 : 2 : スタートアップルーチン例 スタート・アッフ・・トチン 4 : MSC 1 equ 5 : TURBOC equ 2 6 : C-Compi ler equ MSC RAMSIZB equ 800h ROMSEG equ 0C000h 9 : STKSIZ equ 800h ( Microsoft C / TurbO C ラーシ・・モテ Microsoft C Compi ler : スタックハ・イト数 : ROM セメント : RAM ハ・ラク・ラフ数 ( X16 ハ・イト : Turbo C 2. 0 ← 1000H ) ハ・ワー ON リセット処理 i f C-Compiler eq MSC publi c acrtused acrtused 1 equ edata:byte ;extrn : MS-C 用ハ・アリック宣言 : end of DATA ( start Of BSS ROM 化 考察 を指している必要があるため , セグメント レジスタをセットアップします。 ⑧メインルーチン main の呼び出し DOS 上のプログラムて、は main 関数からリ ターンしてプログラムを終了しますが , ROM 化システムて、は main 関数から戻ってくるこ とはないため , サプルーチンコールて、なく main 関数へのジャンプて、もかまいません。 スタトアドレス FFFF0h の割り付け法 8086 は IM ノヾイトの空間の最上位ノヾラグラ フの FFFF0h 番地から実行を開始します。し たがって , 86 系て、 ROM 化を行うには FFFFO h 番地に fa 「ジャンプ命令て、スタートアップル ーチンにジャンプするようなコードを書き 込まなくてはいけません (Fig. 17 ) 。 ROM 化ツール自体がこの処理を独自にサ ポートしているものもあるようて、すが , 般的には以下のような方法て、対処可能て、す。 ( 1 ) AT 疑似命令でセグメントを FFFF0h に割り 付ける (List 9 ① ) この方法は OBJ ファイルをリンクして HEX フォーマットに変換する ROM 化ツールの場 合に使用可能な方法て、す。 EXE ファイルか ら HEX フォーマットに変換する場合は AT て、割り付けたセグメントが EXE ファイル内 に書き込まれないため , この方法は適応て、 きません。 ( 2 ) END 疑似命令で開始アドレスをセットす る (List 9 ② ) MS ー DOS 上のプログラムは END 疑似命令 て、開始アドレスを設定することがて、きます。 たとえば END STARTUP とすればプログラムは STARTUP から開始さ れます。 一般的な EXE ファイルは Fig. 18 のような 構成になっており , ファイルの先頭に EXE ファイルヘッダ ( Table 2 ) があります OEND 疑似命令て、指定した開始アドレスは , この 特集 ROM 化プログラミング考察 51
ROM 化 考察 プログラミング ロケータを用いた ROM 化 Secti0112 野口修男 を使ったボ、一ドが多い。 V25 には特殊機能レ どこまて、の対応がて、きているかは製品によ DOS コンヾイラの ジスタがあり , 周辺チップがメモリに割り って大きな違いがある。ロケータの購入前 付けられている点が特殊だ。ノヾンクレジス に確認を勧める。 タはマルチタスクのスイッチングに高速て、 , かっ便利だ Microsoft C( 以下 MS-C) や Turb0 C の V40 チップには使い慣れた周辺チップをつ プログラムを ROM 化するにはどうすればよ けているのが特長だ。 いのかという答えを出す前に , まず実際に 今回は , この中から V25 のコードを選択し MS-C と Turbo C て、生成可能なコードは ROM 化を試みた結果 , どのような問題が発 た。これにはふたつの理由がある。ひとつ 生するかを考えるのが妥当だろう。 80X86 用のコードだけだ。したがって , この は各種のポードが入手可能て、あること。も コードを使用する CPU チップも 80X86 互換チ 多くの ROM バーナー ( プログラマ ) は HEX うひとつはシリアルポートが 2 本内蔵されて ップとなる。 lntel だけをとっても 8088 , ファイルを入力フォーマットとしている。 おり , このうちの 1 本をコンソールに したがって , HEX ファイルを出力するのが 8086 , 80186 , 80286 , 80386 , 80486 があり , 1 本を Turbo Debugger を使ったリモートデ NEC の V シリーズを加えれば , チップの選 必要最少条件て、ある。 ROM 化専用のコンパ バッグ用に割り付けるためて、ある。 択肢は大きい。ただ , 通常の制御機器を作 イラ以外 , EXE ファイルしか出力て、きな 成する場合には , たんに CPU チップだけて、 い。したがって , EXE ファイルを HEX ファ ーットフォーム はなく , シリアル , タイマ , インタラブト イルに変換 , あるいは OBJ ファイルをリン などの周辺チップを含んだ CPU チップを選 クして HEX ファイルを出力するソフトが必 択するケースが多い。これは , とくに量産 要て、ある。 開発に必要なハード / ソフトを予算にあわ の場合に価格への影響が出るからだ。 一般にこのようなソフトをロケータと呼 こて、は私の せて組まなくてはならない この場合 , lntel には 80186 しかない。とな んて、いる。ロケータは入力ファイルの相対 個人的な好みも含めて選択理由を述べよう れば NEC の V シリーズがクローズアップさ アドレスからターゲットボードの絶対アド (TabIe 1 参照 ) 。 レスへの変換を行うのて、この名前がある。 れる。 市販の V シリーズチップて、は , V25 や V40 C て、はて、きない , プログラム中にアドレス指 パソコン 定することが , ロケータの主要な仕事だ TabIe 1 ROM 化のための八一ド / ソフト ROM 化て、きることとそのコードが正常に 開発システム選択の中核はパソコンだろ 動作することとは別だ。通常 , ロケータに う。日本て、は , ほとんどのソフト会社が PC は置き換え用のスタートアップコードが付 ー 9801 を選択している。そのほかのソフトの 属している。 Turbo C, MS-C に付属してい 開発やワープロて使用することを考えると るスタートアップコードは , DOS のメモリ 当然の結果かもしれない。しかし , IBM 互 構成と PC ー 9801 や IBM 互換機のハード構成 換機のスピードは ROM 化する際には一考に を意識して書いてあるのて、 , このコードを 値する。現在 , 筆者は Turbo C 十十を CP386 ROM 化しても正しく動作しない。ロケータ の 33MHz マシンて使っているが , だいたい に添付されているスタートアップコードは のモシュールのコンパイルは一瞬て終了す この点を改善しかっランライムライプラリ る。しかも , リモートデバッガのシリアル の動作に必要な処理も施してある。ただし 特集 ROM 化プログラミング考察 63 P ノ 7 の選択 ノヾソコン旧 M 互換機 V25 ホード Microsoft C/Turbo C Paradigm LOCATE ROM ライタ ℃ E リモートテノヾッガ
す。以下の Fig. 10 ようなコーディングを行 うとこのセグメントが生成されます。 初期値をもたない③と⑤が混ざっている ため , 対処が難しくなりますが , ③と⑤の 書式を使用しなければこのセグメントを ROM 領域に割り当てることにより対処可能て、す。 FAR DATA セグメントの初期値を ROM に置 いてスタートアップルーチンて、 RAM 上に転 送するツールもあるようて、すが , そこまて、 する意味があるかどうかは疑問て、す ( fa 「デー タにするということは合計て、 64K バイトを超 えるような配列の可能性が高いため , ROM Fig. 15 Fig. 16 ージモデルのセグメントの配置 下位アドレス DGROUP 上位アドレス ???—TEXT —DATA —BSS —STACK far ヒープ ヒュージモテルのセグメントの配置 下位アドレス ???—TEXT ???—DATA —STACK far ヒー ↓ 上位アドレス 'CODE' 'DATA' 'BSS' 'STACK' 'CODE' 'DATA' 'STACK' プ ファイルことに 64K 八イト以下 1- ー D S 64K バイト以下 ↓ SS 64K 八イト以下 ファイルことに 64K 八イト以下 ファイルことに 64K 八イト以下 64K ノヾイト以下 注 ) 1 . ? ? ? ー TEXT などの ? ? ? はファイル名になる。 2. ???_TEXT セグメント : プログラムコード た範囲が 64K 八イト以下の設定になる。 セグメントが DGROUP に属するが , ー STACK セグメントまてを含め 3. スモールモテルとミティアムモテルでは一 DATA セグメントと一 BSS トに組み込まれている。 ただし , ヒュージモテルは一 BSS セグメントか ? ? ? ー DATA セグメン —BSS セグメント : 非初期化テータ ???—DATA セグメント : 初期化テータ ROM 化 考察 プログラミン トて、す。以下のようなコーディングを行う 初期値をもたない HUGE データのセグメン HUGE BSS セグメント 利用することがて、きます (Fig. 11 ) 。 数用の ROM が離れた位置にある場合などに に割り付けることがて、きるため , マシン定 FAR DATA セグメントは任意のアドレス になります ) 。 と RAM に二重に割り付けられメモリが無駄 FAR BSS セグメント ります。 このセグメントは RAM 上に置くことにな int huge fhugepub [Ox8000] : とこのセグメントが生成されます。 特集 ROM 化プログラミング考察 49 なコーディングを行うとこのセグメントが 定数の nea 「セグメントて、す。以下のよう CONST セグメント る必要はありません。 から , 転送するプログラムを新たに記述す ルーチンのソースリストが付属しています す。 ROM 化ツールては通常スタートアップ ーチンて、 RAM 上に転送する必要がありま め , 初期値を ROM に置きスタートアップル このセグメントは DGROUP に属するた func( " DATA" ) ; static int nea 「 fstatdat=10 ; int near fpubdat=10 : このセグメントが生成されます。 て、す。以下のようなコーディングを行うと 初期値をもった neari•—タのセグメント DATA セグメント 11 ) 。 る領域などに使用すると便利て、す (Fig. て、きるため , 生産オーダをバックアップす ントは任意のアドレスに割り付けることが HUGE BSS セグメントと FAR BSS±グメ ります。 このセグメントは RAM 上に置くことにな int fa 「 ffa 「 pub ・ このセグメントが生成されます。 て、す。以下のようなコーディングを行うと 初期値をもたない fa 「データのセグメント
プルーチンて、初期値を RAM 上に転送すると ンを行うことはないため , リンク時にリロ 化て、は通常 ROM と RAM は不連続て、あるた いうような細工を行わない限り , ROM 上に ケーション情報が生成されないようにリン め , コマンドファイルヘッダは ( B ) の形式に 置くことになります。 力のスイッチを指定します。 Fig. 5 からもわ なります。 BSS セグメント かるように BSS セグメントの領域は 68K ファ SENDC68 ユーティリティは . 68K ファイル 初期値をもたない変数が置かれる領域て、 イルの中には書き込まれておらず , 先頭ア のコマンドファイルヘッダから各セグメン す (List 7 ) 。この領域は RAM 上に置かれ , ドレスとバイト数がコマンドファイルヘッ トの先頭アドレスを取得し , TEXT セグメン CP / M ー 68K て、はスタートアップルーチンて、 ダに書き込まれているだけて、す。また , ROM トと DATA セグメントを S レコードに変換し BSS セグメントをゼロクリアしていますか ら , ROM 化の場合て、も通常はスタートアッ コラム 1 プルーチンて、ゼロクリアします。 スタック領域 スタック領域に関しては , スタックポイ ンタをスタートアップルーチンて、セットす るだけて、す。 C プログラムて、は表には出てき ません。しいていえば auto 変数がスタック 上に領域が確保されるくらいて、 , あとはサ プルーチンコールのように無意識のうちに 使用されます。 CP / M ー 68K て、はスタック領域を定義する 特別なセグメントがないため , BSS セグメン トの中にスタック領域を確保します。 上記以外にも ma Ⅱ oc 関数などて、動的にメ モリを獲得するためのヒープ領域があるの て、すが , ROM 化の用途て、はメモリ配置は固 定て、ある場合がほとんどて、すから , ほとん どの場合ヒープ領域は不要て、す。 CP / M ー 68K て、はリンカ (L068) て、 TEXT セグメント DATA セグメント BSS セグメント の 3 つの領域の開始アドレスが設定て、きるた め , システム構成にあわせてアドレスを決 定することがて、きます。リンカて、生成され た . 68K ファイルを SENDC68 ユーティリティ て、 S レコードに変換して ROM 化を行うこと がて、きます。 68 マンドファイル ォット Fig. 5 に 68K コマンドファイルフォー - ・マッ トを示します。 ROM 化の場合リロケー ショ 44 CMAGAZINE 1990 11 どのようなコーディングを行うと , どの セグメントが生成されるかを確認しておく ことは ROM 化にあたって必要です。このため にはコンバイラでアセンプリリストを生成 させます。たとえば , MS-C 5 コであれば /Fa をつけて List MS-C 5.1 テストプログラム ( testl . c ) コンヾイラの 生成セクメントの 確認 int near fpub; 2 : int near fpubdat 3 : int far ffarpub; 4 : int far ffardat ー int huge fhugepubC 0X8000 ] : 5 : 6 : int huge fhugedatC 0X8000 ] 7 : static int near fstat; 8 : static int near fstatdat 9 : static int far ffarstat; 1 0 : static int far ffarstatdat 11 : static int huge fhugestat[ 0X8000 ] : 12 : static int huge fhugestatdat[ 0X8000 ] 13 : 14 : const int near fpubcon const int far ffarcon ニ 10 : const int huge fhugecon[ 0X8000 ] static const int near fstatcon ニ 10 ; 17 : 18 : static const int far ffarstatcon 19 : static const int huge fhugestatcon[ 0X8000 ] ist Turbo C 2 ℃テストプログラム ( test2. c ) ーハ 4 れ一ハ丸ハ ・ハ人れ ーハーハ O みハ 4 ハ い 0 ー CO ーハー員ハ 0 ーハ 4 ハーハ・ハ人胤 ・ BSS を int near fpub; 'DATA' 2 : int near fpubdat 3 : int far *pfarpub; 'DATA' int far *pfardat 5 : i nt huge *phugepub : / * 'DATA' 6 : int huge *phugedat 7 : static int near fstat; 'DATA' 8 : static int near fstatdat 9 : static int far *pfarstat; 'DATAi 10 : static int far *pfarstatdat 1 1 : static int huge *phugestat; 12 : static int huge *phugestatdat ニ 13 : 14 : const int near fpubcon = 10 : ( int far * ) 0XC0000000 し : / * ・ DATA' const int far *pfarcon ( int huge * ) 0XC0000000 し : 'DATA ・ const int huge *phugecon 'DATA ・ 1 7 : static const int near fstatcon ( int far * ) 0XC0000000L : DATA' 18 : static const int far *pfarstatcon ( int huge * ) 0XC0000000 し : / * ' DATA' 1 9 : static const int huge *phugestatcon ( int far * ) 0XC0000000 し : ( int huge * ) 0XC0000000 し : ( int far * ) 0XC0000000 し : ( int huge * ) 0XC0000000 し :
C プログラムてはスタートアップルーチン から main 関数が呼び出されることになって います。 ROM 化システムて、も通常 , これに あわせてスタートアップルーチンから main 関数を呼び出します。このときスタートア ップルーチンはアセンプラて、記述しますか ら , 先頭にを付加します ( 注 1 ) 。 プルを設定します。 ・ BSS セグメントのゼロクリア ・ハードウェアの初期化 ・ユーザスタックポインタの設定 ・ユーザモードに切り換え ・ハードウェア割り込みの許可 ・メインルーチン main の呼び出し ( 注 1 ) c 言語とアセンプラのこの約束事は処理系 によって違います。たとえば MS-C,Turbo C,CP/M- 68KC などでは maln キー - → maln となりますが , LS ℃ー 86 では最後に一を付加して main ←ー→ main となります。また , OPT ー C86 では何も付加されず main + ー→ rnaln となります。 List1-D List1-C 36 : fpubcon label 10 38 : -pfarcon label 39 : 0 40 : dw ー 16384 phugecon label 42 : 0 dw 43 : dw ヨ 6384 44 : fstatcon label word 45 : 10 dw 46 : pfarstatcon label dword 0 dw 48 : ー 16384 dw 49 : phugestatcon label 50 : dw ー 16384 dw 52 : DATA ends 53 : _BSS segment word publ ic 'BSS' 54 : _fpub label word 2 dup ( ? ) 55 : db 56 : fstat 1 abel word 2 dup ( ? ) 57 : db 58 : _pfarpub label dword 4 d 叩 ( ? ) 59 : db 60 : -phugepub label dword 4 d 叩 ( ? ) db 62 : pfarstat label dword 63 : 4 d 叩 ( ? ) db 64 : phugestat b dword 65 : 4 d 叩 ( ? ) db 66 : _BSS endS 67 : ?debug C E9 68 : _DATA segment word public VDATA' 69 : s@ label byte -DATA endS 71 : TEST2_TEXT segment byte public 'CODE' 72 : TEST2_TEXT endS 73 : -phugestatdat phugestatdat equ -phugestatcon phugestatcon eq u 75 : _pfarstatdat pfarstatdat equ pfarstatcon pfarstatcon equ -phugestat phugestat equ 78 : -pfarstat pfarstat equ 79 : public -phugedat 80 : fstatdat fstatdat equ pub I i c -phugecon 82 : public -pfardat fstatcon fstatcon equ 84 : public -fpubdat 85 : public pfarcon 86 : public fpubcon 87 : pub I i c -phugepub public pfarpub 89 : fstat equ fstat 90 : public -fpub end word dword ENDS 96 : TESTIII_DATA SEGMENT 97 : _BSS DW 01H DUP ( ? ) 98 : $S106-fstat ENDS 99 : BSS SEGMENT 100 : TEST15_DATA ORG 101 : 102 : $S108_ffarstat DW 01H DUP ( ? ) ENDS 103 : TEST15_DATA SEGMENT 104 : TEST16_DATA 105 : $S110_fhugestat DW 08000H DUP ( ? ) ENDS 106 : TEST16_DATA 107 : END dword dword 0 List 1 ー B のアセンプリリスト lSt ifndef ??version 2 : ?debug macro 3 : endm 4 : end i f ?debug S "test2. c" 6 : TEST2_TEXT segment byte public 'CODE' 7 : DGROUP gro 叩 DATA, _BSS assume cs:TEST2_TEXT, ds:DGROUP 8 : 9 : TEST2_TEXT endS segment word public 'DATA' DATA 1 1 : d@ label byte 12 : d@w bel word 13 : DATA ends segment word public 'BSS' -BSS 15 : b@ label byte 16 : b@w label word ?debug C E9CE7Al 1150774657374322E63 17 : _BSS endS 19 : _DATA segment word publ ic 'DATA' 20 : _fpubdat label word 10 dw 22 : -pfardat ね b 引 dword 23 : 0 dw ー 16384 24 : dw 25 : label phugedat 0 26 : dw ー 16384 27 : dw label 28 : fstatdat 10 dw 30 : pfarstatdat label 0 dw 32 : ー 16 384 dw 33 : phugestatdat label 34 : dw ー 16384 35 : dw dword word dword dword 0 46 CMAGAZINE 1990 11
( 2 ) 初期値を ROM 上に置いてスタートアップ ルーチンで RAM 上に転送する ( Fig. 2 ) この方法は言葉て、いえば簡単なのて、すが , コンパイラが生成するメモリ配置に精通し ていないと難しい方法てす。 たとえば初期値をもったデータ領域の開 Fig. 5 68K コマンドファイルフォーマット / 0 : リロケーション情報無 としては初期値に関しては ROM と RAM に ように対処て、きることて、すが , デメリット の数に関係なく ( 仮に非常に多くても ) 同じ この方法のメリットは初期値をもつ変数 て、きません。 始アドレスやバイト数がわからないと対処 二重に領域をとることになり , 初期値のバ イト数が多い場合 ( たとえば数百 K バイト ) , メ モリが無駄になってしまいます ( 最近はメモ リが安くなってきましたから , あまり問題 にはなりませんが ) 。 ファイル先頭 コマンドファイルヘッダ TEXT セグメント DATA セグメント シンホルテープル リロケーション情報 Oh 2h 6h OA h 1Ah 16h 12h OEh ( A ) 連続プログラムセグメントのヘッダ形式 リロケーションフラグ = 0 : リロケーション情報有 TEXT セグメントの先頭アドレス 常に 0 ( システム予約 ) シンボルテープルのバイト数 BSS セグメントのバイト数 DATA セグメントのバイト数 TEXT セグメントのバイト数 601Ah Oh 2h 6h OAh OEh 12h 16h IA h 1Ch 20h ( B ) 非連続なプログラムセグメントのヘッダ形式 BSS セグメントの先頭アドレス DATA セグメントの先頭アドレス リロケーションフラグ = 0 : リロケーション情報有 , / 0 : リロケーション情報無 TEXT セグメントの先頭アドレス 常に 0 ( システム予約 ) シンボルテーフルのバイト数 BSS セグメントのバイト数 DATA セグメントのバイト数 TEXT セグメントのバイト数 601Bh 40 CMAGAZINE 1990 11
フラグをつけることによって , —x フラグて、 て、は , 基本的に①②の方法を考えることに メーデレによる データが指定されたのとデータと同じ領域 するが , 場合によっては , ③以外の方法が ツ違い へ割り振ることがて、きる。 使えない場合もあるのて、 , ③についても最 後に簡単に触れることにする。 —x フラグはそのあとに数値をとり , それ ニマムモードては , 前述したとおり , ①②は , 最初に説明した , ROM 化可能な が指定になる。その数値の意味は , 関数ビ 8080 モデルになる。この状態て、は関数とデ プログラムをどう書くかという問題になる。 ット ( 04 ) , リテラルビット ( 02 ) , データビ ット ( 01 ) のそれぞれが 1 ならばテキスト領 すなわち , 0 以外の値て、初期化される静的変 ータは同一のアドレス空間上にあるのて、 , 数は書き換えてはいけないということて、あ 域 , 0 ならばデータ領域という意味になる。 アドレス空間を気にすることなくマップす る。そのうえて、 , 後述するように , コンパ 通常 , ー x6 かー x4 が用いられる。 ることがて、きる。 イル時の指定などて定数や変数をそれぞれ ー x6 は関数とリテラルのビットが立って そこて、通常は , 関数とリテラルをテキス いるから , 関数とリテラルがテキスト領域 テキスト領域に割り振るかデータ領域に割 ト領域に , データをデータ領域に , 0 初期化 り振るかを指定てきるようになっている。 へ , データがデータ領域へマップされる。 データを BSS 領域に割り当てる。 マキシマムモードて、は , 8080 モデルて、あ これはミニマムモードて、用いられる。 その一方て、 ( これも後述するが ) , マキシ マムモードて、は , ①の方法は一般には不可 ー x4 て、は関数ビットのみが立っているの る場合を除いて , 関数とデータは異なるア ドレス空間上にあることになる。すなわち , て、 , 関数のみテキスト領域へ , リテラルと 能になる。 BSS 領域は , 実行前にすべて 0 に初期化さ 関数は CP レジスタに示されるセグメン・ト データはデータ領域へマップされる。これ はマキシマムモードて、用いられる。 れる領域て、ある。初期値として 0 をもつ静的 に , データは DP レジスタに示されるセグメ 変数や , 初期値をとくに指定されていない ントに配置する必要がある。 静的変数に使用てきる。この領域も書き換 通常は , 関数をテキスト領域に , リテラ えられるのて、 RAM に割り当てられる必要が ルとデータをデブタ領域に , 0 初期化データ あるのだが , 実行前または実行時のいちば を BSS 領域に割り当てる。 こうすることに 実行形式オプジェクトは , スタートアッ ん最初にすべて 0 にクリアされる必要があ よって , リテラルについてもほかのデータ プ部 , プログラムをコンパイルしたオプジ る。 ROM 化にあたっても , この領域を使用 と同じようにアクセスて、きるようになる。 ェクト , 実行時ライプラリの 3 つをリンカて、 することにとくに問題はないが , 0 にクリア これを 8080 モデルの場合と同じようにリ リンクすることによってて、きあがる。実行 するという作業は必要て、ある。 テラルもテキスト領域にマップすると , リ 時ライプラリは C の標準的なライプラリて、あ テラルにアクセスするたびに , 一時的に DP なお , BSS 領域に似たものにスタックヒ レジスタまたは EP レジスタを CP レジスタと り , これを使わないて、プログラムを書くこ ープ領域がある。その名のとおり , スタッ 同じ値にする必要があり , コードサイズお ともて、きるが , 非生産的て、ある。 クがここに置かれる。 auto 変数は基本的にスタック上に確保さ よび実行速度の両面て、不利になる。また , そして , リンク時に各記憶領域のマップ されるアドレスも決定される。そのときに れる。また , ma Ⅱ oc ( ) 関数などの標準関数 リテラルへのポインタとデータへのポイン て、確保される動的メモリもこの領域に確保 タの間の整合性が保証て、きなくなり , 正常 ROM 領域と RAM 領域が最終決定されるわ されることがある。 にアクセスて、きなくなる場合もある。 けて、あるが , 最初に述べた ROM 化可能なプ この領域は当然 RAM に割り当てられ , 初 この場合 , リテラルをデータ領域にマッ ログラムて、あれば , テキスト領域は ROM, 期化の必要もない。プログラムの実行前ま プしているのて、 , データ領域は ROM て、ある BSS 領域は RAM に割り当てることがて、きる たは実行時の入口て、スタックポインタ ( H8 / 必要がある。 て、あろう。 WSL C のコードジェネレータ ( p2. h85 ) に 500 ては R7 レジスタがスタックポインタにな データ領域はコードジェネレータ (p2. h85 ) る。以下 SP レジスタ ) をこの領域のもっとも は , オプションフラグとして「一 x 」というも へのフラグが一 x4 の場合は ROM て、ある必要 大きいアドレスにセットする必要がある。 のがある。これは関数 , リテラル , データ があるが , ー x6 の場合はプログラム中て初期 をテキスト領域 , データ領域のどちらに割 以上 , 4 種類のデータを 3 種類の記憶領域 値のあるものにすべて const をつけてリテラ にマップするのてあるが , H8 / 500 て、は CPU り振るかを指定するものて、ある。 ルにしてあればなくなってしまうはずてあ のモードによって多少考え方が変わる ( Fig. 0 初期化データについては必ず BSS 領域に 割り振られるが , 「—bss 」というオプション スタートアップ部ては , 今まて、出てきた アップ 1 参照 ) 。 58 CMAGAZINE 1990 11
static const int nea 「 fstatdat=10 ; これ以外の書式て、は , const を付加しても 、、 DATA" や、、 FAR DATA 〃のクラスになります。 このセグメントは DGROUP に属するため , 初期値を ROM に置いてスタートアップルー チンて、 RAM に転送する必要があります。 BSS セグメント 初期値をもたない near データのセグメン トて、す。以下のようなコーディングを行う とこのセグメントが生成されます。 int near fpub ; static int near fstat : このセグメントは RAM 上に置くことにな ります。 Turbo C 2.0 の標準的なセグメントの配 置を Fig. 12—Fig. 16 に示します。基本的に は MS-C 5.1 から FAR DATA セグメント HUGE BSS セグメント FAR BSS セグメント CONST セグメント を取り除いたような感じになります。 Turbo C て、は far 配列や huge 配列などが宣言て、きな いため , このようになります。 メモリモデルのなかて、ヒュージモデル ( Fig. 16 ) が特別て、す。ほかのメモリモデルて、は DATA セグメントと BSS セグメントが生成 され , 初期値をもったデータと初期値をも たないデータが区別されますが , ヒュージ モデルてはこれらが同一のセグメントに生 成されます ( その代わりに DGROUP がな い ) 。したがってヒュージモデルて、は 初期値をもったデータ 文字列 などを使用すると初期値をもたないデータ と区別がてきなくなるため , ROM 化がて、き なくなります ( 市販の ROM 化ツールが Tur 50 CMAGAZINE 1990 11 生成されます。 00h ~ 01 h 02h ~ 03h 04h ~ 05h 06h ~ 07h 08h ~ 09h OAh—OBh OCh—ODh 14h ~ 15h 1 6 h ~ 1 7 h 1 8 h— 1 9 h 1 Ah ~ 1 B h TabIe 2 EXE ファイルヘッダ オフセット Fig. 17 スタ 内 4Dh, 5Ah : EXE 形式識別マーク 最後のページに入っているノヾイト数 512 バイト単位のファイルの大きさ リロケーションテープルの項目数 ヘッダのバラグラフサイズ ロードするプログラムの他に必要とされるノヾラグラフの最小数 ロードするプログラムの他に必要とされるノヾラグラフの最大数 スタックセグメント ( SS ) のロードモジュール先頭からの相対アドレス 実行直前に SP レジスタにわたされる値 リード補数チェックサム 実行直前ロ P レジスタにわたされる値 コードセグメントのロードモジュール先頭からの相対アドレス ファイル内の先頭のリロケーション項目のオフセット オーノヾレイ番号 ートアドレス FFFFOh の割り付け RAM startup ROM FFFFOh JMP FAR PTR startup