0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Z80のDAA命令の動作を調べてみた

Posted at

Z80 には、BCD (二進化十進数) の加算や減算の後に用いて計算結果を補正する DAA 命令がある。
この命令の動作について、Zilog 社の資料 UM0080 (Z80 CPU User Manual) では記述が足りなかったので、EMUZ80 を用いて調べてみた。
今回用いた EMUZ80 には、「LH0080」と書かれた CPU が搭載されている。

今回用いた EMUZ80

アセンブラとして、MikeAssembler を用いた。

UM0080 に載っている DAA 命令の情報

UM0080 において、DAA 命令の情報は、「Z80 Instruction Set」の中の「General-Purpose Arithmetic and CPU Control Groups」内に載っている。
これを見ると、DAA 命令の実行前の

  • C フラグ
  • H フラグ
  • A レジスタ (アキュムレータ) の値

から、

  • DAA 命令の実行後の C フラグ
  • A レジスタ (アキュムレータ) に加算する値

を求める表が載っている。
この表の内容をまとめると、以下のようになっている。
ただし、それぞれの表の左上の C=x, H=x は、その表における DAA 命令の実行前 (入力) のフラグを表す。

UM0080 に載っている DAA 命令の入力と出力の関係

図示するとわかるように、UM0080 に載っている表の情報では、出力が定義されていない入力が多い。
(検証していないが、BCD の計算の結果としてあり得る部分しか載せていないのかな……?)

また、加算をしたか減算をしたかを表す N フラグは、いかにも DAA 命令の動作に関わってきそうであるが、表には出てきていない。
(表に Operation は載っているが、Operation が違っても他の入力が被らないか結果が同じである)

さらに致命的な点として、DAA 命令の実行後の H フラグの値は「テーブルを見てね」となっているにもかかわらず、テーブルに実行後の H フラグの情報が全く見当たらないのである。
なんでや……?

なお、残りの S・Z・P/V フラグについては実行後の A レジスタの値から求める方法が載っており、N フラグについては「変化しない」となっている。

他の資料に載っている DAA 命令の情報

Zilog Z80 DAA実行結果

互換CPUで実際に実行して得た結果とされる表が載っている。
入力の A レジスタの値全範囲がカバーされ、入力の N フラグとの関係も載っている。
しかし、残念ながらここにも出力の H フラグの情報が無い。

Z80 Instruction - DAA

表が載っているが、UM0080 に載っているものと同じようである。

daatable/daaoutput.txt at master · ruyrybeyro/daatable

DAA 命令の入力と、それに対する H フラグの値を含む出力の表が載っている。
これは「ZX Spectrum」というものでの話らしく、同じリポジトリ内に表を生成するプログラムもある。
ただし、N=1, C=1, H=0 を入力とするときの出力はなぜか載っておらず、かわりに? N=0, C=1, H=1 を入力とするときの出力がなぜか2回ずつ載っている。

内部キャリーフラグがあるかを調べるプログラムを動かす

Z80 DAA 内部キャリーフラグは実在するのか?

では、「Z80 の DEC 命令は処理結果の情報を通常のフラグレジスタとは別に保存しておき、DAA 命令の動作に影響を与える……とザイログ社の資料に書かれているが、実際にはそんなことはなさそう」と主張している。
さらに、実際に DEC 命令と DAA 命令の関係を調べるプログラムが掲載されている。
このプログラムを読んでみると、以下のような特徴が読み取れた。

  • 0x100 番地から配置するように指定されている
  • E レジスタに出力する文字、C レジスタに定数 2 を格納して 0x5 番地を呼び出すことで、1文字を出力しようとしている
  • DE レジスタペアに出力するデータの先頭アドレス、C レジスタに定数 9 を格納して 0x5 番地を呼び出すことで、指定したアドレスから $ の手前までのデータを連続して出力しようとしている

そこで、このプログラムを EMUZ80 で動かしてみるため、MikeAssembler の仕様に合わせるため以下の置換を行った。

  • dbdatab に置換する
  • ([0-9a-f]+)h(?! \$)0x$1 に、正規表現で大文字と小文字を区別して置換する

