はじめに
X68000 のクロス開発環境 elf2x68k では、Linux (WSL) や MinGW、macOS などの環境で以下のような X68000 のクロス開発を行うことができます。
- C/C++ プログラムのコンパイル
- X-BASIC プログラムの C への変換とコンパイル
- X68000 で実行するプログラムの GDB を用いたリモートデバッグ
今回、初めて Mac を導入して X68000 のクロス開発環境を macOS 上で構築してみたので、その手順をまとめてみました。
動作は M3 MacBook Air の macOS Sonoma (14.5)上で確認しています。
事前の準備
ターミナルへのフルディスクアクセス設定
macOS のターミナルは Finder の アプリケーション → ユーティリティー から開けます。zsh が動いて UNIX 系の CUI 環境が最初から使えるようになっていますが、初期状態では文書 (Documents) フォルダなどのいくつかのフォルダにアクセス制限がかかっているため、まずこれを解除します。
「設定」から「プライバシーとセキュリティ」→「フルディスクアクセス」を選択し、「ターミナル」アプリに対してフルディスクアクセスの権限を与えます。これで、ディレクトリ移動の際に不意にアクセス確認を求められたりすることがなくなります。
Xcode Command Line Tools のインストール
CUI 環境上で C コンパイラ等の開発環境を使用するためには、Xcode Command Line Tools のインストールが必要です。以下のコマンドを実行します。
$ xcode-select --install
上記手順が通常の方法ですが、make
や clang
など Command Line Tools に含まれるコマンドを未インストールの状態で実行すると「(コマンドラインデベロッパ)ツールを今すぐインストールしますか?」と聞いてくるので、ここからインストールすることもできます。
Homebrew のインストール
macOS にはパッケージ管理ツールがいくつかありますが、その中で Homebrew というツールがよく使われているようです。X68k クロス開発環境も Homebrew からインストールできるようにしてありますので、まずはこれをインストールします。
トップページのインストール手順に従ってください。これによって、brew
コマンドによるパッケージ導入ができるようになります。
XEiJ エミュレータの導入
OpenJDK のインストール
macOS 上で動作する X68000 エミュレータとして、XEiJ (Makoto Kamadaさん作) を使用します。
XEiJ は Java で開発されているので、Java 実行環境として OpenJDK をインストールします。
OpenJDK は Homebrew でもパッケージとして提供されているため、以下のコマンドでインストールできます。
$ brew install openjdk
インストール後、コンソールに環境設定の方法が表示されているので、これに従って設定を行ってください。
正しく設定されていれば、java
コマンドで以下のようにバージョンが確認できるはずです。
$ java -version
openjdk version "22.0.1" 2024-04-16
OpenJDK Runtime Environment Homebrew (build 22.0.1)
OpenJDK 64-Bit Server VM Homebrew (build 22.0.1, mixed mode, sharing)
$
XEiJ のインストール
XEiJ は、配布サイト https://stdkmd.net/xeij/ の ダウンロード からダウンロードできます。
2024 年 7 月現在、後述するリモートデバッグに対応するための変更がテスト版として 0.24.07.10 TEST に入っています。
リモートデバッグを使用したい場合は、上記リンクの代わりにテスト版の ダウンロード から最新版をダウンロードしてください。
ダウンロードした ZIP ファイルを適当なディレクトリに展開します。
ディレクトリ構成は特に指定されていないのですが、私の場合はホームディレクトリ直下に X68000 関連ファイルをまとめた x68000
というディレクトリを作って、その下に XEiJ を展開しています。
XEiJ はリリースバージョン番号が付いたディレクトリに格納されているので、
$ ln -s XEiJ_<バージョン番号> XEiJ
のようにして XEiJ
から最新バージョンへのシンボリックリンクを張っておくことで、/Users/<ユーザ名>/x68000/XEiJ
から常に最新版 XEiJ にアクセスできるので便利です。
XEiJ の起動
Finder から XEiJ フォルダを開いて (コマンドラインから open
コマンドでも可)、XEiJ.jar
をダブルクリックすると XEiJ が起動します。
XEiJ.jar
についても、コマンドラインから
$ ln -s <XEiJのフルパス>/XEiJ.jar XEiJ.jar
とやってシンボリックリンクを作っておくことで、このリンクがどの場所にあってもダブルクリックで XEiJ が起動できるようになります。
XEiJ を起動すると、最初は起動ドライブが存在しないため、ディスクの挿入を求めてきます。
XEiJ には Human68k システムディスクのフロッピーディスクイメージファイル HUMAN302.XDF
が含まれているので、これを使用することで Human68k の起動が確認できます。
XEiJ のメニュー、「ファイル(F)」→「FD」の「フロッピーディスク」で、ドライブ 0 に XEiJ フォルダ内の HUMAN302.XDF
を指定します。
すると、以下のように Human68k の起動が確認できます。
クロス開発環境の導入
elf2x68k のインストール
続いて、X68000 クロス開発環境 elf2x68k をインストールします。Linux 版などはビルド済みバイナリとして配布していますが、macOS ではネットからダウンロードした野良バイナリの実行に制約があるため、Homebrew からインストールできるソースコードパッケージとして提供しています。
以下のコマンドを実行することでインストールされます。
$ brew install yunkya2/tap/elf2x68k
ツールチェイン一式をソースコードからビルドするため、実行終了までかなり時間がかかります(M3 MacBook Air で 30 分程度)。インストール完了まで気長に待ってください。
Homebrew バイナリに実行パスが通っていれば、以下のコマンドでインストールされたことが確認できます。
$ m68k-xelf-gcc --version
m68k-xelf-gcc (GCC) 13.3.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
XEiJ ホストファイルシステム (HFS) の設定
クロス開発環境では、
- ソースコードの編集、コンパイルは macOS 上で
- 出来上がったバイナリの実行は XEiJ エミュレータの Human68k で
実行することになるので、macOS 上で作成したバイナリファイルをエミュレータ側からアクセスできると便利です。そこで、XEiJ のホストファイルシステム (HFS) 機能を使用します。HFS は、エミュレータを実行しているホスト側 (この場合は macOS) にあるファイルを、エミュレータ側から仮想ドライブとしてアクセスするための機能です。
まず、macOS 上の特定のフォルダを X68000 の起動ドライブとして、そこから起動できるようにします。起動ドライブに使用するファイルとして、無償公開されている Human68k システムディスクを利用します。
上記リンク先から HUMAN302.LZH をダウンロードします。
XEiJ のインストール時に作成したフォルダ /Users/<ユーザ名>/x68000
に起動ドライブ用のディレクトリ HFS
を作成し、ダウンロードしたファイルを展開します。また、通常使用するホームディレクトリ HOME
も合わせて作成しておきます。
ファイルは LZH フォーマットで圧縮されていますが、elf2x68k には LZH ファイルの展開ツール unlha.py が含まれているので、それを使用して unlha.py x <LZHファイル名>
で展開できます。
$ cd ~/x68000
$ mkdir HFS
$ mkdir HOME
$ cd HFS
$ unlha.py x <ダウンロードしたHUMAN302.LZHの場所>
ignore extended header 0x41
HUMAN.SYS
ignore extended header 0x41
CONFIG.SYS
:
ignore extended header 0x41
ETC/INSTALL.BAT
ignore extended header 0x41
許諾条件.txt
$ ls
ASK BIN HIS SYS
AUTOEXEC.BAT COMMAND.X HUMAN.SYS USKCG.SYS
BASIC2 CONFIG.SYS KEY.SYS 許諾条件.txt
BEEP.SYS ETC STARTUP.ENV
$
ファイルに展開ツールが未対応のファイル属性が含まれているため "ignore extended header" というメッセージが出ますが、実行には支障ありません。
続いて、XEiJ を起動して 「ファイル(F)」→「HFS」 を選択し、ホストファイルシステム 0 に作成した HFS
フォルダを、ファイルシステム 1 に HOME
フォルダを設定し、
「設定(C)」→「起動デバイス」→「HFS」→「HFS 0」と設定することで、
HFS フォルダを起動ドライブとして Human68k が起動します。
起動した A: ドライブが macOS 側の x68000/HFS
フォルダ、B: ドライブが x68000/HOME
フォルダとなります。macOS, Human68k それぞれでファイルを作成してみると、お互い同じフォルダを共有していることが分かると思います。
A>B:
B>mkdir src
B>
$ cd ~/x68000/HOME
$ ls
src
$
サンプルコードのコンパイルと実行
以上で、macOS でコンパイルした実行ファイルを XEiJ エミュレータ上で実行するための準備ができました。
テストとして、C 言語のソースコードをコンパイルしてみます。
macOS 上のエディタで ~/x68000/HOME/src/sample.c
として以下のファイルを作成します。
#include <stdio.h>
int main()
{
printf("Hello, world.\n");
return 0;
}
macOS のターミナルからこのプログラムをコンパイルします。
$ cd ~/x68000/HOME/src
$ m68k-xelf-gcc -o sample.x sample.c
$ ls
sample.c sample.x sample.x.elf
$
コンパイル結果として、sample.x.elf
と sample.x
の 2 つのファイルが作成されます。
-
sample.x.elf
は gcc が直接生成する ELF 形式実行ファイルで、elf2x68k に含まれるコマンド類は基本的にはこのファイルを使用します -
sample.x
は ELF 形式から変換してできた X 形式実行ファイルで、こちらが Human68k で実行できるものです
Human68k 側で同じディレクトリに移動して、ファイルを実行してみます。
この通り、macOS でコンパイルしたソースコードが X68000 上で実行できました。
dir の表示が少しおかしいのは、作成された ELF ファイル sample.x.elf
がファイル名にピリオドを 2 つ含んでいて、標準の Human68k ではそういったファイル名をサポートしていないためです。
TwentyOne というツールを導入することで正常に表示されるようになります。
elf2x68k に含まれるコマンドは、頭に m68k-xelf-
が付く以外は通常の gcc や binutils ツールチェインとほぼ同じです。よく使われるコマンドを以下に示します。
コマンド | 意味 |
---|---|
m68k-xelf-gcc -o <出力ファイル>.x <ソースコード>.c |
単一のソースコードをコンパイルして実行ファイルを生成 |
m68k-xelf-gcc -c <ソースコード>.c |
ソースコードをコンパイルしてオブジェクトファイルを生成 |
m68k-xelf-gcc -o <出力ファイル>.x <オブジェクトファイル>.o … |
複数のオブジェクトファイルをリンクして実行ファイルを生成 |
m68k-xelf-objdump -S <出力ファイル>.x.elf |
ELF ファイルの逆アセンブルリストを表示 |
m68k-xelf-nm -S <出力ファイル>.x.elf |
ELF ファイルで定義されているシンボル一覧を表示 |
m68k-xelf-strings <出力ファイル>.x.elf |
ELF ファイル内の表示可能な文字列データを表示 |
m68k-xelf-readelf -a <出力ファイル>.x.elf |
ELF ファイル情報を表示 |
elf2x68k では C++ を使用することもできます。
#include <iostream>
int main() {
std::cout << "Hello, C++ world." << std::endl;
}
このソースコードを macOS 上でコンパイルし、Human68k 上で実行します。
$ m68k-xelf-g++ -o sample2.x sample2.cc
$
X-BASIC プログラムのコンパイルと実行
elf2x68k では、X-BASIC のプログラムを C 言語に変換、コンパイルすることも可能です。
(オリジナルの XC に付属していた X-BASIC to C コンバータ (BAStoC) と同等の機能を持った Python スクリプト が同梱されています)
Human68k から X-BASIC を起動して、以下のプログラムを入力します。
B>basic
(X-BASICが起動するので以下を入力)
10 screen 2,0,1,1
20 for i=0 to 511
30 box(i,i,i+200,i+100,i mod 16)
40 next
50 print inkey$
60 wipe()
save "sample3.bas"
Ok
run
X-BASIC 上での実行が確認できたら、system
命令で Human68k に戻ります。
macOS から m68k-xelf-bas
コマンドで X-BASIC から C への変換、変換後のコンパイルまでを行います。
$ m68k-xelf-bas sample3.bas
$
sample3.x
という名前で実行ファイルができるので、Human68k から実行することができます。
B>sample3
B>
その他のサンプルコード
elf2x68k-sample リポジトリにも elf2x68k でコンパイルできるサンプルコードが入っています。macOS 側でリポジトリを clone して make を実行することで、Human68k から実行できるファイルを生成することができます。
$ git clone https://github.com/yunkya2/elf2x68k-sample.git
Cloning into 'elf2x68k-sample'...
remote: Enumerating objects: 68, done.
remote: Counting objects: 100% (68/68), done.
remote: Compressing objects: 100% (46/46), done.
remote: Total 68 (delta 18), reused 66 (delta 16), pack-reused 0
Receiving objects: 100% (68/68), 16.49 KiB | 5.50 MiB/s, done.
Resolving deltas: 100% (18/18), done.
$ cd elf2x68k-sample/hello
$ ls
Makefile hello.c
$ make
m68k-xelf-gcc -m68000 -O2 -g -c hello.c
m68k-xelf-gcc -o hello.x hello.o
$ ls
Makefile hello.c hello.o hello.x hello.x.elf
$
B>cd \src\elf2x68k-sample\hello
B>hello
リモートデバッガの導入と実行
リモートデバッグの概要
elf2x68k で開発したプログラムは、gdbserver-x68k を用いてリモートデバッグを行うことができます。リモートデバッグは以下のように行います。
- Human68k でデバッグ対象プログラムを gdbserver 上から実行
- macOS では 68000 CPU 対応の GNU デバッガ (GDB) を使用して、ELF ファイルのデバッグ情報とソースコードを用いてデバッグを行う
- GDB は macOS - Human68k 間のシリアル接続にリモート制御コマンドを送って gdbserver を制御する
このリモートデバッグ環境の構築を行います。
ツール類のインストール
まず最初に、リモートデバッグに必要なツール類のインストールを行います。
macOS 上では Homebrew で以下のツールをインストールします。
$ brew install socat
$ brew install yunkya2/tap/m68k-gdb
socat
は macOS - Human68k 間の通信路を tty デバイスを用いて作るために使います。
m68k-gdb
は 68000 CPU 対応のクロス GNU デバッガです。こちらはインストール時にソースコードからビルドするため、インストールに数分かかります。
Human68k 側には gdbserver-x68k をインストールします。リリースページ から最新版の ZIP アーカイブをダウンロードし、展開して得られる gdbserver.x
をパスの通った適当なディレクトリに置きます。
これまでの手順で ~/x68000/HFS
に起動ドライブが作られているので、Finder などから ZIP アーカイブの中のファイルをここにコピーすることで Human68k 側から実行できるようになります。
デバッグ前の事前準備
次に、リモートデバッグのための準備を行います。まずは以下のコマンドを実行します。
$ m68k-xelf-gdb-init
このコマンドは elf2x68k に含まれているシェルスクリプトで、/tmp ディレクトリ内に macOS - Human68k 間の通信路となるデバイスを作成します (上の図の socat の部分)。
続いて、XEiJ エミュレータを起動して、tty デバイス接続のための設定を行います。
メニューの 「設定(C)」→「RS-232Cとターミナル」を選択すると別ウィンドウが開き、エミュレートされる X68000 からの RS-232C (AUX) ポートに対する設定を行うとができます。
「接続」の一番下、「追加ポート」の欄に /tmp/ttyv0
と入力して「更新」を押します。すると User- Specified Port が更新されるので、ttys???(User-Specified Port) ⇔ AUX
のチェックボックスをチェックします。
この操作は m68k-xelf-gdb-init
で通信路が更新されるたびに行う必要があります(初期化のたびに ttys??? のデバイス名が変わるため)。
既に設定が終わっている場合も、ttys???(User-Specified Port) ⇔ AUX
の設定を一旦外して、「更新」を押した後に再度チェックし直す必要があります。
デバッガの実行
ここまで準備ができたら、いよいよデバッガの実行です。先ほどコンパイルしたサンプルコード elf2x68k-sample/hello
をデバッガ上で実行してみましょう。
プログラムをデバッグするには、コンパイル時のコマンドラインに -g
オプションを追加して ELF ファイルにデバッグ情報を出力しておく必要があります。
elf2x68k-sample のサンプルコードでは最初から -g
付きでコンパイルしています。
Human68k 側でデバッグ対象のプログラムを gdbserver.x
上から以下のように実行します。
プログラムをロードしてデバッガの接続待ち状態に入ります。
B>gdbserver hello.x
Target addr:0xd2740 usp:0xba0ba ssp:0xb90ba
Target hello.x waiting for connection...
その後、macOS 側でデバッグ対象の ELF ファイルを指定して m68k-xelf-gdb
を実行します。
gdb の起動と同時に Human68k 側の gdbserver.x の接続待ち状態も解除され、デバッガからのコマンド入力待ち状態になります。
$ m68k-xelf-gdb hello.x.elf
GNU gdb (GDB) 14.2
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=aarch64-apple-darwin23.5.0 --target=m68k-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello.x.elf...
Remote debugging using /tmp/ttyv1
0x000d2740 in _start ()
(gdb)
この時点で、Human68k 側はデバッグ対象プログラムの実行開始アドレスで止まっています。C 言語の main()
関数の先頭まで実行を進めるために、main
にブレークポイントを仕掛けて以下のように実行を開始します。
(gdb) b main
Breakpoint 1 at 0xd2928: file hello.c, line 15.
(gdb) c
Continuing.
Breakpoint 1, main () at hello.c:15
15 {
(gdb)
以降は、通常の gdb と同様にソースコードを参照してブレークポイントを仕掛けたり、変数を参照したりしてのデバッグが可能です。
ターミナル上でソースコードを見やすく表示するために、layout src
コマンドを実行してみます。
n
(next) コマンドで 1 行ずつ実行していくと、プログラムの実行に伴って XEiJ の画面表示も変わっていくのが確認できます。
また、p
(print) コマンドで変数の内容を表示することができます。
このように、macOS 上から X68000 のプログラムのデバッグを行うことができます。
q
コマンドで m68k-xelf-gdb を終了すると、gdbserver も実行を終了します。
デバッグ時によく使われる gdb コマンドを以下に示します。
gdb コマンド | 意味 |
---|---|
q | gdb を終了する |
c | プログラムの実行を再開する(次にブレークポイントに達するまで実行) |
n (ni) | ソースコード上の 1 行のみ実行 (ステップオーバー) ni は CPU 命令の 1 命令分のみ実行 |
s (si) | ソースコード上の 1 行のみ実行 (ステップイン) si は CPU 命令の 1 命令分のみ実行 |
p <変数名> | 実行中のプログラムの変数の値を表示する |
b [ファイル名:]<行番号> | プログラム上の指定した箇所にブレークポイントを設定する |
info breakpoints | 現在設定されているブレークポイントの一覧を表示する |
delete <ブレークポイント番号> | 指定の番号のブレークポイントを削除する |
delete | 全てのブレークポイントを削除する |
list | ソースコードの内容を表示する |
x/<長さ><フォーマット> [<アドレス>] | 指定したアドレス(省略した場合は現在の PC 位置)から長さで指定したメモリの内容をフォーマットに従って表示する。フォーマットは x:16進数 d:10進数 i:命令コード など |
layout src | デバッガ実行中のターミナル表示を上下 2 分割して上にソースコードを表示する (CTRL+X a で 1 画面表示に戻る) |
layout asm | デバッガ実行中のターミナル表示を上下 2 分割して上に逆アセンブルを表示する |
Visual Studio Code を用いたデバッグ
Visual Studio Code (以下 VSCode) のデバッグ設定ファイル launch.json を適切に設定することで、macOS の VSCode から X68000 のプログラムをデバッグすることも可能です。
VSCode で先ほどデバッガを使用した elf2x68k-sample/hello
を開いて、hello.c
を開いたところで 「実行とデバッグ」→「launch.json ファイルを作成します」をクリックし、「デバッガの選択」で「C++ (GDB/LLDB)」を選択すると .vscode/launch.json
ファイルの雛形が用意されるので、以下のように変更します。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "X68000 Remote debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/hello.x.elf",
"stopAtEntry": true,
"cwd": "${workspaceRoot}",
"MIMode": "gdb",
"miDebuggerPath": "m68k-xelf-gdb",
"miDebuggerServerAddress": "/tmp/ttyv1"
}
]
}
コマンドラインでのデバッグ時と同様に、Human68k 側で gdbserver
からデバッグ対象の hello.x
を起動して接続待ちに入ります。
B>gdbserver hello.x
Target addr:0xd2740 usp:0xba0ba ssp:0xb90ba
Target hello.x waiting for connection...
VSCode の「実行とデバッグ」から「X68000 Remote debug」を選択するとデバッガが起動し、main()
関数の先頭で実行を停止します。
ここからは CUI と同様に、ステップ実行したりブレークポイントを設定したり変数の値を参照したりしてのデバッグが可能になります。
画面に表示されているデバッガツールバーで、左から
- 実行再開 (
c
コマンド) - ステップオーバー (
n
コマンド) - ステップイン (
s
コマンド) - ステップアウト (
fin
コマンド) - デバッグセッションの再起動 (Human68k側で
gdbserver
の再実行が必要です) - デバッグセッションの終了
これらのボタンでデバッグセッションを制御することができます。
終わりに
X68000 クロス開発環境の構築を XEiJ エミュレータの導入から順を追って説明してみました。特にリモートデバッグ周りは環境立ち上げが少々複雑なので、この説明が環境構築の助けになれば幸いです。
最後に、X68000 でのプログラミングに役立つ資料のリンクを紹介しておきます。
- ぷにぐらま~ずまにゅある (立花@桑島技研 さん)
- https://github.com/kg68k/puni
- X68000 の IOCS/DOS コールや内部ワークエリア、データ構造、ハードウェアレジスタなど、プログラミングに関係する資料がほとんどまとまっています
- X-BASIC リファレンス (ZooMark さん)
- http://ww3.enjoy.ne.jp/~zoomark/ip/xb/xb_frm.html
- X-BASIC の命令や関数についてまとめられています
- X-BASIC ver2.0 リファレンスマニュアル【基本編】 (JUNK-Pro68k(杉浦 善夫) さん)
- https://junk-pro68k.booth.pm/items/5940250
- PDF ファイルにまとめられた X-BASIC のリファレンスマニュアルです
- 豊富なサンプルコードで分かりやすく解説されています
この文書の執筆に際して、以下の方々の資料やプログラム、投稿を参考にさせていただきました。感謝します。
-
macOSユーザ向けX680x0エミュレータXEiJ活用ガイド(導入編) (tantanGH さん)
- macOS での XEiJ エミュレータセットアップ方法について参考にさせていただきました
- HDD イメージからの起動やドライブレター変更、英語キーボード対応など、XEiJ のさらなる活用の参考になります
- elf2x68k の macOS でのビルドについては、tantanGH さん、ザバイオーネ さんの X(Twitter) での投稿を参考にさせていただきました
- macOS でのリモートデバッグについては、くにちこ さんの X(Twitter) での投稿を参考にさせていただきました
- XEiJ 作者の Makoto Kamada さんには macOS 上での X68000 エミュレータ利用の道を開いていただいただけでなく、シリアルポートの追加ポート対応でリモートデバッグの利用も可能にしていただきました