File:  [Isaki's NoNo m68k/m88k emulator] / nono / exp / fmovemn.php
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:36 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, v024, v023, v022, HEAD
nono 1.2.0

;
; nono
; Copyright (C) 2020 nono project
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
; 1. Redistributions of source code must retain the above copyright
;    notice, this list of conditions and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright
;    notice, this list of conditions and the following disclaimer in the
;    documentation and/or other materials provided with the distribution.
;
; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
; AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
; SUCH DAMAGE.

; How to compile:
;  > has fmovemn.has
;  > hlk fmovemn.o si_util.o

	.xref	hexstr_long
	.include doscall.mac
	.include iocscall.mac
	.list
	.cpu	68030

PRINT	.macro	msg
	pea.l	msg
	DOS	_PRINT
	addq.l	#4,sp
	.endm

	.text
	.even

<?php
	// レジスタ割り当て
	// d0-d1	work
	// d4	d8(An,IX) の IX で使う。形式だけでいいので値は 0。
	// d5	0=easy, $ffffffff=hard
	// d6	ダイナミックモードでのレジスタ
	// d7	1=検査対象命令でFライン例外がおきた
	//      その後は ok を表示するかどうかのカウント
	// a0-a2	work
	// a3	検査対象命令の次の位置 (Fライン例外から戻るのに使用)
	// a4	元のFライン例外ハンドラ置き場
?>
<?php

	// 第2ワードの下位バイトが FP 指定、3通りある。
	//
	//  b7  b6  b5  b4  b3  b2  b1  b0
	// -------------------------------
	// FP7 FP6 FP5 FP4 FP3 FP2 FP1 FP0 : static pred
	// FP0 FP1 FP2 FP3 FP4 FP5 FP6 FP7 : static ctrl
	//  0   r   r   r   0   0   0   0  : dynamic
	//
	// ここでは常に %0110'0000 ($60) を指定しておき、
	// プリデクリメントなら FP6-FP5、
	// それ以外なら FP1-FP2、
	// 動的レジスタ指定なら d6 を指すようにしておく。
	// d6 の中は $30 (FP5-FP4 か FP2-FP3 になる) にしておく。
	$d6 = "$30";

	$srctable = array(
		//   dir ,mode1          easy       hard
		0 /* toFP,   pred */ => ".......... !!m+!rxwp!",
		2 /* toFP,   ctrl */ => "..m+.rxwp. !!m+!rxwp!",
		4 /* fromFP, pred */ => "....-..... !!m!-rxw!!",
		6 /* fromFP, ctrl */ => "..m..rxw.. !!m!-rxw!!",
	);
	$testlist = array();
	$testnum = 0;
	foreach ($srctable as $mode21 => $eastr) {
		list ($easy_str, $hard_str) = preg_split('/\s+/', $eastr);
		$easy_ea = preg_split("//", $easy_str, -1, PREG_SPLIT_NO_EMPTY);
		$hard_ea = preg_split("//", $hard_str, -1, PREG_SPLIT_NO_EMPTY);
		// mode0 ビットは dynamic or static。
		for ($mode0 = 0; $mode0 <= 1; $mode0++) {
			$mode = $mode21 + $mode0;
			for ($i = 0; $i < 10; $i++) {
				$eatype = substr("dam+-rxwpi", $i, 1);
				$ee = $easy_ea[$i];
				$eh = $hard_ea[$i];

				// 難しいので保留。
				if ($i >= 7) {
					continue;
				}

				// 命令語。
				$inst = 0xf200c060;
				$inst |= eatype2word($eatype) << 16;
				$inst |= $mode << 11;

				$test = array(
					"num" => $testnum++,
					"mode" => $mode,
					"mem_to_fp" => (($mode & 4) == 0),
					"is_pred" => (($mode & 2) == 0),
					"dynamic" => (($mode & 1) != 0),

					"eatype" => $eatype,
					"is_easy" => ($ee != '.'),
					"is_trap" => ($eh == '!'),
					"inst" => $inst,
				);
				$testlist[] = $test;
			}
		}
	}
?>
start:
	clr.l	-(sp)
	DOS	_SUPER
	movem.l	d4-d7/a2-a4,-(sp)
	moveq.l	#<?php print $d6; ?>,d6	; Init D6 for dynamic
	moveq.l	#0,d4		; Init D4 for d8(An,IX)
	fmove.l	d4,fpcr		; Init FPCR, especially round mode and round prec.

	; rough argument check
	cmpi.b	#4,(a2)+	; strlen(arg)<4 ?
	bcs	easymode
	cmpi.l	#$68617264,(a2)	; "hard"
	bne	easymode

hardmode:
	moveq.l	#-1,d5
	PRINT	msg_hard(pc)
<?php
	foreach ($testlist as $test) {
		out("	bsr	test_{$test["num"]}");
	}
?>
	bsr	test_nofpn
	bsr	test_illdyn
	bra	done

easymode:
	moveq.l #0,d5
	PRINT	msg_easy(pc)
<?php
	foreach ($testlist as $test) {
		if ($test["is_easy"]) {
			out("	bsr	test_{$test["num"]}");
		}
	}
?>

done:
	movem.l	(sp)+,d4-d7/a2-a4
	DOS	_EXIT

<?php
	// テスト本体を出力。
	foreach ($testlist as $test) {
		$dir = $test["mem_to_fp"] ? "to" : "from";
		$pred = $test["is_pred"] ? "pred" : "ctrl";
		$dyn  = $test["dynamic"] ? "dyn" : "sta";
		$hard = $test["is_easy"] ? "" : " (hard)";
		out("; {$dir},{$pred},{$dyn},EA={$test["eatype"]}{$hard}");
		out("test_%d:", $test["num"]);
		// msg_test_* は先頭にテスト番号 "nn:ctrl;" が8バイトある。
		// hard モードでは表示したいが easy モードでは表示したくない。
		out("	moveq.l	#-8,d0");
		out("	and.w	d5,d0");
		out("	PRINT	msg_test_{$test["num"]}+8(pc,d0.w)");

		if ($test["is_trap"]) {
			test_trap($test);
		} else {
			if ($test["mem_to_fp"]) {
				test_to($test);
			} else {
				test_from($test);
			}
		}
	}
?>
<?php
function test_trap($test)
{
	// 実行
	out_run($test, "");

	// 例外が起きるはずなので D7 が非ゼロなら成功(次へ)
	out("	tst.l	d7");
	out("	bne	@f");
	out("	PRINT	msg_fail_notrap(pc)");
	out("	rts");
	out("@@:");
	out("	PRINT	msg_oktrap(pc)");
	out("	rts");
	out("");
}

function test_to($test)
{
	$eatype = $test["eatype"];

	// FPn を初期化。(こっちでは使わない書き込みバッファも初期化されるけど)
	out("	bsr	init_from");

	// 実行。
	out_run($test, "srcdata");

	// 例外は起きないはずなので D7 がゼロなら成功(次へ)
	out("	tst.l	d7");
	out("	beq	@f");
	out("	PRINT	msg_fail_trap(pc)");
	out("	rts");
	out("@@:");

	// An を照合する。
	// (An)  なら変化なし。
	// -(An) なら実行前に進めてあるので +0 に戻る。
	// (An)+ なら進む。
	out("	lea.l	srcdata%s(pc),a1", ($eatype == "+" ? "+24" : ""));
	out("	cmp.l	a1,a0");
	out("	beq	@f");
	out("	pea.l	msg_fail_addr(pc)");
	out("	move.l	a1,-(sp)");
	out("	move.l	a0,-(sp)");
	out("	bsr	result");
	out("	lea.l	12(sp),sp");
	out("@@:");

	// FPn を比較。
	// 8本のうち、どこかの2本が (昇順か降順かで) 書き換わってる。
	// $s1 が srcdata+0  が転送されたレジスタ番号、
	// $s2 が srcdata+12 が転送されたレジスタ番号。
	list ($s1, $s2) = get_fplist($test);
	// ただし src が -(An) なら(undocumented)、レジスタは書き換わらないようだ。
	if ($eatype == "-") {
		$s1 = -1;
		$s2 = -1;
	}

	out("	lea.l	workarea(pc),a2");
	for ($i = 0; $i < 8; $i++) {
		out("	; compare FP${i}");
		out("	pea.l	msg_fail_fp{$i}(pc)");
		if ($i == $s1) {
			out("	pea.l	srcdata(pc)");
		} else if ($i == $s2) {
			out("	pea.l	srcdata+12(pc)");
		} else {
			out("	pea.l	(initdata+%d*12)(pc)", $i);
		}
		out("	fmove.x	fp{$i},(a2)");
		out("	pea.l	(a2)");
		out("	bsr	check_ext");
		out("	lea.l	12(sp),sp");
	}

	out("");
	out("	tst.l	d7");
	out("	bne	@f");
	out("	PRINT	msg_ok(pc)");
	out("@@:");
	out("	rts");
	out("");
}

function test_from($test)
{
	$eatype = $test["eatype"];

	// FPn と書き込みバッファを初期化。
	out("	bsr	init_from");

	// 実行
	out_run($test, "workarea");

	// 例外は起きないはずなので D7 がゼロなら成功(次へ)
	out("	tst.l	d7");
	out("	beq	@f");
	out("	PRINT	msg_fail_trap(pc)");
	out("	rts");
	out("@@:");

	// An を照合する。
	// (An)  なら変化なし。
	// -(An) なら実行前に進めてあるので +0 に戻る。
	// (An)+ なら進む。
	out("	lea.l	workarea%s(pc),a1", ($eatype == "+" ? "+24" : ""));
	out("	cmp.l	a1,a0");
	out("	beq	@f");
	out("	pea.l	msg_fail_addr(pc)");
	out("	move.l	a1,-(sp)");
	out("	move.l	a0,-(sp)");
	out("	bsr	result");
	out("	lea.l	12(sp),sp");
	out("@@:");

	// workarea に書き出されたのを initdata と比較。
	if ($eatype == "+") {
		// dst が (An)+ なら(undocumented)、謎な書き込みが行われるようだ。
		// 法則はありそうだが分からないのでテストしないことにする。
		out("	PRINT	msg_skip_dst(pc)");
	} else {
		// workarea の若いアドレスから順に比較するが、
		// FMOVEM fpnlist,-(An) の時 (predec の時ではなく eatype='-' の時) は
		// 転送順にメモリを下っていくので、比較も下りながら行わないといけない。
		list ($s1, $s2) = get_fplist($test);
		$work = 0;
		if ($eatype == "-") {
			$work = 1 - $work;
		}
		out("	; compare first one");
		out("	pea.l	msg_fail_1st(pc)");
		out("	pea.l	(initdata+%d*12)(pc)", $s1);
		out("	pea.l	(%d*12)(a1)", $work);
		out("	bsr	check_ext");
		out("	lea.l	12(sp),sp");
		$work = 1 - $work;
		out("	; compare second one");
		out("	pea.l	msg_fail_2nd(pc)");
		out("	pea.l	(initdata+%d*12)(pc)", $s2);
		out("	pea.l	(%d*12)(a1)", $work);
		out("	bsr	check_ext");
		out("	lea.l	12(sp),sp");
	}
	out("");

	out("	tst.l	d7");
	out("	bne	@f");
	out("	PRINT	msg_ok(pc)");
	out("@@:");
	out("	rts");
	out("");
}

// 1行を出力する。引数は printf のように fmt... で指定可能。
// 改行はこちらで付加する。
function out()
{
	$args = func_get_args();
	$fmt = array_shift($args);
	print vsprintf($fmt, $args);
	print "\n";
}

// ターゲット実行部分を出力する。
function out_run($test, $label)
{
	// EA ごとに命令前後にいろいろ必要。
	// to/from どちらも EA (の先頭) が $label を指すようにする。
	$pre = "";
	$post = "";
	if ($test["is_trap"] == false) {
		switch ($test["eatype"]) {
		 case 'm':
		 case '+':
			$pre = "lea.l	{$label}(pc),a0";
			break;
		 case '-':
			$pre = "lea.l	({$label}+24)(pc),a0";
			break;
		 case 'r':	// d18(An)
			// 賢いアセンブラだと 0(An) は (An) にしてしまうが、ここは
			// 生の命令列を書き込んでいるので 0(An) は d16(An) 扱いになる。
			$pre = "lea.l	{$label}(pc),a0";
			$post = ".dc.w	0";
			break;
		 case 'x':	// d8(An,IX) = 0(An,d4<0>)
			$pre = "lea.l	{$label}(pc),a0";
			$post = ".dc.w	$4000";
			break;
		 case 'w':	// Abs、ここでは Abs.L のみ
			$post = ".dc.l	{$label}";
			break;
		 case 'p':	// d8(PC,IX)
			// これは難しいので保留。
			break;
		 default:
			break;
		}
	}
	if (strlen($pre) > 0) {
		out("	{$pre}");
	}
	out("	bsr	set_fline");
	out("	moveq.l	#0,d7");
	out("	lea.l	@f,a3");
	out("	.dc.l	$%08x", $test["inst"]);
	if (strlen($post) > 0) {
		out("	{$post}");
	}
	out("@@:");
	out("	bsr	restore_fline");
}

// ターゲットレジスタを返す。
// 制御モードとプリデクリメントとでビットの割り当てが違う。
// スタティックと動的ではあえて違うビットを割り当てている。
function get_fplist($test)
{
	$fplist = array(
		0 /*pred, static  */ => array(6, 5),
		1 /*pred, dynamic */ => array(5, 4),
		2 /*ctrl, static  */ => array(1, 2),
		3 /*ctrl, dynamic */ => array(2, 3),
	);
	$mode = $test["mode"];
	return $fplist[$mode & 3];
}

// EA 種別文字から命令ワードに。n はすべて0
function eatype2word($eatype)
{
	switch ($eatype) {
	 case 'd':	return 000; // D0
	 case 'a':	return 010; // A0
	 case 'm':	return 020; // (A0)
	 case '+':	return 030; // (A0)+
	 case '-':	return 040; // -(A0)
	 case 'r':	return 050; // d16(An)
	 case 'x':	return 060; // d8(An,IX)
	 case 'w':	return 071; // Abs.L
	 case 'p':	return 072; // (PC,IX)
	 case 'i':	return 074; // #imm
	}
	err("unknown eatype '{$eatype}'");
}

// EA 種別文字からニーモニックに。
function eatype2mnem($eatype, $n = 0)
{
	switch ($eatype) {
	 case 'd':	return "d{$n}";
	 case 'a':	return "a{$n}";
	 case 'm':	return "(a{$n})";
	 case '+':	return "(a{$n})+";
	 case '-':	return "-(a{$n})";
	 case 'r':	return "d16(a{$n})";
	 case 'x':	return "d8(a{$n},ix)";
	 case 'w':	return "abs";
	 case 'p':	return "(pc,ix)";
	 case 'i':	return "#imm";
	}
	return "";
}
?>

; 空リストは正しく0個転送という扱いになる。
; たぶん dynamic でも同様だろうけどもうテストしない。
test_nofpn:
	PRINT	msg_test_nofpn(pc)
	bsr	init_from
	; 実行
	lea.l	srcdata(pc),a0
	bsr	set_fline
	moveq.l	#0,d7
	lea.l	@f,a3
	.dc.l	$f218d000	; fmovem.x (a0)+,nofpn
@@:
	bsr	restore_fline
	; 例外は起きないはずなので D7 がゼロなら成功(次へ)
	tst.l	d7
	beq	@f
	PRINT	msg_fail_trap(pc)
	rts
@@:
	; An を照合する。(An)+ だけど変わらないはず。
	lea.l	srcdata(pc),a1
	cmp.l	a1,a0
	beq	@f
	pea.l	msg_fail_addr(pc)
	move.l	a1,-(sp)
	move.l	a0,-(sp)
	bsr	result
	lea.l	12(sp),sp
@@:
	lea.l	workarea(pc),a2
<?php
	// FPn を比較。
	for ($i = 0; $i < 8; $i++) {
		out("	; compare FP${i}");
		out("	pea.l	msg_fail_fp{$i}(pc)");
		out("	pea.l	(initdata+%d*12)(pc)", $i);
		out("	fmove.x	fp{$i},(a2)");
		out("	pea.l	(a2)");
		out("	bsr	check_ext");
		out("	lea.l	12(sp),sp");
	}
?>

	tst.l	d7
	bne	@f
	PRINT	msg_ok(pc)
@@:
	rts

; dynamic レジスタ指定の 0rrr_0000 の %0 のところに何か書かれてても無視。
test_illdyn:
	PRINT	msg_test_illdyn(pc)
	bsr	init_from
	; 実行
	lea.l	srcdata(pc),a0
	moveq.l	#$80,d6
	moveq.l	#0,d7
	lea.l	@f,a3
	.dc.l	$f210d86f	; fmovem.x (a0),d6
@@:
	bsr	restore_fline
	; 例外は起きないはずなので D7 がゼロなら成功(次へ)
	tst.l	d7
	beq	@f
	PRINT	msg_fail_trap(pc)
	rts
@@:
	; An を照合する。
	lea.l	srcdata(pc),a1
	cmp.l	a1,a0
	beq	@f
	pea.l	msg_fail_addr(pc)
	move.l	a1,-(sp)
	move.l	a0,-(sp)
	bsr	result
	lea.l	12(sp),sp
@@:
	lea.l	workarea(pc),a2
<?php
	// FPn を比較。
	for ($i = 0; $i < 8; $i++) {
		out("	; compare FP${i}");
		out("	pea.l	msg_fail_fp{$i}(pc)");
		if ($i == 0) {
			out("	pea.l	srcdata(pc)");
		} else {
			out("	pea.l	(initdata+%d*12)(pc)", $i);
		}
		out("	fmove.x	fp{$i},(a2)");
		out("	pea.l	(a2)");
		out("	bsr	check_ext");
		out("	lea.l	12(sp),sp");
	}
?>

	tst.l	d7
	bne	@f
	PRINT	msg_ok(pc)
@@:
	rts

; test_from 用の初期化。
; FP0..7 を初期値で埋めるのと、書き込み先バッファを用意。
; a0/a1 は破壊する。
init_from:
	lea.l	initdata(pc),a0
<?php
	for ($i = 0; $i < 8; $i++) {
		out("	fmove.x (a0)+,fp{$i}");
	}
?>

	; 書き込み先を分かりやすいデータで初期化。
	lea.l	initdata_from(pc),a0
	lea.l	workarea(pc),a1
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0),(a1)+
	subq.l	#8,a0
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0),(a1)+
	rts