大文字と小文字を区別しないと、ラベルの fH が置換されてしまい、プログラムが壊れてしまった。
また、否定先読みを用い、文字列中に現れる 0ffbah を置換しないようにした。

さらに、特徴に合わせた以下のプログラムを、掲載されているプログラムの前に追加した。

内部キャリーフラグの検証プログラムを動かすためのプログラム
target z80

	JP entry

	ORG 5
	PUSH AF
	LD A, C
	CP 2
	JR Z, call_imp_putc
	CP 9
	JR Z, call_imp_puts
return_from_call:
	POP AF
	RET
call_imp_putc:
	CALL imp_putc
	JR return_from_call
call_imp_puts:
	CALL imp_puts
	JR return_from_call

entry:
	LD SP, 0x9000
	CALL 0x100
end:
	HALT
	JR end

; E レジスタに格納された1文字をUARTに出力する
imp_putc:
	LD A, (0xe001)
	BIT 1, A
	JR Z, imp_putc
	LD A, E
	LD (0xe000), A
	RET

; DE レジスタに格納されたアドレスから '$' の手前までのデータをUARTに出力する
imp_puts:
	PUSH DE
	PUSH HL
	LD H, D
	LD L, E
imp_puts_loop:
	LD E, (HL)
	LD A, '$'
	CP E
	JR NZ, imp_puts_proceed
	POP HL
	POP DE
	RET
imp_puts_proceed:
	CALL imp_putc
	INC HL
	JR imp_puts_loop

プログラムを実行すると、以下の出力が得られた。

[normal]
xor a        A:00 F:-Z---P--
dec a        A:FF F:S-5H3-N-
daa          A:99 F:S---3PNC
[set AF value]
xor a        A:00 F:-Z---P--
ld hl,0ffbah A:00 F:-Z---P--
push hl      A:00 F:-Z---P--
inc a        A:01 F:--------
dec a        A:00 F:-Z----N-
pop af       A:FF F:S-5H3-N-
daa          A:99 F:S---3PNC

この結果は、ページに掲載されている「HB-11実機とFS-A1ST実機Z80モード(T9769C)での実行結果」と同じである。
よって、DEC 命令が A レジスタおよびフラグレジスタ以外に保存した情報を DAA 命令が参照していることはなさそう、と判定できる。

DAA 命令の入力と出力の関係の表を作る

DAA 命令に入力する N・C・H フラグと A レジスタの値の全ての組み合わせを試し、A レジスタに加算される値と出力の C・H フラグを表にする、以下のプログラムを作成した。

このプログラムは、それぞれの組み合わせについて、A レジスタに加算される値を16進数2桁で出力し、続いて H フラグ・C フラグが立っているかをそれぞれ 2・1 を足すかで表した1桁を出力する。
表では、列 (上の見出し) が入力の A レジスタの下位4ビットを、行 (左の見出し) が入力の A レジスタの上位4ビットを表す。

DAA 命令の出力を表にするプログラム
target z80

define FLAG_LOOP_CNT, 0x8000

	LD SP, 0x8100
	; 入力のフラグの組み合わせを試す
	XOR A
	LD (FLAG_LOOP_CNT), A
flag_loop:
	; 用いるフラグの組み合わせを出力する
	LD A, (FLAG_LOOP_CNT)
	LD B, A
	LD A, 'N'
	CALL putchar
	LD A, '='
	CALL putchar
	LD A, B
	RRA
	RRA
	AND 1
	ADD A, '0'
	CALL putchar
	LD A, ','
	CALL putchar
	LD A, ' '
	CALL putchar
	LD A, 'C'
	CALL putchar
	LD A, '='
	CALL putchar
	LD A, B
	RRA
	AND 1
	ADD A, '0'
	CALL putchar
	LD A, ','
	CALL putchar
	LD A, ' '
	CALL putchar
	LD A, 'H'
	CALL putchar
	LD A, '='
	CALL putchar
	LD A, B
	AND 1
	ADD A, '0'
	CALL putchar
	LD A, '\n'
	CALL putchar

	; ヘッダを出力する
	LD B, 16
