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