AILight / AILZ80ASM

Z80アセンブラ
MIT License
49 stars 2 forks source link
z80 z80-assembler

Z80 Assembler 'AILZ80ASM'

Build Status

AILZ80ASMは、C#で書かれた.NET 8の環境で動作するZ80アセンブラです。

読み方
免責事項
連絡方法

入手方法

※ 実行形式は、「自己完結型の実行可能ファイル」になっています。.NETの環境を用意する必要はありません。

サポートツール

パフォーマンス

使い方

AILZ80ASM [<オプション>] <オプション指定文字列:ファイル名等> [ <オプション指定文字列:ファイル名等>]

> AILZ80ASM sample.z80

コンソールアプリですので、コンソールより起動してください。

入力ファイル形式

コマンドラインオプション

コマンドライン 説明
-i, --input アセンブリ対象のファイルをスペース区切りで指定します。 (オプション名の省略が可能)
-ie, --input-encode 入力ファイルのエンコードを選択します。 [auto, utf-8, shift_jis] デフォルト値:auto
-o, --output 出力ファイルを指定します。
-om, --output-mode 出力ファイルのモードを選択します。 [bin, hex, t88, cmt, sym, equ, lst, err, tag] デフォルト値:bin
-oe, --output-encode 出力ファイルのエンコードを選択します。 [auto, utf-8, shift_jis] デフォルト値:auto
-lm, --list-mode リストの出力形式を選択します。 [simple, middle, full] デフォルト値:full
-lob, --list-omit-binary リストの出力でバイナリーインクルードを省略出力をします。
-ep, --entry-point
エントリーポイントを指定します。
-ts, --tab-size TABのサイズを指定します。 デフォルト値:4
-dw, --disable-warning Warning、Informationをオフにするコードをスペース区切りで指定します。
-ul, --unused-label 未使用ラベルを確認します。
-cd, --change-dir アセンブル実行時のカレントディレクトリを変更します。終了時に元に戻ります。
-gap, --gap-default アセンブラのギャップのデフォルト値を指定します。 デフォルト値:$FF
-df, --diff-file アセンブル出力結果のDIFFを取ります。アセンブル結果は出力されません。
-dl, --define-label ラベルをスペース区切りで指定します。値を設定するときは=で代入します。
-nsa, --no-super-asm スーパーアセンブルモードを無効にします。
-sa, --start-address
スタートアドレス(出力)を指定します。ORGで指定したアドレスまで -gap で埋めます
-f, --force 出力ファイルを上書きします。
-v, --version バージョンを表示します。
-?, -h, --help ヘルプを表示します。各オプションの詳細ヘルプを表示します。例: -h --input-mode
-??, --readme Readme.mdを表示します。

コマンドライン例

■ sample.z80をアセンブル、出力はBIN形式
> AILZ80ASM sample.z80

■ sample.z80をアセンブル、出力はBIN形式、上書き確認プロンプトを表示しないで上書きをする
> AILZ80ASM sample.z80 -f

■ sample.z80をアセンブル、出力はBIN形式、ログファイルを出力
> AILZ80ASM sample.z80 -bin -err

■ sample.z80をアセンブル、出力はBIN形式、LST形式、SYM形式、ログファイルを出力
> AILZ80ASM sample.z80 -bin -lst -sym -err

■ sample.z80をアセンブル、出力はCMT形式
> AILZ80ASM sample.z80 -cmt
> AILZ80ASM sample.z80 -om cmt

■ sample.z80をアセンブル、出力はBIN形式、CMT形式、リストの出力(形式:シンプル、タブサイズ8)
> AILZ80ASM sample.z80 -bin -cmt -lst -lm simple -ts 8

■ sample.z80をアセンブル、出力はBIN形式、ファイル名は、output.bin
> AILZ80ASM sample.z80 -bin output.bin
> AILZ80ASM -i sample.z80 -o output.bin -om bin

■ sample.z80をアセンブル、出力はBIN形式、指定(W0001,W9001,W9002)のワーニング表示をOFFにする
> AILZ80ASM sample.z80 -bin output.bin -dw W0001 W9001 W9002

■ sample.z80をアセンブル、ラベルを指定する
> AILZ80ASM sample.z80 -bin -dl TEST1=10 TEST2=20 TEST3

■ -omオプションのヘルプを表示
> AILZ80ASM -h -om

コマンドライン: ラベル指定

コマンドラインからラベルを指定することができます。代入式で指定すると値を設定できます。ラベル単体で記述した場合は#TRUEが設定されます。ネームスペースを指定して出力するには「.」で区切って指定します。