header_loop:
	LD A, ' '
	CALL putchar
	CALL putchar
	CALL putchar
	LD A, 16
	SUB B
	CALL printhex
	DJNZ header_loop
	LD A, '\n'
	CALL putchar

	; フラグの組み合わせを構築する
	LD A, (FLAG_LOOP_CNT) ; A = 00000NCH
	SRL A ; A = 000000NC, C flag = H
	LD D, A ; D = 000000NC
	LD A, 0
	RRA
	RRA
	RRA
	RRA ; A = 000H0000
	OR D ; A = 000H00NC
	LD E, A

	; 入力のAレジスタの値を試す
	XOR A
	LD D, A
test_outer_loop:
	LD A, ' '
	CALL putchar
	LD A, D
	RRA
	RRA
	RRA
	RRA
	CALL printhex
test_inner_loop:
	LD A, ' '
	CALL putchar
	PUSH DE
	POP AF
	DAA
	PUSH AF
	POP BC
	; 「処理後のAレジスタの値」から「処理前のAレジスタの値」を引き、足された数を求める
	SUB D
	LD B, A
	RRA
	RRA
	RRA
	RRA
	CALL printhex
	LD A, B
	CALL printhex
	; 処理後のHフラグを2、Cフラグを1として、組み合わせを求める
	LD A, C
	RRA
	RRA
	RRA
	AND 2
	LD B, A
	LD A, C
	AND 1
	OR B
	CALL printhex

	; 次の数に進む、それが16の倍数なら改行する
	INC D
	LD A, D
	AND 0xf
	JP NZ, test_inner_loop
	LD A, '\n'
	CALL putchar
	; 一周してなければ、続行する
	LD A, D
	AND A
	JP NZ, test_outer_loop

	; 次のフラグの組み合わせを試す
	LD A, (FLAG_LOOP_CNT)
	INC A
	LD (FLAG_LOOP_CNT), A
	CP 8
	JP C, flag_loop
end:
	HALT
	JR end

; A レジスタに格納した1バイトをUARTに出力する
putchar:
	PUSH AF
putchar_wait:
	LD A, (0xe001)
	BIT 1, A
	JR Z, putchar_wait
	POP AF
	LD (0xe000), A
	RET

; A レジスタの下位4ビットを16進数でUARTに出力する
printhex:
	PUSH AF
	AND 0xf
	ADD A, '0'
	CP '9' + 1
	JR C, printhex_noadjust
	ADD A, 'A' - '0' - 10
printhex_noadjust:
	CALL putchar
	POP AF
	RET

このプログラムを実行すると、以下の出力が得られた。

DAA 命令の出力を表にするプログラムの実行結果
N=0, C=0, H=0
   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
 0 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 1 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 2 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 3 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 4 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 5 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 6 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 7 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 8 000 000 000 000 000 000 000 000 000 000 062 062 062 062 062 062
 9 000 000 000 000 000 000 000 000 000 000 663 663 663 663 663 663
 A 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 B 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 C 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 D 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 E 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 F 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
N=0, C=0, H=1
   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
 0 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 1 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 2 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 3 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 4 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 5 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 6 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 7 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 8 060 060 060 060 060 060 060 060 060 060 062 062 062 062 062 062
 9 060 060 060 060 060 060 060 060 060 060 663 663 663 663 663 663
 A 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 B 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 C 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 D 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 E 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 F 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
N=0, C=1, H=0
   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
 0 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 1 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 2 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 3 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 4 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 5 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 6 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 7 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 8 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 9 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 A 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 B 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 C 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 D 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 E 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
 F 601 601 601 601 601 601 601 601 601 601 663 663 663 663 663 663
N=0, C=1, H=1
   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
 0 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 1 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 2 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 3 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 4 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 5 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 6 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 7 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 8 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 9 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 A 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 B 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 C 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 D 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 E 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
 F 661 661 661 661 661 661 661 661 661 661 663 663 663 663 663 663
