|
|
1.1 root 1: ;
2: ; nono
3: ; Copyright (C) 2019 [email protected]
4: ;
5:
6: ; How to compile:
7: ; > has fmovem_n.has
8: ; > hlk fmovem_n.o si_util.o
9:
10: .xref hexstr_long
11: .include doscall.mac
12: .list
13: .cpu 68030
14:
15: PRINT .macro msg
16: pea.l msg(pc)
17: DOS _PRINT
18: addq.l #4,sp
19: .endm
20:
21: SET_FLINE_TRAP .macro
22: move.l (a5),a4
23: lea.l fline_handler(pc),a1
24: move.l a1,(a5)
25: .endm
26:
27: RESTORE_FLINE_TRAP .macro
28: move.l a4,(a5)
29: .endm
30:
31: .text
32: .even
33: <?php
34: // レジスタ割り当て
35: // d0-d1 work
36: // d6 ダイナミックモードでのレジスタ
37: // d7 1=検査対象命令でFライン例外がおきた
38: // その後は ok を表示するかどうかのカウント
39: // a0-a2 work
40: // a3 検査対象命令の次の位置 (Fライン例外から戻るのに使用)
41: // a4 元のFライン例外ハンドラ置き場
42: // a5 Fライン例外ベクタの位置 $002c
43: ?>
44: <?php
45: // "dam+-i" の各文字は実行できるところ。
46: // "." は例外がおきるところ。
47: //
48: // EA が -(An) なら FP-to-EA (fromFP)の方向のみ可能。
49: // EA が (An)+ なら EA-to-FP (toFP) の方向のみ可能。
50: $table = array(
51: // mode dam+-i
52: 0/* to FP, pred, static */ => "..m+..", // fmovem EA,fp1-fp2
53: 1/* to FP, pred, dynamic */ => "..m+..", // fmovem EA,d6
54: 2/* to FP, ctrl, static */ => "..m+..", // fmovem EA,fp1-fp2
55: 3/* to FP, ctrl, dynamic */ => "..m+..", // fmovem EA,d6
56: 4/* from FP, pred, static */ => "..m.-.", // fmovem fp1-fp2,EA
57: 5/* from FP, pred, dynamic */ => "..m.-.", // fmovem d6,EA
58: 6/* from FP, ctrl, static */ => "..m.-.", // fmovem fp1-fp2,EA
59: 7/* from FP, ctrl, dynamic */ => "..m.-.", // fmovem d6,EA
60: );
61: foreach ($table as $mode => $eastr) {
62: $ealist = preg_split("//", $eastr, -1, PREG_SPLIT_NO_EMPTY);
63: for ($id = 0; $id < 6; $id++) {
64: $ea = $ealist[$id];
65: if ($ea == ".") {
66: // 許されない組み合わせ
67: subr_fail($mode, $id);
68: } else {
69: if ($mode < 4) {
70: subr_to($mode, $id);
71: } else {
72: subr_from($mode, $id);
73: }
74: }
75: }
76: }
77: ?>
78: <?php
79: // 1行を出力する。引数は printf のように fmt... で指定可能。
80: // 改行はこちらで付加する。
81: function out()
82: {
83: $args = func_get_args();
84: $fmt = array_shift($args);
85: print vsprintf($fmt, $args);
86: print "\n";
87: }
88:
89: // mode 番号(下2bit)からラベル文字列に。
90: function mode2label($mode)
91: {
92: $rv .= (($mode & 2) == 0) ? "pred" : "ctrl";
93: $rv .= (($mode & 1) == 0) ? "_sta" : "_dyn";
94: return $rv;
95: }
96:
97: // $mode 番号からターゲットレジスタに。
98: // Ctrl/PostInc と PreDec とで転送する順番が違う。
99: // static と dynamic はなんとなく別のマスクを用意しておく。
100: function mode2fplist($mode)
101: {
102: $fplist = array(
103: 0/*pred, static */ => array(6, 5),
104: 1/*pred, dynamic */ => array(5, 4),
105: 2/*ctrl, static */ => array(1, 2),
106: 3/*ctrl, dynamic */ => array(2, 3),
107: );
108: return $fplist[$mode & 3];
109: }
110:
111: // EA 番号から命令ワードに。n はすべて0
112: function eanum2word($id)
113: {
114: switch ($id) {
115: case 0: // D0
116: return 0 << 3;
117: case 1: // A0
118: return 1 << 3;
119: case 2: // (A0)
120: return 2 << 3;
121: case 3: // (A0)+
122: return 3 << 3;
123: case 4: // -(A0)
124: return 4 << 3;
125: case 5: // #imm
126: return 0x3c;
127: }
128: }
129:
130: // EA 番号をラベル文字列に。
131: function eanum2label($id)
132: {
133: $idstr = array(
134: 0 => "dn",
135: 1 => "an",
136: 2 => "anin",
137: 3 => "anpi",
138: 4 => "anpd",
139: 5 => "imm",
140: );
141: return $idstr[$id];
142: }
143:
144: // EA 番号をニーモニックに。
145: function eanum2mnem($id, $n = 0)
146: {
147: switch ($id) {
148: case 0: return "d{$n}";
149: case 1: return "a{$n}";
150: case 2: return "(a{$n})";
151: case 3: return "(a{$n})+";
152: case 4: return "-(a{$n})";
153: }
154: }
155:
156: function addfunc($name)
157: {
158: global $funclist;
159:
160: $funclist[] = $name;
161: out("test_{$name}:");
162: out(" PRINT msg_{$name}");
163: }
164:
165: // 結果表示のサブルーチンコールを出力
166: function out_result($msg, $exp, $act)
167: {
168: out(" pea.l {$msg}(pc)");
169: out(" move.l {$exp},-(sp)");
170: out(" move.l {$act},-(sp)");
171: out(" bsr result");
172: out(" lea.l 12(sp),sp");
173: }
174:
175: // 許されない組み合わせのテスト。
176: // Fライン例外が起きることをチェックする。
177: function subr_fail($mode, $id)
178: {
179: $modestr = mode2label($mode);
180: $ealabel = eanum2label($id);
181:
182: $funcname = ($mode & 4) == 0
183: ? "fmovem_{$ealabel}_to_fpn_{$modestr}"
184: : "fmovem_fpn_to_{$ealabel}_{$modestr}";
185: addfunc($funcname);
186:
187: $w1 = 0xf200 | eanum2word($id);
188: $w2 = 0xc060 | ($mode << 11);
189:
190: out(" SET_FLINE_TRAP");
191: out(" moveq.l #0,d7");
192: out(" lea.l @f,a3");
193: // アセンブルできない可能性があるので命令はバイナリを出力。
194: out(" .dc.w $%04x, $%04x", $w1, $w2);
195: out("@@:");
196: out(" RESTORE_FLINE_TRAP");
197:
198: // 例外が起きるはずなので D7 が非ゼロなら成功(次へ)
199: out(" tst.l d7");
200: out(" bne @f");
201: out(" PRINT msg_fail_notrap");
202: out(" rts");
203: out("@@:");
204: out(" PRINT msg_oktrap");
205: out(" rts");
206: out("");
207: }
208:
209: // 実行できる組み合わせなら動作確認。EA to FPn
210: function subr_to($mode, $id)
211: {
212: $modestr = mode2label($mode);
213: $ealabel = eanum2label($id);
214:
215: $funcname = "fmovem_{$ealabel}_to_fpn_{$modestr}";
216: addfunc($funcname);
217:
218: $w1 = 0xf200 | eanum2word($id);
219: $w2 = 0xc060 | ($mode << 11);
220: $predec = ($mode & 2) == 0;
221: $dynamic = $mode & 1;
222:
223: // FPn を初期化
224: out(" lea.l initdata(pc),a0");
225: for ($i = 0; $i < 8; $i++) {
226: out(" fmove.x (a0)+,fp{$i}");
227: }
228:
229: // 読み込み元メモリを用意。EA to FPn 側に -(An) は存在しない。
230: out(" lea.l srcdata(pc),a0");
231: if ($dynamic) {
232: // ダイナミックモードでの転送マスクもあえて違うものにしておく
233: out(" moveq.l #$30,d6");
234: }
235:
236: // 検査
237: out(" SET_FLINE_TRAP");
238: out(" moveq.l #0,d7");
239: out(" lea.l @f,a3");
240: // アセンブルできない可能性があるので命令はバイナリを出力。
241: out(" .dc.w $%04x, $%04x", $w1, $w2);
242: out("@@:");
243: out(" RESTORE_FLINE_TRAP");
244:
245: // 例外は起きないはずなので D7 がゼロなら成功(次へ)
246: out(" tst.l d7");
247: out(" beq @f");
248: out(" PRINT msg_fail_trap");
249: out(" rts");
250: out("@@:");
251:
252: // An を調べる。An はソース
253: out(" lea.l srcdata+%d(pc),a1", ($id == 3)/*(An)+*/ ? 24 : 0);
254: out(" cmp.l a1,a0");
255: out(" beq @f");
256: out(" pea.l msg_fail_addr(pc)");
257: out(" move.l a1,-(sp)");
258: out(" move.l a0,-(sp)");
259: out(" bsr result");
260: out(" lea.l 12(sp),sp");
261: out("@@:");
262:
263: // FPn を取り出してきて比較。
264: // f1 なら srcdata[0] と、f2 なら srcdata[1] と。
265: // それ以外は initdata[n] と比較する。
266: list ($f1, $f2) = mode2fplist($mode);
267:
268: out(" lea.l workarea(pc),a2");
269: for ($i = 0; $i < 8; $i++) {
270: out(" ; compare FP${i}");
271: out(" pea.l msg_fail_fp{$i}(pc)");
272: // 比較先は都度違う
273: if ($i == $f1) {
274: out(" pea.l srcdata+0(pc)");
275: } else if ($i == $f2) {
276: out(" pea.l srcdata+12(pc)");
277: } else {
278: out(" pea.l (initdata+%d*12)(pc)", $i);
279: }
280: out(" fmove.x fp{$i},(a2)");
281: out(" pea.l (a2)");
282: out(" bsr check_ext");
283: out(" lea.l 12(sp),sp");
284: }
285: out(" tst.l d7");
286: out(" bne @f");
287: out(" PRINT msg_ok");
288: out("@@:");
289: out(" rts");
290: out("");
291: }
292:
293: // 実行できる組み合わせなら動作確認。FPn to EA
294: function subr_from($mode, $id)
295: {
296: $modestr = mode2label($mode);
297: $ealabel = eanum2label($id);
298:
299: $funcname = "fmovem_fpn_to_{$ealabel}_{$modestr}";
300: addfunc($funcname);
301:
302: $w1 = 0xf200 | eanum2word($id);
303: $w2 = 0xc060 | ($mode << 11);
304: $predec = ($mode & 2) == 0;
305: $dynamic = $mode & 1;
306:
307: // FPn を初期化
308: out(" lea.l initdata(pc),a0");
309: for ($i = 0; $i < 8; $i++) {
310: out(" fmove.x (a0)+,fp{$i}");
311: }
312: list ($f1, $f2) = mode2fplist($mode);
313:
314: // 書き込み先バッファも初期化
315: out(" moveq.l #0,d0");
316: out(" moveq.l #0,d1");
317: out(" moveq.l #0,d7");
318: out(" lea.l workarea(pc),a0");
319: out(" movem.l d0-d1/d7,(a0)");
320: out(" movem.l d0-d1/d7,12(a0)");
321: switch ($id) {
322: case 2: // (An)
323: break;
324: case 4: // -(An)
325: out(" lea.l workarea+24(pc),a0");
326: break;
327: }
328: if ($dynamic) {
329: // ダイナミックモードでの転送マスクもあえて違うものにしておく
330: out(" moveq.l #$30,d6");
331: }
332:
333: // 検査
334: out(" SET_FLINE_TRAP");
335: out(" lea.l @f,a3");
336: // アセンブルできない可能性があるので命令はバイナリを出力。
337: out(" .dc.w $%04x, $%04x", $w1, $w2);
338: out("@@:");
339: out(" RESTORE_FLINE_TRAP");
340:
341: // 例外は起きないはずなので D7 がゼロなら成功(次へ)
342: out(" tst.l d7");
343: out(" beq @f");
344: out(" PRINT msg_fail_trap");
345: out(" rts");
346: out("@@:");
347:
348: // An を調べる。An は dest。FPn to EA 側に (An)+ は存在しない
349: out(" lea.l workarea(pc),a1");
350: out(" cmp.l a1,a0");
351: out(" beq @f");
352: out(" pea.l msg_fail_addr(pc)");
353: out(" move.l a1,-(sp)");
354: out(" move.l a0,-(sp)");
355: out(" bsr result");
356: out(" lea.l 12(sp),sp");
357: out("@@:");
358:
359: // workarea に書き込まれているのを srcdata と比較
360: // workarea の若いアドレスから順に比較するが、
361: // FMOVEM fpnlist,-(An) の時 (predec の時ではなく id==4 の時) は
362: // 転送順にメモリを下っていくので、比較も下りながら行わないといけない。
363: $work = ($id == 4) ? 12 : 0;
364: out(" ; compare first one");
365: out(" pea.l msg_fail_1st(pc)");
366: out(" pea.l (initdata+%d*12)(pc)", $f1);
367: out(" pea.l %d(a1)", $work);
368: out(" bsr check_ext");
369: out(" lea.l 12(sp),sp");
370: if ($id == 4)
371: $work -= 12;
372: else
373: $work += 12;
374: out(" ; compare second one");
375: out(" pea.l msg_fail_2nd(pc)");
376: out(" pea.l (initdata+%d*12)(pc)", $f2);
377: out(" pea.l %d(a1)", $work);
378: out(" bsr check_ext");
379: out(" lea.l 12(sp),sp");
380: out("");
381: out(" tst.l d7");
382: out(" bne @f");
383: out(" PRINT msg_ok");
384: out("@@:");
385: out(" rts");
386: out("");
387: }
388: ?>
389: <?php
390: // 空リストは正しく0個転送という扱いになる。
391: // たぶん dynamic でも同様だろうけどもうテストしない。
392: addfunc("fmovem_nofpn"); ?>
393: lea.l initdata(pc),a0
394: <?php
395: for ($i = 0; $i < 8; $i++) {
396: out(" fmove.x (a0)+,fp{$i}");
397: }
398: ?>
399: SET_FLINE_TRAP
400: moveq.l #0,d7
401: lea.l workarea(pc),a0
402: move.l d7,(a0)
403: move.l d7,4(a0)
404: move.l d7,8(a0)
405: lea.l @f,a3
406: .dc.w $f210, $f000 ; fmovem nofpn,(a0)
407: @@:
408: RESTORE_FLINE_TRAP
409: tst.l d7
410: beq @f
411: PRINT msg_fail_trap
412: rts
413: @@:
414: pea.l msg_fail_1st(pc)
415: pea.l zerodata(pc)
416: pea.l (a0)
417: bsr check_ext
418: lea.l 12(sp),sp
419:
420: tst.l d7
421: bne @f
422: PRINT msg_ok
423: @@:
424: rts
425:
426: <?php
427: // dynamic のレジスタ指定 0rrr_0000 の %0 のところに何か書かれてても無視。
428: addfunc("fmovem_illegal_dyn"); ?>
429: lea.l initdata(pc),a0
430: <?php
431: for ($i = 0; $i < 8; $i++) {
432: out(" fmove.x (a0)+,fp{$i}");
433: }
434: ?>
435: SET_FLINE_TRAP
436: lea.l srcdata(pc),a0
437: moveq.l #$80,d6
438: moveq.l #0,d7
439: lea.l @f,a3
440: .dc.w $f210, $d86f ; fmovem (a0),d6
441: @@:
442: RESTORE_FLINE_TRAP
443:
444: tst.l d7
445: beq @f
446: PRINT msg_fail_trap
447: rts
448: @@:
449: lea.l workarea(pc),a0
450: fmovem.x fp0,(a0)
451: pea.l msg_fail_fp0(pc)
452: pea.l srcdata(pc)
453: pea.l (a0)
454: bsr check_ext
455: lea.l 12(sp),sp
456:
457: tst.l d7
458: bne @f
459: PRINT msg_ok
460: @@:
461: rts
462:
463: <?php
464: // lea.l $0000002c.l,a5 だと has.x に絶対アドレッシングだと
465: // 怒られてしまうため仕方なく
466: ?>
467: start:
468: clr.l -(sp)
469: DOS _SUPER
470: movem.l d6-d7/a2-a5,-(sp)
471: moveq.l #$2c,d0 ; alternate of "lea.l $2c,a5"
472: move.l d0,a5 ;
473: <?php
474: foreach ($funclist as $name) {
475: out(" bsr test_{$name}");
476: }
477: ?>
478: movem.l (sp)+,d6-d7/a2-a5
479: DOS _EXIT
480:
481: ; 結果表示
482: ; スタックには、メッセージ、期待値、実際の値の順で積む。
483: result:
484: link a6,#0
485: movem.l d0/a0,-(sp)
486:
487: move.l 8+8(a6),-(sp)
488: DOS _PRINT
489: addq.l #4,sp
490:
491: move.l 8+4(a6),d0
492: lea.l buf(pc),a0
493: bsr hexstr_long
494: PRINT buf
495: PRINT msg_but
496:
497: move.l 8+0(a6),d0
498: lea.l buf(pc),a0
499: bsr hexstr_long
500: PRINT buf
501: PRINT msg_crlf
502:
503: addq.l #1,d7 ; errcnt
504: movem.l (sp)+,d0/a0
505: unlk a6
506: rts
507:
508: ; 拡張精度の比較と結果表示。
509: ; 一致したら何もせず帰る。一致しなければエラーメッセージを表示。
510: ; スタックには、(エラー時の)メッセージ、期待値、実際の値の順で積む
511: check_ext:
512: link a6,#0
513: movem.l d0/a0-a2,-(sp)
514:
515: move.l 8+4(a6),a1
516: move.l 8+0(a6),a2
517: cmpm.l (a1)+,(a2)+
518: bne @f
519: cmpm.l (a1)+,(a2)+
520: bne @f
521: cmpm.l (a1)+,(a2)+
522: bne @f
523: ; equal
524: bra check_ext_done
525:
526: @@: ; not equal
527: move.l 8+8(a6),-(sp)
528: DOS _PRINT
529: addq.l #4,sp
530:
531: lea.l buf(pc),a0
532: move.l 8+4(a6),a1
533: move.l (a1)+,d0
534: bsr hexstr_long
535: move.b #'_',(a0)+
536: move.l (a1)+,d0
537: bsr hexstr_long
538: move.b #'_',(a0)+
539: move.l (a1),d0
540: bsr hexstr_long
541: PRINT buf
542: PRINT msg_but
543:
544: lea.l buf(pc),a0
545: move.l 8+0(a6),a2
546: move.l (a2)+,d0
547: bsr hexstr_long
548: move.b #'_',(a0)+
549: move.l (a2)+,d0
550: bsr hexstr_long
551: move.b #'_',(a0)+
552: move.l (a2),d0
553: bsr hexstr_long
554: PRINT buf
555: PRINT msg_crlf
556:
557: addq.l #1,d7 ; errcnt
558: check_ext_done:
559: movem.l (sp)+,d0/a0-a2
560: unlk a6
561: rts
562:
563: ; Fライン例外ハンドラ
564: ; a3 に戻りアドレスをセットしてあること
565: ; d7 を 1 にして帰る
566: fline_handler:
567: moveq.l #1,d7
568: move.l a3,2(sp)
569: rte
570:
571: ; FPn を埋める初期値
572: initdata:
573: .dc.l $0, $0, $8
574: .dc.l $0, $0, $1
575: .dc.l $0, $0, $2
576: .dc.l $0, $0, $3
577: .dc.l $0, $0, $4
578: .dc.l $0, $0, $5
579: .dc.l $0, $0, $6
580: .dc.l $0, $0, $7
581:
582: ; ターゲットの FPn に転送するデータ
583: srcdata:
584: .dc.l $3fff0000, $88112233, $44556677
585: .dc.l $dfff0000, $8899aabb, $ccddeeff
586:
587: zerodata:
588: .dc.l $0, $0, $0
589:
590: msg_oktrap: .dc.b $9,"ok(trap)",$d,$a,0, 0,0
591: msg_fail_notrap: .dc.b $9,"FAIL: trap expected but not occured",$d,$a,0
592: msg_fail_trap: .dc.b $9,"FAIL: unexpected trap occured",$d,$a,0
593:
594: msg_ok: .dc.b $9,"ok",$d,$a,0
595: msg_fail_fp0: .dc.b $9,"FAIL: fp0 expects ",0
596: msg_fail_fp1: .dc.b $9,"FAIL: fp1 expects ",0
597: msg_fail_fp2: .dc.b $9,"FAIL: fp2 expects ",0
598: msg_fail_fp3: .dc.b $9,"FAIL: fp3 expects ",0
599: msg_fail_fp4: .dc.b $9,"FAIL: fp4 expects ",0
600: msg_fail_fp5: .dc.b $9,"FAIL: fp5 expects ",0
601: msg_fail_fp6: .dc.b $9,"FAIL: fp6 expects ",0
602: msg_fail_fp7: .dc.b $9,"FAIL: fp7 expects ",0
603: msg_fail_1st: .dc.b $9,"FAIL: 1st expects ",0
604: msg_fail_2nd: .dc.b $9,"FAIL: 2nd expects ",0
605: msg_fail_addr: .dc.b $9,"FAIL: an expects ",0
606: msg_but: .dc.b " but ",0
607: msg_crlf: .dc.b $d,$a,0
608:
609: <?php
610: foreach ($funclist as $name) {
611: out("msg_{$name}: .dc.b \"{$name}\",0");
612: }
613: ?>
614:
615: .data
616: .even
617: workarea: .ds.b 24
618: buf: .dc.b 64
619:
620: .end start
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.