; 結果表示
; スタックには、メッセージ、期待値、実際の値の順で積む。
result:
	link	a6,#0
	movem.l	d0/a0,-(sp)

	move.l	8+8(a6),-(sp)
	DOS	_PRINT
	addq.l	#4,sp

	move.l	8+4(a6),d0
	lea.l	buf(pc),a0
	bsr	hexstr_long
	PRINT	buf(pc)
	PRINT	msg_but(pc)

	move.l	8+0(a6),d0
	lea.l	buf(pc),a0
	bsr	hexstr_long
	PRINT	buf(pc)
	PRINT	msg_crlf(pc)

	addq.l	#1,d7	; errcnt
	movem.l	(sp)+,d0/a0
	unlk	a6
	rts

; 拡張精度の比較と結果表示。
; 一致したら何もせず帰る。一致しなければエラーメッセージを表示。
; スタックには、(エラー時の)メッセージ、期待値、実際の値の順で積む
check_ext:
	link	a6,#0
	movem.l	d0/a0-a2,-(sp)

	move.l	8+4(a6),a1
	move.l	8+0(a6),a2
	cmpm.l	(a1)+,(a2)+
	bne	@f
	cmpm.l	(a1)+,(a2)+
	bne	@f
	cmpm.l	(a1)+,(a2)+
	bne	@f
	; equal
	bra	check_ext_done