N=1, C=0, H=0
   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
 0 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 1 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 2 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 3 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 4 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 5 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 6 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 7 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 8 000 000 000 000 000 000 000 000 000 000 FA0 FA0 FA0 FA0 FA0 FA0
 9 000 000 000 000 000 000 000 000 000 000 9A1 9A1 9A1 9A1 9A1 9A1
 A A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 B A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 C A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 D A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 E A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 F A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
N=1, C=0, H=1
   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
 0 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 1 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 2 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 3 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 4 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 5 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 6 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 7 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 8 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0 FA0
 9 FA2 FA2 FA2 FA2 FA2 FA2 FA0 FA0 FA0 FA0 9A1 9A1 9A1 9A1 9A1 9A1
 A 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 B 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 C 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 D 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 E 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 F 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
N=1, C=1, H=0
   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
 0 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 1 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 2 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 3 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 4 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 5 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 6 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 7 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 8 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 9 A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 A A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 B A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 C A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 D A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 E A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
 F A01 A01 A01 A01 A01 A01 A01 A01 A01 A01 9A1 9A1 9A1 9A1 9A1 9A1
N=1, C=1, H=1
   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
 0 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 1 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 2 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 3 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 4 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 5 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 6 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 7 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 8 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 9 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 A 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 B 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 C 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 D 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 E 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1
 F 9A3 9A3 9A3 9A3 9A3 9A3 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1 9A1

DAA 命令の入力と出力の関係

今回の自作プログラムにより得られた結果をまとめると、以下のようになった。

N=0 (加算後) のとき

N=0 のときの DAA 命令の実行結果

N=1 (減算後) のとき

N=1 のときの DAA 命令の実行結果

他のページの情報との比較

Zilog Z80 DAA実行結果

の表と比較すると、このページの情報は H フラグが無い分場合分けが少ないが、A レジスタに加算する値と C フラグの値は今回の結果と一致していた。

daatable/daaoutput.txt at master · ruyrybeyro/daatable

の結果と比較するため、この表を今回のプログラムの出力形式に変換するプログラムを作成した。

変換を行うプログラム (Perl)
#!/usr/bin/perl

use strict;
use warnings;

my %data = ();

while (my $line = <STDIN>) {
	if ($line =~ /N ([01]) C ([01]) H ([01]) ([0-9A-F]{2}) N ([01]) C ([01]) H ([01]) ([0-9A-F]{2})/) {
		my $key = "$1,$2,$3,$4";
		my $value = sprintf("%02X%d", (hex($8) - hex($4)) & 0xff, int($6) + int($7) * 2);
		if (defined($data{$key})) {
			if ($data{$key} ne $value) {
				warn "conflict: $key -> $data{$key} vs $value\n";
			}
		} else {
			$data{$key} = $value;
		}
	}
}

for (my $N = 0; $N <= 1; $N++) {
	for (my $C = 0; $C <= 1; $C++) {
		for (my $H = 0; $H <= 1; $H++) {
			print "N=$N, C=$C, H=$H\n";
			for (my $i = 0; $i < 0x10; $i++) {
				printf "   %X", $i;
			}
			print "\n";
			for (my $i = 0; $i < 0x10; $i++) {
				printf " %X", $i;
				for (my $j = 0; $j < 0x10; $j++) {
					my $key = sprintf("%d,%d,%d,%X%X", $N, $C, $H, $i, $j);
					my $value = $data{$key};
					if (defined($value)) {
						print " $value";
					} else {
						print " ???";
					}
				}
				print "\n";
			}
		}
	}
}

この変換結果を確認すると、表に載っていない N=1, C=1, H=0 の部分を除き、今回の結果と一致していた。

MSX でも DAA 命令を実行してみる

MSX では、Z80A (Z80 のクロックが速い版) 相当のCPUが使用されている
そこで、MSX BASIC から DAA 命令を実行し、動作を確認してみた。

