この文書は、Z80 を CPU に持つコンピュータ向けの C コンパイラ・アセンブラツールチェーンである Z88DK を使って MSX のゲームをつくるための環境構築メモです。
The development kit for over a hundred z80 family machines - c compiler, assembler, linker, libraries.
手順では Ubuntu 24.04 LTS を用いています。Z88DK の準備については Windows WSL2 でも同様の手順です。
筆者が Z88DK で実装した MSX ゲームです。GitHub からソースコードも見ることができます。
🔗 https://github.com/h1romas4/z88dk-msx-template
🔗 https://github.com/h1romas4/noborunoca
Z88DK の v2.4 を使うためソースコードからビルドします。
依存関係の導入(Z88DK の Github Actions build-on-ubuntu.yml を参考にしてください)
sudo apt install build-essential bison flex libxml2-dev zlib1g-dev m4 ragel re2c dos2unix texinfo texi2html gdb curl perl cpanminus ccache libboost-all-dev libmodern-perl-perl libyaml-perl liblocal-lib-perl libcapture-tiny-perl libpath-tiny-perl libtext-table-perl libdata-hexdump-perl libregexp-common-perl libclone-perl libfile-slurp-perl pkg-config libgmp3-dev
Perl の依存関係をローカルホーム(~/.perl5)に導入
cpanm --local-lib=~/perl5 App::Prove CPU::Z80::Assembler Data::Dump Data::HexDump File::Path List::Uniq Modern::Perl Object::Tiny::RW Regexp::Common Test::Harness Text::Diff Text::Table YAML::Tiny
ビルド前に Perl のライブラリーパスを設定
eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)
ビルド(submodule を使っているので --recursive を必ずつける)
git clone --recursive https://github.com/z88dk/z88dk.git
cd z88dk
git checkout v2.4
git submodule update --init --recursive
./build.sh
ビルド確認(zcc がコンパイラフロントエンドコマンドになります)
$ ls -laF bin/
合計 85628
drwxrwxr-x 2 hiromasa hiromasa 4096 12月 22 20:36 ./
drwxrwxr-x 18 hiromasa hiromasa 4096 12月 24 15:12 ../
-rwxr-xr-x 1 hiromasa hiromasa 26791712 12月 22 20:29 z80asm*
-rwxr-xr-x 1 hiromasa hiromasa 1546984 12月 22 20:27 z88dk-appmake*
-rwxr-xr-x 1 hiromasa hiromasa 15664 12月 22 20:29 z88dk-asmpp*
-rwxr-xr-x 1 hiromasa hiromasa 6793 12月 22 20:29 z88dk-asmstyle*
-rwxr-xr-x 1 hiromasa hiromasa 264960 12月 22 20:29 z88dk-basck*
-rwxr-xr-x 1 hiromasa hiromasa 206536 12月 22 20:27 z88dk-copt*
-rwxr-xr-x 1 hiromasa hiromasa 577952 12月 22 20:29 z88dk-dis*
-rwxr-xr-x 1 hiromasa hiromasa 28272 12月 22 20:29 z88dk-dzx0*
-rwxr-xr-x 1 hiromasa hiromasa 17192 12月 22 20:29 z88dk-dzx7*
-rwxr-xr-x 1 hiromasa hiromasa 35864 12月 22 20:29 z88dk-font2pv1000*
-rwxr-xr-x 1 hiromasa hiromasa 1213384 12月 22 20:29 z88dk-gdb*
-rwxr-xr-x 1 hiromasa hiromasa 47408 12月 22 20:29 z88dk-lib*
-rwxr-xr-x 1 hiromasa hiromasa 893344 12月 22 20:27 z88dk-sccz80*
-rwxr-xr-x 1 hiromasa hiromasa 1809984 12月 22 20:29 z88dk-ticks*
-rwxr-xr-x 1 hiromasa hiromasa 318472 12月 22 20:27 z88dk-ucpp*
-rwxr-xr-x 1 hiromasa hiromasa 26791712 12月 22 20:29 z88dk-z80asm*
-rwxr-xr-x 1 hiromasa hiromasa 436904 12月 22 20:29 z88dk-z80nm*
-rwxr-xr-x 1 hiromasa hiromasa 101896 12月 22 20:29 z88dk-z80svg*
-rwxr-xr-x 1 hiromasa hiromasa 459360 12月 22 20:29 z88dk-zobjcopy*
-rwxr-xr-x 1 hiromasa hiromasa 46104 12月 22 20:29 z88dk-zpragma*
-rwxrwxr-x 1 hiromasa hiromasa 25538288 12月 22 20:36 z88dk-zsdcc*
-rwxr-xr-x 1 hiromasa hiromasa 48496 12月 22 20:29 z88dk-zx0*
-rwxr-xr-x 1 hiromasa hiromasa 21456 12月 22 20:29 z88dk-zx7*
-rwxr-xr-x 1 hiromasa hiromasa 398288 12月 22 20:29 zcc*
ZCCCFG 環境変数を z88dk/lib/config に設定して、PATH を z88dk/bin に通します。 また、この後 VS Code のソース編集時に include path を通すため Z88DK_HOME (任意の名前)を設定しておきます。
.bashrc の再下部に追加
# z88dk
export Z88DK_HOME=/home/hiromasa/devel/msx/z88dk
export ZCCCFG=${Z88DK_HOME}/lib/config
export PATH=${Z88DK_HOME}/bin:${PATH}
zcc の起動確認
$ zcc +msx
zcc - Frontend for the z88dk Cross-C Compiler - v23854-4d530b6eb7-20251222
Usage: zcc +[target] {options} {files}
Options:
-v -verbose Output all commands that are run (-vn suppresses)
-h -help Display this text
-o Set the basename for linker output files
-specs Print out compiler specs
# ..snip..
Z88DK のコアやライブラリーソースなどを VS Code で開いて参照する場合は、ビルド後に多数生成される .o オブジェクトファイルで VS Code が遅くならないよう .vscode/settings.json を追加し以下の files.watcherExclude 設定をすると良いです。
.vscode/settings.json
{
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/obj/**": true,
}
}
導入したツールチェーンの動作を確認するため、筆者がつくったサンプルプログラムをセットしたテンプレートプロジェクトを git clone します。
.git/ を削除して、自分のプログラムを入れるとそのままプロジェクトディレクトリとして使えると思います。.rom を GitHub のコンテナでビルドしてリリースできます。Z88DK MSX build template with sample game
Use this template
cmake の導入
apt install cmake
テンプレートプロジェクトのビルドをしてみます。
git clone https://github.com/h1romas4/z88dk-msx-template.git
cd z88dk-msx-template
cmake -S . -B build
cmake --build build
この操作で src/msx 配下のサンプルプログラムがコンパイルされ、dist/ 配下に MSX で起動可能な .rom ファイルが生成されます。(任意の MSX エミュレータにセットすることで起動可能です)
$ ls -laF dist/
合計 152
drwxrwxr-x 2 hiromasa hiromasa 4096 12月 27 14:19 ./
drwxrwxr-x 11 hiromasa hiromasa 4096 12月 27 14:18 ../
-rw-rw-r-- 1 hiromasa hiromasa 122410 12月 27 14:19 example.map
-rw-rw-r-- 1 hiromasa hiromasa 16384 12月 27 14:19 example.rom
-rw-rw-r-- 1 hiromasa hiromasa 264 12月 27 14:19 example_BSS.bin
-rw-rw-r-- 1 hiromasa hiromasa 24 12月 27 14:19 example_DATA.bin
CMakeLists.txt の構成プロジェクトのビルドは CMakeLists.txt に従って行われます。プロジェクトに合わせて修正します。
コンパイラのパス指定(${Z88DK_HOME} 環境変数を利用している)
set(CMAKE_C_COMPILER $ENV{Z88DK_HOME}/bin/zcc)
set(CMAKE_ASM_COMPILER $ENV{Z88DK_HOME}/bin/zcc)
dist/example.rom の出力 ROM 名の設定
project(example.rom C ASM)
ビルド対象ソースファイルの追加削除(.c 及び .asm に対応)
target_sources(${PROJECT_NAME} PRIVATE
src/c/example.c
src/asm/psgdriver.asm
src/asm/define_music.asm
src/asm/define_graphic.asm
)
CMakeLists.txt を修正した後は、一度 cmake をし直します。
# build ディレクトリごと削除
rm -Rf build
cmake -S . -B build
cmake --build build
通常のソースコード変更だけの場合は cmake --build build だけで OK です。なお、アセンブラで include を使っている場合、include 先の更新までは make が追従しませんので、更新がある場合はいったん make clean してください。
その他のコンパイルオプション
The frontend of z88dk is called zcc, it is this that you should call if you want to do any compilations. To invoke the frontend use the command:
リンカー向けオプション:
target_link_options(${PROJECT_NAME} PRIVATE
+msx
-create-app
-subtype=rom
-m
-lm
-lmsxbios
)
-m が後述の example.map シンボルマップファイルを出力する指定。-subtype=rom で 0x4000 からの ROM 版をつくることを指定。0xc0000 からの RAM 版をつくる場合は -subtype=default (.cas 形式) もしくは -subtype=wav (カセットテープのピーガー形式) を指定。BLOAD "CAS:",R でロード・ランできる。cmake が生成した Makefile の zcc コマンドを確認する場合は build/compile_commands.json ファイルを確認すると良いでしょう。
また、GitHub Actions でビルドを構成しています。ここまでのコマンドの流れは .github/workflows/build-release.yml でも確認できますのでご参照ください。
テンプレートプロジェクトは C/C++ for Visual Studio Code 拡張用の .vscode/settings.json を含んでいます。Z88DK への include path の設定がされているので、拡張を有効にした後、ディレクトリを VS Code で開くことで、ソースコード編集中の定義の参照やインテリセンスによる補完ができます。
The C/C++ extension adds language support for C/C++ to Visual Studio Code, including features such as IntelliSense and debugging.

.vscode/settings.json (${env:Z88DK_HOME} 環境変数で Z88DK へのパスをたどっている)
{
"configurations": [
{
"name": "z88dk",
"includePath": [
"${workspaceFolder}/src/msx/*",
"${env:Z88DK_HOME}/include/*",
"${env:Z88DK_HOME}/include/**/*"
],
"defines": [],
"compilerPath": "${env:Z88DK_HOME}/bin/zcc",
"cStandard": "c11",
"intelliSenseMode": "gcc-x86"
}
],
"version": 4
}
また、.vscode/tasks.json で F1 キー押下後の Run Tasks メニューに、ビルド系のコマンドを追加しています。
.vscode/tasks.json
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Clean CMake directory",
"type": "shell",
"linux": {
"command": "rm -Rf ${workspaceFolder}/build",
},
},
{
"label": "Run CMake (make)",
"type": "shell",
"dependsOn": "Clean CMake directory",
"linux": {
"command": "cmake -S . -B build",
},
},
{
"label": "Clean Build (make)",
"type": "shell",
"linux": {
"command": "make --build build --target clean",
},
},
{
"label": "Run Build (make)",
"type": "shell",
"dependsOn": "Clean Build (make)",
"linux": {
"command": "cmake --build build",
},
},
]
}
v2.2 から v2.4 へアップグレードする場合本手順の旧テンプレートリポジトリ(2025-12-24以前)では Z88DK v2.2 が使われていました。 Z88DK ツールチェインを v2.4 にアップグレードした場合、そのままの旧 CMakeLists.txt であるとコンパイラ・リンカーオプションが混乱してビルドできなくなるため、次のようにして CMakeLists.txt を新しいものにしてください。
CMakeLists.txt を置換する。cmake ディレクトリを rm -Rf cmake/ のように削除。不要なマクロをリファクタしました。プロジェクト(.rom)名:
project(example.rom LANGUAGES C ASM)
ソースコード設定:
target_sources(${PROJECT_NAME} PRIVATE
src/c/example.c
src/asm/psgdriver.asm
src/asm/define_music.asm
src/asm/define_graphic.asm
)
コンパイル・リンカーオプションで変更している部分があれば旧 CMakeLists.txt から移植(旧から比べてそれぞれ分割しました)
# Basic compile options
target_compile_options(${PROJECT_NAME} PRIVATE
+msx
-O2
-vn
#$<$<COMPILE_LANGUAGE:C>:-debug>
$<$<COMPILE_LANGUAGE:ASM>:--list>
)
# Defines
target_compile_definitions(${PROJECT_NAME} PRIVATE
# https://github.com/z88dk/z88dk/wiki/Classic-allocation#automatic-heap-configuration
-DAMALLOC
)
# Linker options
target_link_options(${PROJECT_NAME} PRIVATE
+msx
-create-app
-subtype=rom
-m
-lm
-lmsxbios
)
旧から比べてビルドコマンドを短く使いやすいようにしました。次のようなコマンドで cmake - make するようにしてください。
# プロジェクトのルートにいること
$ pwd
/home/hiromasa/devel/msx/z88dk-msx-template
cmake -S . -B build # cmake
cmake --build build --target clean # make clean
cmake --build build # make
ビルドした .rom の動作確認を行うため openMSX をビルドします。(RELEASE_21_0 で確認)
the MSX emulator that aims for perfection
依存関係の導入
sudo apt-get install libgl1-mesa-dev
sudo apt-get install libsdl2-dev libpng-dev tcl-dev libglew-dev libsdl2-ttf-dev libvorbis-dev libtheora-dev libogg-dev libao-dev libfreetype6-dev
ビルド
git clone https://github.com/openMSX/openMSX.git
cd openMSX
git checkout RELEASE_21_0
make -j6 OPENMSX_TARGET_CPU=x86_64 OPENMSX_TARGET_OS=linux OPENMSX_FLAVOUR=opt
# ...snip...
Creating binary package:
Executable...
Data files...
Documentation...
C-BIOS...
Creating symlinks...
-j6 はコンパイルに使う CPU コア数。マシンに合わせて設定すると速くビルドできます。インストール
derived/x86_64-linux-opt-3rd/bindist/install/bin に生成された openmsx をパスが通っている適当な場所にコピー。
cp -p derived/x86_64-linux-opt-3rd/bindist/install/bin/openmsx ~/.local/bin
~/.openMSX にコンフィグをコピー
mkdir ~/.openMSX
cp -Rfp derived/x86_64-linux-opt-3rd/bindist/install/share/ ~/.openMSX
起動確認(テンプレートプロジェクトの example.rom による)
$ cd /home/hiromasa/devel/msx/z88dk-msx-template/dist
$ ls -laF
合計 128
drwxrwxr-x 2 hiromasa hiromasa 4096 9月 9 23:26 ./
drwxrwxr-x 10 hiromasa hiromasa 4096 9月 9 18:04 ../
-rw-rw-r-- 1 hiromasa hiromasa 94546 9月 9 17:02 example.map
-rw-rw-r-- 1 hiromasa hiromasa 16384 9月 9 17:02 example.rom
-rw-rw-r-- 1 hiromasa hiromasa 245 9月 9 17:02 example_BSS.bin
-rw-rw-r-- 1 hiromasa hiromasa 16 9月 9 17:02 example_DATA.bin
$ openmsx example.rom