@@:	; not equal
	; テスト名を表示した行に続けてこれを表示すると折り返してしまうので、
	; これが1件目のエラーなら先に一つ改行する。
	tst.l	d7
	bne	@f
	PRINT	msg_crlf(pc)
@@:
	move.l	8+8(a6),-(sp)
	DOS	_PRINT
	addq.l	#4,sp

	lea.l	buf(pc),a0
	move.l	8+4(a6),a1
	move.l	(a1)+,d0
	bsr	hexstr_long
	move.b	#'_',(a0)+
	move.l	(a1)+,d0
	bsr	hexstr_long
	move.b	#'_',(a0)+
	move.l	(a1),d0
	bsr	hexstr_long
	PRINT	buf(pc)
	PRINT	msg_but(pc)

	lea.l	buf(pc),a0
	move.l	8+0(a6),a2
	move.l	(a2)+,d0
	bsr	hexstr_long
	move.b	#'_',(a0)+
	move.l	(a2)+,d0
	bsr	hexstr_long
	move.b	#'_',(a0)+
	move.l	(a2),d0
	bsr	hexstr_long
	PRINT	buf(pc)
	PRINT	msg_crlf(pc)

	addq.l	#1,d7	; errcnt
check_ext_done:
	movem.l	(sp)+,d0/a0-a2
	unlk	a6
	rts