まず、MSX BASIC から呼び出され、DAA 命令を実行するマシン語を用意した。
5章 マシン語とのリンク - MSX Datapack wiki化計画
を参考に、整数を受け取って整数を返す関数の形にした。

DAA 命令を実行するマシン語のアセンブリコード
target z80

; 16ビット整数の下位8ビットにAレジスタ、上位8ビットにFレジスタの値を入れる
; (入力、出力共通)
; ただし、出力時、負の数にならないようSフラグ (最上位) を強制的に0にする

CP 2
RET NZ
PUSH HL
POP IX
LD B, (IX + 2)
LD C, (IX + 3)
PUSH BC
POP AF
DAA
PUSH AF
POP BC
LD A, C
AND 0x7f
LD (IX + 2), B
LD (IX + 3), A
RET

そして、これを埋め込んで呼び出すプログラムを作成した。
4章 BASICの内部構造 - MSX Datapack wiki化計画
を参考に、

  1. SPACE$ を用い、マシン語を格納する領域を文字列として確保する
  2. 整数型変数の値を、文字型変数の文字列格納アドレスに設定する
  3. 設定した変数を用いて、DATA で埋め込んだマシン語を文字列の領域にコピーする

という手順で、用意したマシン語を USR で実行できる形にした。

DAA 命令を実行する MSX BASIC のプログラム
10 DEFINT N,C,H,I,J,K,P,Q,R,A,B,F
20 U$=SPACE$(&H1B):P=0
30 Q=VARPTR(U$):R=VARPTR(P)
40 POKE R,PEEK(Q+1)
50 POKE R+1,PEEK(Q+2)
60 FOR I=0 TO &H1A
70 READ C:POKE P+I,C
80 NEXT
90 DATA &HFE,&H02,&HC0,&HE5
100 DATA &HDD,&HE1,&HDD,&H46
110 DATA &H02,&HDD,&H4E,&H03
120 DATA &HC5,&HF1,&H27,&HF5
130 DATA &HC1,&H79,&HE6,&H7F
140 DATA &HDD,&H70,&H02,&HDD
150 DATA &H77,&H03,&HC9
160 DEF USR=P
170 FOR N=0 TO 1
180 FOR C=0 TO 1
190 FOR H=0 TO 1
200 FOR K=0 TO 8 STEP 8
210 PRINT "N=";HEX$(N);
220 PRINT ", C=";HEX$(C);
230 PRINT ", H=";HEX$(H)
240 FOR I=0 TO 7
250 PRINT "   ";HEX$(K+I);
260 NEXT I
270 PRINT
280 FOR I=0 TO &HF
290 PRINT " ";HEX$(I);
300 FOR J=0 TO 7
310 A=I*16+K+J:F=H*&H10+N*2+C
320 B=USR(F*&H100+A)
330 F=B\&H1000 MOD 2
340 F=F*2 + B\&H100 MOD 2
350 B=B MOD &H100 - A
360 IF B<0 THEN B=B+&H100
370 B=B*&H10+F:PRINT " ";
380 IF B<&H10 THEN PRINT "0";
390 IF B<&H100 THEN PRINT "0";
400 PRINT HEX$(B);
410 NEXT J
420 PRINT
430 NEXT I
440 IF INKEY$="" THEN GOTO 440
450 NEXT K:NEXT H:NEXT C:NEXT N

それぞれの表を左右に分割して半分ずつ表示し、キーを押すと次の表に進むようにした。
これを WebMSX で実行すると、今回の結果と同様の結果が得られた。

MSXPen で実行する

まとめ

Z80 の DAA 命令について、入力 (A レジスタ、および N・C・H フラグ) と出力 (A レジスタに加算される値、および C・H フラグ) の関係を出力するプログラムを作成した。
このプログラムを用いて、EMUZ80 および WebMSX における DAA 命令の動作を確認した。
さらに、これにより得られた結果が、今回の調査で見つけた DAA 命令の動作のうち一部の情報しか載っていないページの情報と整合性が取れていることを確認した。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?