> AILZ80ASM sample.z80 -bin -equ -dl TEST1=10 TEST2=20 TEST3 NSTEST.TEST4=40

file: sample.equ
[NAME_SPACE_DEFAULT]
TEST1           equ 10
TEST2           equ 20
TEST3           equ #TRUE

[NSTEST]
TEST4           equ 40

コマンドライン 戻り値

コマンドライン デフォルト値の設定

EXEと同じフォルダに以下の形式で「AILZ80ASM.json」を保存

スーパーアセンブルモードについて

特定のエラーがアセンブル時に発生した場合、再アセンブルを行ってエラーを解決するためのモードです。このモードを適用する前に、アセンブル解析の結果を確認し、再アセンブルによってエラーが解決できる可能性がある場合に限り、このモードが実行されます。このモードは、以下のエラーに対して有効です。

※ スーパーアセンブルモードを無効にする場合には、コマンドラインオプションに '-nsa' を付けてください

エントリーポイントについて

CMT形式の読み込みアドレスに利用されるエントリーポイントは、以下の優先順位で利用されます。

  1. コマンドラインオプション (-ep) で指定した値
  2. END で指定した値
  3. アセンブル結果が出力される最初のプログラムアドレス

新バージョン導入の手順

  1. 新バージョンを入手
  2. インストール済みのAILZ80ASMでアセンブルを行う
  3. インストール済みのAILZ80ASMを退避
  4. 新バージョンでAILZ80ASMを置き換える
  5. 新バージョンでコマンドラインオプションに「-df」を付け、差分確認アセンブルを行う
  6. アセンブル結果が一致しているかが表示される
  7. アセンブル結果が一致していたら置き換え可能、一致していなければ置き換え不可なので退避したプログラムを元に戻す

ソースコード書式

ニーモニック

未定義命令 (Undocumented Instructions)

ラベル

ラベルは、ネームスペース、標準ラベル、ローカルラベルで指定します。ネームスペースを指定しない場合には、 'NAME_SPACE_DEFAULT' が割り当てられています。必要に応じて変更をしてください。ラベルは指定した行以降は、下位のラベルを利用するときには上位のラベル名を省略することが出来ます。テンポラリーラベルは、.@に数字で宣言します。匿名ラベルは、.@@で宣言します。

ラベルに使用できる文字と出来ない文字列

大文字と小文字の区別

テンポラリーラベルと匿名ラベルについて

テンポラリーラベルは、.@に数字をつけて宣言します。テンポラリーラベルの制約として、ラベル名が一意である必要があります。例えば、ローカルラベル内では.@1 を一度しか宣言できません。匿名ラベルの場合は、ローカルラベル内に、.@@を複数記述することが出来ます。

ラベルの宣言

ラベルの指定

テンポラリーラベルの指定

ローカルラベルが存在する場合

ラベルの機能

ラベルの機能 (糖衣構文)

ラベル指定サンプル

    org $8000
    ld a, 0
addr:
    ld a, (addr)
    ld hl, addr
.test
    ld a, (addr.test)
    ld hl, addr.test
    ld hl, (addr.test)

テンポラリーラベルの指定サンプル

    org $8000
    ld a, 0
addr:
    ld a, (addr)
.@1                     ; (1) addr..@1
    ld hl, addr
.test
    ld a,(.@1)          ; 参照先 (2) 【注意:(1)は参照されない】
.@1                     ; (2) addr.text.@1
    ld hl, addr.test
.@2                     ; (3) addr.text.@2
    ld hl, (addr.test)
    ; 参照
    ld hl, (addr..@1)   ; 参照先 (1)
    ld hl, (.text.@1)   ; 参照先 (2)
    ld hl, (.@1)        ; 参照先 (2)
    ld hl, (.@2)        ; 参照先 (3)
    ; 特殊アクセス
EQT:
.@1 equ %00001100   ; (4) EQT..@1
.@2 equ %00001101   ; (5) EQT..@2
.@3 equ %00001110   ; (6) EQT..@3
    ;【マジック実装】本来ならEQT.AL.@1 を参照するが、存在しないとき EQT..@1を参照する
.AL equ (.@1 | .@2 | .@3) ; 参照先 (4) | (5) | (6)

即値

文字と文字列について

エスケープシーケンス