; Fライン例外をテスト用のものに差し替える。
; 変更前のアドレスを a4 に格納する。
; a1 は破壊する。
set_fline:
	movem.l	d0-d1,-(sp)
	moveq.l	#$b,d1
	lea.l	fline_handler(pc),a1
	IOCS	_B_INTVCS
	movea.l	d0,a4
	movem.l	(sp)+,d0-d1
	rts

; Fライン例外を元に戻す。
; a1 は破壊する。
restore_fline:
	movem.l	d0-d1,-(sp)
	moveq.l	#$b,d1
	movea.l	a4,a1
	IOCS	_B_INTVCS
	movem.l	(sp)+,d0-d1
	rts

; Fライン例外ハンドラ
; a3 に戻りアドレスをセットしてあること
; d7 を 1 にして帰る
fline_handler:
	moveq.l	#1,d7
	move.l	a3,2(sp)
	rte

; FPn を埋める初期値
initdata:
	.dc.l	$00010000, $80888888, $88888888
	.dc.l	$00010000, $80111111, $11111111
	.dc.l	$00010000, $80222222, $22222222
	.dc.l	$00010000, $80333333, $33333333
	.dc.l	$00010000, $80444444, $44444444
	.dc.l	$00010000, $80555555, $55555555
	.dc.l	$00010000, $80666666, $66666666
	.dc.l	$00010000, $80777777, $77777777