(2025-12) なお、テンプレートに含まれる example.rom は openMSX の VDP アクセスタイミングの精度向上により不具合があります。具体的にはおそらく VDP を連続でリードしている部分で読みぬけが起きていてボールがどこかに飛んでいきます。気が向いた時にでも修正します。
Z88DK には z88dk-gdb コマンドが含まれており、MAME の gdbstub と通信してデバッグを行うこともできます。
CFLAGS で -m -debug コンパイルオプションを有効にしてビルドすると C のレベルでデバッグできます。(プログラムは遅くなります)$ (cd ${MAME_HOME} && ./cbios cbios example -window -resolution 800x600 -debugger gdbstub -debug)
gdbstub: listening on port 23946
$ cd dist/ # .map ファイル内に出力されたソースコードのパス(../src/msx/example.c)と z88dk-gdb を起動するカレントディレクトリを合わせます。(v2.2 からソースマップがフルパスになったのでこの操作は不要)
$ z88dk-gdb -h 127.0.0.1 -p 23946 -x example.map


また、Native Debug 拡張を使い、gdb/mi2 に VS Code からアタッチすることで VS Code デバッガから操作することもできます。
.vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to MAME gdbserver",
"type": "gdb",
"request": "attach",
"target": "127.0.0.1:23946",
"remote": true,
"cwd": "${workspaceRoot}",
"gdbpath": "${env:Z88DK_HOME}/bin/z88dk-gdb",
"debugger_args": [
"-x",
"${workspaceRoot}/dist/example.map" // or appropriate .map of your project (-m -debug needed!)
],
"autorun": [
]
}
]
}