エスケープ シーケンス 表現 Unicode エンコーディング
\' 単一引用符「'」 0x0027
\" 単一引用符「"」 0x0022
\\ 円記号「\」 0x005C
\0 Null 0x0000
\a ベル (警告) 0x0007
\b バックスペース 0x0008
\f フォーム フィード 0x000C
\n 改行 0x000A
\r キャリッジ リターン 0x000D
\t 水平タブ 0x0009
\v 垂直タブ 0x000B

内蔵CHARMAP一覧

名前 デフォルト 詳細
@SJIS * シフトJIS
@JIS1 JIS第1水準
@JIS12 JIS第1水準・第2水準

ロケーションカウンタ

詳細は、ORG命令の章をご覧ください

値を指定するところに、式を使用することができます。使用できる演算子と優先順位は、下の表のとおりです。 優先順位 演算子 コメント
1 ( ) 括弧
2 low high exists text backward forward near far 下位8ビット 上位8ビット ラベル存在 ラベル値文字列 後方ラベル 前方ラベル 近いラベル 遠いラベル
3 + - ! ~ 正記号 負記号 論理NOT ビット反転
4 * / % 乗算 除算 剰余
5 + - 加算 減算
6 << >> 左シフト 右シフト
7 < > <= >= 算術比較
8 == != 算術比較
9 & ビットAND
10 ^ ビットXOR
11 | ビットOR
12 && 論理AND
13 || 論理OR
14 : 三項演算子
15 ? 三項演算子

※大文字と小文字は区別しません

low 演算子

下位8ビットを取得します

    ld a, low $1234 ; a = $34

high 演算子

上位8ビットを取得します

    ld a, high $1234 ; a = $12

exists 演算子

ラベルが存在する時には、 #TRUEを返します。ラベルが存在しない時には、#FALSE を返します。

LB1 equ $10

    #IF exists LB1
        ;展開されます
    #ENDIF

    #IF exists LB2
        ;展開されません
    #ENDIF

text 演算子

ラベルに設定された文字列を取得します。

    LDEX a, 1
    LDEX b, 1

LDEX MACRO arg1, arg2
    #IF text arg1 == "a"
        ld a, arg2
    #ELSE
        ld b, arg2
    #ENDIF

    ENDM

backward 演算子

後方(アドレスが小さい方)のラベルを指定します。

LB:
.Sub1
.@1             ; ここが参照されています
.Sub2
    JP backward .@1
.Sub3
.@1

forward 演算子

前方(アドレスが大きい方)のラベルを指定します。

LB:
.Sub1
.@1
.Sub2
    JP forward .@1
.Sub3
.@1             ; ここが参照されています

near 演算子

プログラムアドレスが近いラベルを参照します。距離が同じ場合には後方(アドレスが小さい方)のラベルが優先されます。

LB:
.Sub1
.@1             ; ここが参照されています
.Sub2
    JP near .@1
.Sub3
    LD HL, 0
    LD DE, HL
.@1

far 演算子

プログラムアドレスが遠いラベルを参照します。距離が同じ場合には後方(アドレスが小さい方)のラベルが優先されます。

LB:
.Sub1
.@1
.Sub2
    JP far .@1
.Sub3
    LD HL, 0
    LD DE, HL
.@1             ; ここが参照されています

アドレス指定について

式に()を利用することが出来ますが、命令には()が含まれるものがあります。式の全体を()で囲むとアドレス指定になります。

    ld a,($1234 + 5)    ;アドレス指定
    ld a,($1234) + 5    ;値として指定されます。16bit値が指定されているので、ワーニングが表示されます。

コメント

アドレス・制御命令

ORG <式>, [<式2>], [<式3>]

本アセンブラの特徴として、アセンブル時のアドレスとアウトプット時のアドレスを別で管理しています。通常モードで利用する場合には、第一引数だけで利用してください。アウトプットアドレスは自動的に制御されます。第二引数を利用した時には、アウトプットアドレスを制御できます。その時にはROM出力モードになり、ラベルに使われるアドレスと出力のアドレスを別々に制御することが出来ます。プログラム・ロケーションカウンターは、アセンブル内で重複可能になります。アウトプット時のアドレスは、アウトプット・ロケーションカウンターと呼び、バイナリデータの出力位置を指定します。出力用のアドレスになりますので、重複することは出来ません。

    ORG $1000
LB1000:
    LD A, (LB1000)

    ORG $1010
LB1010:
    LD A, (LB1010)

    ORG $2000, $0020
LB2000:
    LD A, (LB2000)

出力結果

0000 3A 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00
0010 3A 10 10 00 00 00 00 00 00 00 00 00 00 00 00 00
0020 3A 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00