; ターゲットの FPn に転送するデータ
srcdata:
	.dc.l	$3fff0000, $80aaaaaa, $aaaaaaaa
	.dc.l	$3fff0000, $80bbbbbb, $bbbbbbbb

; 書き込み先の初期化用データ
initdata_from:
	.dc.l	$90919293, $94959697, $98999a9b

msg_hard:	.dc.b	"hard mode",$d,$a,0
msg_easy:	.dc.b	"easy mode",$d,$a,0
msg_oktrap:	.dc.b	$9,"ok(trap)",$d,$a,0, 0,0
msg_fail_notrap:	.dc.b	$9,"FAIL: trap expected but not occured",$d,$a,0
msg_fail_trap:	.dc.b	$9,"FAIL: unexpected trap occured",$d,$a,0
msg_skip_dst:	.dc.b	$9,"SKIP(dstmem)",0

msg_ok:		.dc.b	$9,"ok",$d,$a,0
msg_fail_fp0:	.dc.b	$9,"FAIL: fp0 expects ",0
msg_fail_fp1:	.dc.b	$9,"FAIL: fp1 expects ",0
msg_fail_fp2:	.dc.b	$9,"FAIL: fp2 expects ",0
msg_fail_fp3:	.dc.b	$9,"FAIL: fp3 expects ",0
msg_fail_fp4:	.dc.b	$9,"FAIL: fp4 expects ",0
msg_fail_fp5:	.dc.b	$9,"FAIL: fp5 expects ",0
msg_fail_fp6:	.dc.b	$9,"FAIL: fp6 expects ",0
msg_fail_fp7:	.dc.b	$9,"FAIL: fp7 expects ",0
msg_fail_1st:	.dc.b	$9,"FAIL: 1st expects ",0
msg_fail_2nd:	.dc.b	$9,"FAIL: 2nd expects ",0
msg_fail_addr:	.dc.b	$9,"FAIL: an expects ",0
msg_but:	.dc.b	" but ",0
msg_crlf:	.dc.b	$d,$a,0

<?php
	foreach ($testlist as $test) {
		$name = sprintf("%02d:", $test["num"]);
		if ($test["is_pred"]) {
			$name .= "pred;";
		} else {
			$name .= "ctrl;";
		}
		$name .= "fmovem.x ";
		$m = eatype2mnem($test["eatype"]);
		$f = get_fplist($test);
		sort($f);
		if ($test["dynamic"]) {
			$r = "d6<fp{$f[0]}-fp{$f[1]}>";
		} else {
			$r = "fp{$f[0]}-fp{$f[1]}";
		}
		if ($test["mem_to_fp"]) {
			$name .= "{$m},{$r}";
		} else {
			$name .= "{$r},{$m}";
		}
		out("msg_test_{$test["num"]}:	.dc.b	\"{$name}\",0");
	}
?>
msg_test_nofpn:	.dc.b	"fmovem.x (a0)+,nofpn",0
msg_test_illdyn:.dc.b	"fmovem.x (a0),d6<FP0>_bit",0

	.data
	.even
workarea:	.ds.b	24
buf:		.ds.b	64

	.end	start

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.