なお、2022/7 現在、Step Over すると動作が戻ってこなくなるようです。Continue と Step into はうまく動作しますので使い分けて活用すると良いと思います。
VS Code 上でアセンブラデバッグをする場合は以下の文書を参考にしてください。
DeZog + Z88DK + MAME で MSX アセンブリーをデバッグする手順
この文書は、VS Code の Z80 デバッガーである DeZog 拡張と Z80 ツールチェイン Z88DK、及び MSX エミュレータ・gdb スタブとして MAME を使い、VS Code 上の Z80 アセンブリーをデバッグする手順です。
MSX 向けのグラフィックを描くため nMSXtiles を導入してみます。(ここでは master ブランチの e4db1b8 版で確認しています)
Editor de Baldosas (Tiles) y Sprites para MSX en modo gáfico SC2 y SC4

依存関係の導入
sudo apt install qtcreator
ソースコードの clone
git clone https://github.com/pipagerardo/nMSXtiles.git
依存関係で導入した Qt Creator を起動して ファイル/プロジェクトを開くから src/nmsxtiles.pro を指定する。
ビルドからプロジェクトのビルドを実行する。

build/ 下に nMSXtiles 実行バイナリが作成されるので、適当なパスの通ったディレクトリにコピーして起動する。
$ ls -laF build/
合計 452
drwxrwxr-x 4 hiromasa hiromasa 4096 9月 9 21:40 ./
drwxrwxr-x 9 hiromasa hiromasa 4096 9月 9 21:40 ../
drwxrwxr-x 2 hiromasa hiromasa 4096 9月 9 21:21 doc/
drwxrwxr-x 2 hiromasa hiromasa 4096 9月 9 21:52 examples/
-rwxrwxr-x 1 hiromasa hiromasa 445792 9月 9 21:40 nMSXtiles*
$ cp -p nMSXtiles ~/.local/bin
$ nMSXtiles
起動して build/examples 下にあるサンプルプロジェクトを開くと使い方が分かります。

