コンパイル用バッチファイル
まずC言語プログラミングの前に、Windows上でのプログラムのコンパイルと6502-COREへのロード用のファイルの作成を手軽に行えるように、1つだけのソースファイルのプログラムをコンパイルするためのバッチファイルを作成しましょう。
バッチファイルを「コンパイル用バッチファイル:cc65exec.bat」に紹介します。
PATH=C:\XENESIS\6502\CC65\bin;C:\XENESIS\SREC
cl65 -t none --cpu 65C02 -O %1.c -o %1.bin -m %1.map xcore.lib
srec_cat %1.bin -binary -offset 0x1000 -o %1.SR
copy %1.SR + STARTVEC.SREC %1.SREC
DEL %1.SR %1.bin
コンパイル用バッチファイル:cc65exec.bat
バッチファイルの各行は以下の様な処理を行います。
- 1行目:コンパイラやツールの実行ファイルのパスを設定する
- 2行目:バッチファイルの引数で指定したプログラムをコンパイルし、ライブラリとリンクしてバイナリファイルを作る
- 3行目:バイナリファイルを6502-COREにロードするためのSレコード形式に変換する
- 4行目:Sレコード形式に、プログラムの実行開始アドレスを自動設定するためのデータを追加する
- 5行目:いらないファイルを削除する
バッチファイルの1行目は、ご自身がCC65やSレコードツールをインストールしたパスを反映させてください。
4行目のSTARTVEC.SRECは、プログラムを6502-CORE にロードした際に、プログラムの実行開始アドレスを Universal Monitorに自動設定し、Gコマンドで開始アドレスの指定を省略できるようにするものです。
STARTVEC.SRECデモパッケージに含まれていますが、作成法を\ref{c-unimon-go}節に示します。
以下にバッチファイルcc65exec.batの使用法を示します。
例えば、evalpr.cというファイルをコンパイルする場合には、拡張子のcを取って引数に指定して以下の様にバッチファイルを実行します。
% cc65exec evalpr
バッチファイルを利用したコンパイル
最初のCプログラム
お約束のHello Worldは端折らせていただいて、繰り返し処理により0から9までを出力するプログラムevalpr.cを図に示します。
#include <xcore.h>
void main()
{
int i ;
for (i = 0; i < 10; i++) {
cprintf("i = %d\n", i) ; // printfの画面出力版
}
wexit() ; // プログラムの終了:モニタのウォームスタート
}
evalpr.c
C言語のプログラムでは、多くのプログラムでstdio.hがインクルードされていますが、6502-CORE にはstdio.hが取り扱う標準入出力やファイルIOの機能がないので、stdio.hがサポートする関数群を使うことができず、したがってstdio.hをインクルードしません。
画面に対する入出力機能がxcore.hに宣言されているのでstdio.hの代わりにxcore.hをインクルードしてください。
evalpr.c には以下の様なライブラリ関数が使用されています。
- cprintf()は、画面出力専用のprintf()です。
- wexit()は、プログラムを終了しUniversal Monitorをウォームスタートさせます。
プログラムを終了させ、Universal Monitorをコールドスタートさせるcexit()関数もあります。
コールドスタートすると、起動後の経過時間も含め、Universal Monitorの全ての設定が初期化されます。
evalpr.c は先に作成したコンパイル用のバッチファイルを使用して、図\ref{fig:c-cc65exec-do2}の様にcc65exec evalprと入力して簡単にコンパイルできます。
% cc65exec evalpr
バッチファイルによるevalpr.cのコンパイル
コンパイルによりSレコードファイルevalpr.SRECが生成されます。
図\ref{fig:ex-cdemo-1}に示すように、6502-COREにevalpr.SRECをロードし、Gコマンドで実行することができます。
コンパイラで生成されたコードのサイズも気になりますよね。
コンパイル処理では、ファイルの拡張子をmapとしたファイルが生成されており、その中の[Segment list]を見ると、生成されたコードサイズを確認することができます。
図\ref{fig:c-demo-test1-map}には、evalpr.cのコンパイルコードのアドレスマッピングやコードサイズが示されています。
STARTUP, ONCE, CODEのSizeの合計が、自分自身で書いたプログラムだけでなくくっついてきたライブラリも含めたプログラムのサイズです。
また、RODATA,DATA,BSSのSizeがデータのサイズです。
Segment list:
-------------
Name Start End Size Align
----------------------------------------------------
ZEROPAGE 000080 000099 00001A 00001
STARTUP 001000 001016 000017 00001
ONCE 001017 001022 00000C 00001
CODE 001023 001725 000703 00001
RODATA 001726 0017D4 0000AF 00001
DATA 0017D5 00180B 000037 00001
BSS 00180C 001837 00002C 00001
生成コードのメモリマップ:evalpr.map
全部ひっくるめると2Kバイト程度ですね。こんな短いプログラムでTinyBasicが書けるサイズを必要とするの?と思いますよね。
mapファイルの中身をよく確認するとわかりますが、実際には、cprintf()関係の処理が1KB程度を占めています。
逆に言えば、cprintf()を使用しなければ、あっという間に1KB程度コードサイズは減少します。
その他にも、C言語の処理を行う各種のサブルーチンが多くのサイズを占めているため、思いのほかプログラムのサイズが大きくなっています。
Cのプログラムはプログラムが小さくても、様々なライブラリ関数を使用すると初期的なコードサイズが急激に増大しますが、その後はプログラムの行数が増えても、使用されるライブラリ関数が増えなければコードサイズの増加は緩やかです。
ライブラリ関数の追加使用
もう少し多くの入出力用の基本的なライブラリ関数を使用するevalprsc.cを図\ref{fig:c-demo-evalprsc}に示します。
#include <xcore.h>
void main()
{
int i, j, n, m ;
clrscr() ; // 画面の消去とカーソルを画面左上に移動
cputs("Input Int Num: ") ; // 文字列を画面に出力
cscanf("%d", &n) ; // scanfのキーボード入力版
for (i = 0; i < n; i++) {
cprintf("i = %d ", i) ;
m = i % 70 ;
for (j = 0; j < m; j++)
cputc('*') ;
cputc('\n') ; // 文字を画面に出力
}
wexit() ;
}
evalprsc.c
evalpr.c.c のプログラムのライブラリに加え、evalprsc.cでは以下の様なライブラリ関数が使用されています。
- clrscr()は画面を消去し、カーソルを画面の左上に移動させます。
- cputs()は、文字列をコンソールに出力します。
- cscanf()は、コンソール入力専用のscanf()です。
- cputc()は、文字をコンソールに出力します。
evalprsc.cもevalpr.c同様にバッチファイルでコンパイルしてevalprsc.SRECを生成し、6502-CORE にロードして実行できます。
図\ref{fig:ex-cdemo-2}に示すように、6502-COREにevalprsc.SRECをロードし、Gコマンドで実行することができます。
evalprsc.cのmapファイルのSegment listを図\ref{fig:c-demo-evalprsc-map}に示します。
Segment list:
-------------
Name Start End Size Align
----------------------------------------------------
ZEROPAGE 000080 000099 00001A 00001
STARTUP 001000 001016 000017 00001
ONCE 001017 001022 00000C 00001
CODE 001023 002219 0011F7 00001
RODATA 00221A 0022FA 0000E1 00001
DATA 0022FB 002333 000039 00001
BSS 002334 0023A6 000073 00001
生成コードのメモリマップ:evalprsc.c
今度は、全部ひっくるめると5Kバイト程度とかなり大きくなっています。
evalpr.cの時と同様にmapファイルを確認すると、cscanf()関係だけで2Kバイト以上のコードサイズを占めているようです。
オリジナルのUNIXでも同様ですが、printf系、scanf系のライブラリ関数は大メモリぐらいですね。