これらの開発ツール群はもともと UNIX 上で開発、発展してきたもので、 UNIX 上で動作させると非常に効率の良い開発環境として利用することが できます。
本橋さんが、PlayStation の実行形式のクロスコンパイル環境を 作成するためのパッチを、ソニーが公開したコードを元に作成して くださいました。これを用いることで、UNIX 上でも PlayStation の開発環境が構築できます。 この文書ではその開発環境を利用した実際の開発の手順について解説してあります。
注意事項
PlayStation の開発においては、PlayStation で動作する実行形式のファイルを 別のマシン上で作成し、その実行ファイルを PlayStation に転送して実行させます。 このようなプログラム作成と実行を行うマシンが違う開発環境のことを クロス環境と言い、そのために利用するコンパイラのことを クロスコンパイラと呼びます。
UNIX 上で PlayStation の実行ファイルを作成するにはそのUNIX で 動作する PlayStation 向けのクロスコンパイラを作成する必要があります。 GNU のコンパイル環境である、binutils と gcc は、はじめからクロスコンパイル 環境を構築するための仕組みを持っており、ターゲットのアーキテクチャの CPU や 実行ファイルの形式などがわかっていればクロスコンパイラとして 動作させることができます。
PlayStatin 向けのクロスコンパイラを構築するためのパッチを 本橋さんが作成してくださっています。これらのパッチををあてることで、 PlayStation の実行ファイルを生成する gcc を作成できます。
このページにパッチと各ツールのインストール方法が紹介されています。 また、実行ファイルを PlayStation に転送して実行するためのプログラム も必要ですが、これも本橋さんが hsssutils として作成して同じページに おいてあります。ここを参考にして、ツール群をインストールして下さい。
以下のようなコマンドが作成されます。 通常 /usr/local/bin にインストールされるはずです。
psx-ar アーカイバ psx-as アセンブラ psx-ld リンクエディタ psx-nm シンボル名表示 psx-ranlib ライブラリの参照テーブル作成 psx-strings ファイル中の文字列をさがす psx-size オブジェクトファイルのサイズ表示 psx-strip 実行ファイル中の不要な文字列の削除 psx-gcc GNU C コンパイラ psx-gdb GNU デバッガ psxfer PlayStation との通信プログラム
基本的には UNIX の通常の cc や gcc の代わりに psx-gcc をつかうだけです。make などは UNIX 標準のものをそのまま使用します。 Makefile の中に、CC = psx-gcc と記述しておけば良いでしょう。 UNIX のバージョン管理や差分とりなどの豊富なコマンド群はそのまま利用できます。
使用方法は次のとおりです。
psxfer -nfile -a80140000 データの転送 UNIX -> PS psxfer -nfile -a80140000 -s1000 データの転送 PS -> UNIX psxfer file プログラムの転送 psxfer -g file プログラムの転送/実行 psxfer -g プログラムの実行
gdb 実行中に help コマンドを入力することで 簡単なヘルプを見ることが可能です。 正式なドキュメントは、配布に含まれている info ファイルです。
ここでは PlayStation の実行ファイルと、HSSプロトコルによる 通信をサポートした psx-gdb と、HSS プロトコルによる転送プログラム psxfer を用いたデバッグの手順を示します。
ソースレベルでのデバッグを行うためには、コンパイル時に -g オプションを つけとコンパイルして、実行ファイルの中にデバッグ情報を埋め込む 必要があります。コンパイルオプションとして -g をつけると、 最適化が無効になって、変数や行番号などの情報などがオブジェクトに うめこまれます。Makefile などで、CFLAGS に -g を入れておきます。
# CFLAGS = -O # OPTIMIZE CFLAGS = -g # DEBUGGING
また注意点ですが、デバッガがデバッグのための情報をやりとりするために シリアル通信を使用しています。このため、プログラム側で シリアル通信を行うと、誤動作します。 つまり printf などは使用してはいけません。 しかも、たとえプログラムでシリアル線を使用していなくても、 PlayStation のライブラリがかってにメッセージを出力します。 これを防ぐために、プログラムが開始してすぐの時点に、
close(0); close(1);をいれるようにして下さい。 コンパイルが完了した状態から解説していきます。
% psxfer programこのとき -g オプションをつけると実際に実行することになります。 データなどについてはあらかじめ psxfer -nfile -aaddr で転送しておきます。
これにより、プログラムファイルが PlayStation に転送され、 実行可能な状態に展開されます。実際には、未定義変数領域の確保、 スタック、プログラムカウンタの初期化などが行われます。
続いて gdb を実行します。
% psx-gdb program
これにより、program のなかに埋め込まれた情報を gdb が読みだして、 ソースレベルでのデバッグが可能な状態になります。
このあと gdb のプロンプトが表示されるので、リモートデバッグの モードに移行します。
(gdb) set remotebaud 115200 (gdb) target hss /dev/cua00
左にでている (gdb) というのは、コマンド入力をうながすプロンプトです。 1 つめのコマンドは通信速度の指定です。 2 つめは、hss を用いたリモートデバッグで、接続先デバイスが /dev/cua00 であるというように指定しています。デバイス名は OS や環境によって 変わって来ます。
これを毎回行うのが面倒な場合は、カレントディレクトリなどの .gdbinit に 記述しておけば良いです。これについては後述します。
この状態で、実行可能な状態になってます。 ここからデバッグのためのコマンドを入力していくことになります。
break 次の実行命令に設定 break function 指定した関数の先頭に設定 break -offset break +offset 現在の中断位置の offset 行前後 break linenum 現在参照中のファイルの行番号 break filename:function break filename:linenum ファイルを指定する場合 tbreak ... 1回のみ動作するポイント現在設定されているブレークポイントは、info break で参照できます。 ブレークポイントの削除には次のようなコマンドを使用します。
clear 現在の場所のブレークポイントを削除 clear function clear linenum 関数、行に設定されたポイントを削除 delete nums ... 番号で示されるポイントを削除
他にも、無効化/有効化、条件づけなどが可能です。 詳しくは help や info を参照して下さい。
プロンプトに対して run コマンドを入力すると、実際の 実行が開始されます。 実行中に何らかのシグナルが通知されると、 プログラムが中断して gdb のコマンドプロンプトに戻って来ます。
シグナルというのは、OS からプログラムに対して送られて来る 割り込みの要求です。なんらかの要因でプログラムが実行できなく なったときなどに送られて来ます。 PlayStation の場合は次のようなシグナルが送られて来て動作が中断します。
番号 4 SIGILL オーバーフローや演算のエラーなどが発生した 5 SIGTRAP プログラムが中断した(ブレークポインタ、終了) 10 SIGBUS バスエラーが発生した 11 SIGSEGV 不正なセグメントへのアクセス
SIGBUS というのは、メモリの境界に対して不正なアクセスを行った時に 発生します。PlayStation の CPU として使用されている R3000 は、 基本的に 4 byte 単位のメモリアクセスを行います。 4byte のデータをアクセスする時には、かならずそのアドレスも4byte 単位に なる必要があります。これを破ると SIGBUS が発生します。 char のポインタに対して long でアクセスしたりすると発生します。 (たまたま境界と一致した場合は発生しません)
SIGSEG というのは、メモリの領域への不正なアクセスが行われた場合に 発生します。PlayStation においても一応簡単なメモリの領域管理 がおこなわれており、データ領域でないアドレスに書き込んだりしようと するとこのシグナルが送られて来ます。
これら2つのシグナルがでた時は、ポインタ関連でなにか変なことをしてます。 その当たりを確認して見て下さい。ポインタの内容を表示してみると 原因がわかる場合が多いです。
以下実行に関連したコマンド一覧です。
run プログラムの実行を開始します。 cont ブレークポイントなどで中断したプログラムを継続させます until ... 指定した部分(行、アドレス、関数)が終るまで実行します step [n] 1行実行します。回数が指定できます。 next [n] step と同様ですが、関数のなかには入っていきません finish 現在の関数呼び出し終了まで実行します stepi nexti マシンインストラクションレベルで動作します。
gdb では、このスタックフレームを解析して、 現在実行中の部分がどういう引数でどう呼び出されて来たのかを 追跡する機能があります。 プログラムの流れを確認するときに便利です。
変数を参照するときなどは、たとえばローカル変数は、現在 注目しているフレームのもののみが参照できます。 プログラムが中断した時点では、その中断した場所のフレームが 注目の対象になっています。
次のようなコマンドが使用できます。
backtrace 呼び出されて来たフレームの一覧を表示します where backtrace のエイリアスです frame n 指定したフレームを選択します up [n] n個前のフレームを選択します。 down [n] n個次のフレームを選択します。これらのコマンドを実行すると、そのフレームに関連する情報を 表示します。
変数の内容の表示には、print コマンドを用います。 しよう方法は単純で、print 変数名 とします。書式指定付きの printf も あります。書式は C の printf と同様です。
例: print
DOS 版の開発ツールについているものをちょっといじったものです。 これの中で次のようなコマンドが拡張されています。
start HSS通信モードの起動 dr レジスタ内容の一覧 si stepi して レジスタ一覧をだす ni nexti して レジスタ一覧をだす
この例では、通信の設定を "start" と入力することで行うようになっています。 これを psx-gdb が起動した時に常に行うようにする場合は、
define start set remotebaud 115200 target hss /dev/cua00 end document start start remote PSX debugging endの部分を
set remotebaud 115200 target hss /dev/cua00というように変更して、start の定義のわくをはずせば良いです。
hilit19を使用するには、$HOME/.emacs などに次のような行を加えます。
(cond (window-system (setq hilit-mode-enable-list '(not text-mode) hilit-background-mode 'light) (require 'hilit19)))この設定は Mule が Window System で動作しているときのみ有効になります。 hilit-mode-enable-list で、text-mode 以外で hilit19 を有効にしています。 hilit-background-mode では、デフォルトの色を設定しています。 背景を暗い色にしている場合は、これを 'dark にしたほうが読みやすく なります。
hilit19に関する詳しい情報は、インストールされている mule の lisp ディレクトリ (/usr/local/lib/mule/19.28/lisp など。バージョンなどにより 少し異なる) の、hilit19.el という hilit19 のソースを直接参照して下さい。
c-mode は、C 言語でのプログラミング作成を支援するためのモードです。 自動的なインデントや、括弧の対応表示などを行ってくれます。基本的な操作
TAB インデントを行う C-c C-u #ifdef などの階層内を1つあがってその先頭に移動 C-c C-p #ifdef などの階層の同じ階層の次の部分に移動 C-c C-n #ifdef などの階層の同じ階層の前の部分に移動 ESC e {}やifなどの対応の末尾に移動 ESC a {}やifなどの対応の先頭に移動 ESC C-h 関数全体をマーク最後の関数全体のマークは、C-h と DEL を入れ替えたりしていると 誤動作します。こういう場合は、C-M-h (Ctrl と Meta(Alt) と hを同時に押す) で大丈夫なはずです。
関数全体マークはかなり便利です。 たとえばソースの中で関数を移動させたい場合などは、目的の関数内で ESC C-h して、C-w (kill-region) して目的の場所で C-y (yank) します。
c-mode の詳しい操作方法は、c のファイル (hogehoge.c) を開いて c-mode にした状態で、M-x help-for-help m とすることで参照できます。 これは、現在のモードに関するヘルプを表示させるコマンドです。
設定の例です。
(setq c-mode-hook (function (lambda () (setq c-tab-always-indent nil c-auto-newline nil c-continued-statement-offset 4 c-indent-level 4 c-label-offset -4 tab-width 4 ))))setq でパラメータを調整しています。次のようなパラメータが 調整できます。
M-x compile としてコンパイルモードを起動します。 すると、ミニバッファでコンパイルのためのコマンド入力待ちになります。 デフォルトは make -k になっているので、Makefile がある場合はそのまま リターンで良いです。いちど入力したコマンドは次回も有効です。
編集中のファイルで更新されてないものがある場合、ディスクに 書き込むか聞いて来るので、適宜答えてください。
新しいバッファが開いてそこでコンパイルが開始されます。 エラーがでた場合は、C-o でバッファを移動し、目的の行に カーソルをあわせて C-c C-c と入力することで、そのファイルのその行 を開くことができます。 X Window System などでマウスを使用している場合は、その行にマウスカーソルを あわせて中ボタンでもジャンプします。
この状態で通常通りに GDB を利用することが可能です。 Debugger mode では、バッファのうえでカーソルを自由に移動することが 可能で、移動先でリターンをおすことで、 その場いん表示された内容をコマンドとして実行できます。 さらにバッファの内容は通常の mule の操作で編集可能です。
C-c C-b その場所にブレークポイントを指定する C-c C-d その場所のブレークポイントを解除する C-c C-l 最後に GUD バッファから参照された場所のソースを表示します。 C-c C-s 1行実行する C-c C-n 1行実行する(関数の内部には入らない) C-c TAB 1命令づつ実行する C-c C-r 実行を継続する C-c C-p カーソルのある位置の変数の値を表示させる C-c C-t 1回限りのブレークポイントの設定 C-c < スタックフレームを1つあがる C-c > スタックフレームを1つさがる
なお、他の全てのバッファ(例えばソースコードを開いたバッファ) においても、 通常の prefix key である C-c の変わりに C-x C-a を使用することで、上記のコマンドが使用できます。 つまり、あるファイルで C-x C-a C-b とするとそこにブレークポイントが 設定されますし、C-x C-a C-p なら、その変数の内容が GUD バッファに 表示されます。