Z88DK で +msx で MSX をターゲットに指定した場合は C の標準ライブラリーは Classic Library になります。(もうひとつは New Library)
The classic library can be used with both sccz80 and zsdcc and the final binary can be made of object files generated by either compiler (though care will need to be taken around calling conventions and floating point usage).
sprintf などが使える(便利)。src/example.c
#include <stdio.h>
#include <stdlib.h>
/**
* スコア等表示
*/
void print_state()
{
uchar score_string[VRAM_WIDTH + 1];
sprintf(score_string, "SCORE %06u HISCORE %06u %02u", game.score, game.score_hi, game.remein_clear);
vwrite(score_string, VPOS(0, 0), VRAM_WIDTH);
}
MSX の TMS9918a/TMS9928a VDP にアクセスする場合は msx/gfx.h を include します。
set_color や set_mode set_mangled_mode などで VDP の初期化ができる。vwrite や fill、vpeek vpoke などで VRAM へのアクセスができる。#include <msx/gfx.h>
/**
* グラフィックス初期化
*/
void init_graphics()
{
// スクリーンモード
set_color(15, 1, 1);
set_mangled_mode();
// スプライトモード
set_sprite_mode(sprite_default);
// キークリックスイッチ(OFF)
*(uint8_t *)MSX_CLIKSW = 0;
// 画面クリア
fill(VRAM_START, VRAM_NONE, VRAM_WIDTH * VRAM_HEIGHT);
// PCG 設定(3面に同じデーターを転送)
vwrite(chars, 0x0000, 0x800);
vwrite(chars, 0x0800, 0x800);
vwrite(chars, 0x1000, 0x800);
// 色設定(0000|0000 = 前|背景)
set_char_color('=', 0x54, place_all);
set_char_color('$', 0xa0, place_all);
set_char_color('>', 0x6d, place_all);
set_char_color('?', 0x60, place_all);
}
get_rnd seed_rnd 関数で乱数が使える。uint8_t x = get_rnd() % 31 + 1;
uint8_t y = get_rnd() % 21 + 1;
get_stick get_trigger でコントローラ、キーボードの入力ができる。// 入力取得
uint8_t stick = st_dir[get_stick(0)];
uint8_t trigger = get_trigger(0);
Z88DK のブートストラップの解説は以下にドキュメントがあります。
The crt is the startup code that runs before calling main(). It is responsible for setting the memory map, instantiating device drivers on stdin/stdout/stderr, initializing the bss and data sections and calling any initialization code prior to calling main(). On return from main() it is responsible for closing open files, resetting the stack and preparing to return to the host.
+msx subtype=rom 指定の場合は、lib/config/msx.cfg より設定され、ブートストラップは次のアセンブラになります。
lib/target/msx/classic/rom.asm
;
; Main Code Entrance Point
;
IFNDEF CRT_ORG_CODE
defc CRT_ORG_CODE = $4000
ENDIF
org CRT_ORG_CODE
; ROM header
defm "AB"
defw start
defw 0 ;CallSTMT handler
defw 0 ;Device handler
defw 0 ;basic
defs 6
start:
di
INCLUDE "crt/classic/crt_init_sp.asm"
ei
;...snip...
0x4000 からの 16KB ROM。ROM ヘッダーがここでつけられる。0xc000 から。.asm をエントリーポイントとしてプログラムを構成する場合は _main を PUBLIC にする。
; code_user is for read-only code
; called by the crt as entry to program
SECTION code_user
; _main という名前でラベルを PUBLIC にする
PUBLIC _main
; メイン
_main:
; ここからプログラム
LD BC,VALUE1
LD A,(BC)
LD IX,WORK1
LD (IX),A
RET
; rodata_user if for constant data
; kept in rom if program is in rom
SECTION rodata_user
; ROM に書き込むデーター
VALUE1: DB 10
; bss_user is for zeroed ram variables
; zeroed by crt when program started
SECTION bss_user
; RAM に配置するワークエリア(CRT が 0 に初期化してくれる)
WORK1: defs 1
; data_user is for initially non-zero ram variables
; initialized in ram by crt if the program is in rom
SECTION data_user
; RAM に配置するデーター(CRT が指定値で初期化してくれるらしい)
WORK2: DB 10
.asm へのバイナリデータリンク.asm ファイルにデータセクション rodata_user(ROM に配置される)をつくり、_ アンダーバー付きラベルをパブリック指定することで .c から extern で、アンダーバーなしのラベル名で参照できる。
src/chars.asm
; rodata_user
; https://github.com/z88dk/z88dk/blob/master/doc/overview.md#a-quick-note-for-asm-code
; rodata_user if for constant data
; kept in rom if program is in rom
SECTION rodata_user
PUBLIC _chars, _colors
_chars:
DB $fe,$c2,$8a,$92,$aa,$86,$fe,$00,$fe,$c2,$8a,$92,$aa,$86,$fe,$00
DB $fe,$c2,$8a,$92,$aa,$86,$fe,$00,$fe,$c2,$8a,$92,$aa,$86,$fe,$00
src/example.c
// chars.asm::_chars ラベルのアドレス参照(VRAM PCG 転送用)
extern unsigned char chars[];
ABI を合わせることで .asm と .c 間で関数呼び出しや call が可能。(本サンプルではアセンブラでかかれたサウンドドライバーの呼び出し部分で使用)
The z88dk parameter passing mechanism normally relies on the stack: local variables declared in a C program are allocated on the stack as a function is entered and are popped off the stack as functions are exited. z88dk supports multiple calling conventions so care should be taken when writing assembler that interfaces with C.
.asm でかかれたプログラム領域は SECTION code_user に配置する。.asm の規定セクション名については、以下のドキュメントに記載があります。
Z88DK uses z80asm as a section-aware linking assembler. What this means is placement of code and data in memory is controlled by section assignment rather than ORG. This is an essential feature of a modern development environment.
本項「呼び出し規則と関数デコレータ」は Z88DK Wiki の DeepL 日本語訳です。
Z88DK には、関数を呼び出すためのいくつかの異なる規約があります。これらを理解することで、プログラムとアセンブラの機能をリンクさせたり、デバッグの際に役立つでしょう。
規約や修飾子は、例えば、関数のプロトタイプにサフィックスとして追加することで、コンパイラに示されます。
int function(long val) __z88dk_callee;
Z88DK は以下の呼び出し規則をサポートしています。
| 修飾子 | Stack cleanup | 説明 |
|---|---|---|
__smallc |
呼出し元 | sccz80 が使用するデフォルトの呼び出し規則です。パラメータは、左から右に向かってスタックに押し込まれます。sccz80 の場合、char は word としてスタックにプッシュされます。注意 zsdcc のバグにより、__smallc 関数にアクセスすると、chars は 1 バイトとしてプッシュされます。戻り値は hl, または dehl です。 |
__stdc |
呼出し元 | パラメータは逆順(右から左)にプッシュされます。char は word としてスタックにプッシュされます。戻り値は hl または dehl です。 |
__z88dk_sdccdecl |
呼出し元 | zsdcc のデフォルトの規約です。パラメータは、右から左に向かってスタックにプッシュされます。char は、1 バイトとしてスタックにプッシュされます。戻り値は、l、hl、または dehl に保持されます。 |
| 修飾子 | 説明 |
|---|---|
__z88dk_callee |
呼び出された関数(callee)は、スタックをクリーンアップする責任があります。 |
__z88dk_fastcall |
レジスターには最大で1つのパラメータが渡されます。smallc では、一番右のパラメータになります。また、__stdc と __z88dk_sdccdecl では、唯一のパラメータとなります。使用されるレジスタは、パラメータのビット幅に応じて、常に DEHL のサブセットとなります。 sccz80 の浮動小数点/倍精度は 48 ビットなので、少し扱いが異なります。 これらは「一次浮動小数点アキュムレータ」を介して渡されます。 従来の C ライブラリでは、これは "fa"と名付けられた6バイトのスタティックメモリです。 new c library では、これはexxセットのレジスタ BCDEHL です。 sdcc の 64 ビット long long 型は、fastcall リンケージを使用して渡すことができません。 |
__z88dk_saveframe |
sccz80 で生成されたコードにのみ有効です。sdccフレームポインタ(ix)は、この関数への入力時に保存されます。これはこの関数が sdcc コンパイルコードから呼び出されることが予想され、長さまたは浮動小数点を使用する場合に必要です。 |
__critical |
割り込みの状態は、関数への入力時に保存され、終了時に復元されます。 |
__interrupt(n) |
入力時にプライマリ・レジスタとインデックス・レジスタを保存し、終了時にリストアします。必要に応じてreti/retnして返します。z88dk で採用されている動作 はsdccと同じで「かなり紛らわしい」です。 |
__naked |
アセンブラ関数に使用され、関数のプロローグとエピローグが生成されないようにします。 |
__interrupt __critical インタラクション:void func() __critical __interrupt - レジスタをセーブし、retn で返します(NMIの場合など)void func() __interrupt - eiし、レジスターを保存し、reti で返します (im2 の場合)void func() __critical __interrupt(0) - レジスターを保存し、ei; reti で返します (im1 の場合)| 修飾子 | 使用方法 |
|---|---|
__banked |
ターゲット固有の banked_call 関数を使用して、関数を呼び出すことができます。呼び出しの後には、その関数の32ビットのアドレスが続きます。最初の2バイトがアドレスで、後の2バイトがバンクです。この呼び出し規則の関数例は、クラシックな +zx、+msx、+gbポートに見られます。 |
__z88dk_shortcall(RR, VV) |
rst RR トランポリンで関数を呼び出すことができます。VV < 256 の場合、生成されるコードは rst RR; defb VV であり、そうでない場合は rst RR; defw VV となります。これは、非ページ化されたメモリバンクにある関数にアクセスするために使用できます。 |
__z88dk_shortcall_hl(RR, VV) * |
生成されたトランポリンが次のようになることを除けば、上記と同じです。: ld hl, VV; rst RR |
__z88dk_hl_call(VV1, VV2) * |
spectranet スタイルトランポリンです。: ld hl, VV1; call VV2 |
__z88dk_params_offset(VV) |
トランポリンを介して呼び出された場合、関数のパラメータがsp+2を起点に配置されていないことがあります。このアノテーションでは、パラメータに到達するために必要な追加のオフセットを定義します。 |
*: __z88dk_fastcall と組み合わせた場合、fastcall に必要なコンテンツや HL は BC にコピーオーバーされ、後に置き換えられます。トランポリンが受信側で処理されたときにHLの内容を復元するのは、ユーザーの責任です。
__z88dk_shortcall() では、直接呼び出しのみがrstトランポリンを使用し、関数ポインタを介した呼び出しは通常通り呼び出します。したがって、ライブラリを配布したり、インターフェイスを提供したりする際には、rst トランポリンを介して呼び出すことができるマッチした関数スタブを提供する必要があります。
| 修飾子 | 利用方法 |
|---|---|
__preserves_regs(r1,r2...) |
指定されたレジスタが関数によって保持されることを sdcc に示します。この情報は、sdcc が生成するコードの品質を向上させるために使用されます。 |
慣習的に、sccz80が使用するライブラリ関数は、型の後に__LIB__と記されています。
void __LIB__ mylibrary_function(int param);
つまり、sccz80 は mylibrary_function を、sdcc は _mylibrary_function を呼び出すことになります。これらの異なるエントリーポイントは、呼び出し規則を調整するのに役立ちます。(vaargs関数では必須)
戻り値は、戻り値のビット幅に応じて、DEHLのサブセットに保持されます。 sccz80 の 48 ビット float/double は、クラシックライブラリではアドレス "fa"の 6 バイトのスタティックメモリである "primary floating point accumulator" に値を返し、new c library では exx セットのレジスタBCDEHL に値を返すなど、扱いが異なります。 なお、DEHL を介して1つのパラメータが関数に渡される fastcall リンケージと同じルールが適用されます。
64-bit long long 型の戻り値は特別に処理されます。 コンパイラは、関数呼び出しの最初のパラメータとして、戻り値のメモリへのポインタを渡します。 このパラメータは、関数のプロトタイプには記載されていません。 呼び出された関数は、そのポインタを使って、返された64ビットの値を格納しなければなりません。
[翻訳ここまで]
C 言語ソースコード中に #asm #endasm もしくは、__asm __endasm; を挟むことでインラインアセンブラを使うことができます。スタックは __smallc にて、char は word のリトルエンディアンで積まれるので、C言語関数の引数は次のように取得できます。
void write_psg(uint8_t reg, uint8_t dat)
{
#asm
LD HL ,2 ;
ADD HL, SP ; リターンアドレスをスキップ
LD E, (HL) ; WRTPSG(E)
INC HL ; WORD の 2byte 目をスキップ
INC HL ;
LD A,(HL) ; WRTPSG(A)
CALL $0093 ; call WRTPSG(A, E)
#endasm
}
/**
* 特殊効果音
*/
void sound_jump()
{
// ..snip..
// ボリューム設定
write_psg(0xa, 0x0);
// ..snip..
}