ALIGN <式>, [<式2>]

DS <式>, [<式2>]

制御命令

<ラベル> EQU <式>

PORT_A  equ $CC
.WRITE  equ $01
.READ   equ $02

    LD A, PORT_A.WRITE
    OUT (PORT_A), A

    LD A, PORT_A.READ
    OUT (PORT_A), A

CHARMAP <CHARMAP名>, <ファイル名>

アセンブラ内で利用する、文字列の変換テーブルをロードします。

INCLUDE <ファイル名>, [<ファイルタイプ>], [<開始位置>], [<長さ>]

ファイル名の内容を読み取り、その場所に展開します

DB <式>, [<式>]

DB [<変数名>=<ループ開始値>..<ループ終了値>:<式>]

DW <式>, [<式>]

DW [<変数名>=<ループ開始値>..<ループ終了値>:<式>]

DBFIL <式>, [<式2>]

DWFIL <式>, [<式2>]

マクロ

<マクロ名> MACRO [<引数1>, <引数2>] ~ ENDM

ARG1    equ 2
.Three  equ 3

    ALLLD
    TestArg ARG1, ARG1.Three
    INITLD B    ; レジスター名を指定

ALLLD MACRO
    ld a,1
    ld b,2
    ld c,3
    ld d,4
    ld e,5
    ld h,6
    ld l,7
    ENDM

TestArg MACRO a1, a2
    ld a, a1
    ld b, a2
    ENDM

INITLD MACRO REG
    LD A, REG
    LD REG, 0
    ENDM

REPT <式1> [LAST <式2>] ~ ENDM

    REPT 3
        xor     a
    ENDM

    REPT 8 LAST -1
        ld      (hl), a
        set     5, h
        ld      (hl), a
        add     hl, de
    ENDM

※ LAST -1で消える行にラベルが設定されている場合にはエラーになります。2行に分ける等の工夫をしてください。

    REPT 8 LAST -1
        ld      (hl), a
        set     5, h
        or      a
        jr      z, .@1
        add     hl, de
.@1     add     hl, de
    ENDM

<名前> ENUM ~ <ラベル名> : <長さ> = <値> ~ ENDM

Color ENUM
    RED = 5          ; 5
    GREEN            ; 6
    BLUE :2          ; 7, サイズ2バイト
    YELLOW           ; 9
    ORANGE :2 = 12   ; 12, サイズ2バイト
    CYAN             ; 14
    PURPLE = RED-1   ; 4
ENDM

INIT:
    LD  A, Color.RED    ; 5
    LD  B, Color.GREEN  ; 6
    LD  C, Color.BLUE   ; 7
    LD  D, Color.YELLOW ; 9
    LD  E, Color.ORANGE ; 12
    LD  H, Color.CYAN   ; 14
    LD  L, Color.PURPLE ; 4

FUNCTION <名前>([<引数1>, <引数2>]) => <式>

式をまとめる事が出来ます

    LD A, ABS(-1)   ; LD A, 1
    LD B, ABS(1)    ; LD B, 1

Function ABS(value) => value < 0 ? value * -1 : value

END [<式1>]

アセンブルの実行を中断します。これ以降のソースコードはアセンブルされません。アセンブル結果は出力されます。

コード・チェック

CHECK ALIGN <式1>[, <式2>] ~ ENDC

CHECKからENDCで囲まれた範囲のアセンブル結果がアライメント境界を超えるとアセンブルエラー(E6002)になります。

プリプロセッサ

条件付きアセンブル

条件付きアセンブルを制御します

PRINT <引数1> [<引数2>]

アセンブルの情報をインフォメーション[I0001]として表示します。

TEST1   EQU 1
TEST2   EQU 2

    #PRINT "TEST1:{0}, TEST2:{1}", TEST1, TEST2

PRAGMA (プラグマ)

PRAGMA ONCE

ソースコードをアセンブルするときに、記述があるファイルを1回だけアセンブルすることを指定します

#pragma once

LABEL   equ 00FFH

ラベルの再定義エラーを回避する方法 (#pragma onceの利用を推奨)

#if LABEL.@EXISTS
LABEL   equ 00FFH
#endif
#if exists LABEL
LABEL   equ 00FFH
#endif
LIST <引数1>

LST形式のファイルの出力を停止します。

on  equ #TRUE
off equ #FALSE

    ld  a, 0

    #LIST off

    ld  b, 1

    #LIST on

    ld  c, 2

    ret

表記の揺れ対応

エラー

仕様の裏話

謝辞

Z80資料