|
|
1.1 root 1: ;
2: ; nono
3: ; Copyright (C) 2019 [email protected]
4: ;
5:
6: ; How to compile:
7: ; > has fmovem.has
8: ; > hlk fmovem.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: // d7 1=検査対象命令でFライン例外がおきた
37: // その後は ok を表示するかどうかのカウント
38: // a0/a1 work
39: // a3 検査対象命令の次の位置 (Fライン例外から戻るのに使用)
40: // a4 元のFライン例外ハンドラ置き場
41: // a5 Fライン例外ベクタの位置 $002c
42: ?>
43: <?php
44: // regs がターゲットのFPcr。
45: // C..FPCR
46: // S..FPSR
47: // I..FPIAR の3ビット。
48: // 右辺がそのターゲットの時に使える EA。レジスタ相対は省略でいい?
49: // d..Dn
50: // a..An
51: // m..(An)
52: // +..(An)+
53: // -..-(An)
54: // i..#imm
55:
56: // FMOVEM EA,regs
57: $table = array(
58: //regs EA
59: "___" => "dam+-i",
60: "__I" => "dam+-i",
61: "_S_" => "d.m+-i",
62: "_SI" => "..m+-i",
63: "C__" => "d.m+-i",
64: "C_I" => "..m+-i",
65: "CS_" => "..m+-i",
66: "CSI" => "..m+-i",
67: );
68: foreach ($table as $regs => $eastr) {
69: $ealist = preg_split("//", $eastr, -1, PREG_SPLIT_NO_EMPTY);
70: for ($id = 0; $id < 6; $id++) {
71: $ea = $eastr[$id];
72: if (0) printf("regs='{$regs}' id=${id} ea={$ea}\n");
73:
74: if ($ea == ".") {
75: // 許されない組み合わせ。例外が出ることを確認
76: subr_fail("to", $regs, $id);
77: } else {
78: // アクセス可能な場合のテスト
79: subr_success_to($regs, $id);
80: }
81: }
82: }
83:
84: // FMOVEM regs,EA
85: foreach ($table as $regs => $eastr_src) {
86: // EA が dst になる時は #imm は無効
87: $eastr = preg_replace("/i/", ".", $eastr_src);
88:
89: $ealist = preg_split("//", $eastr, -1, PREG_SPLIT_NO_EMPTY);
90: for ($id = 0; $id < 6; $id++) {
91: $ea = $eastr[$id];
92: if (0) printf("regs='{$regs}' id=${id} ea={$ea}\n");
93:
94: if ($ea == ".") {
95: // 許されない組み合わせ。例外が出ることを確認
96: subr_fail("from", $regs, $id);
97: } else {
98: // アクセス可能な場合のテスト
99: subr_success_from($regs, $id);
100: }
101: }
102: }
103: ?>
104: <?php
105: // 1行を出力する。引数は printf のように fmt... で指定可能。
106: // 改行はこちらで付加する。
107: function out()
108: {
109: $args = func_get_args();
110: $fmt = array_shift($args);
111: print vsprintf($fmt, $args);
112: print "\n";
113: }
114:
115: // regs の省略記号を数値形式に
116: function reg2num($str)
117: {
118: $n = 0;
119: if (preg_match("/I/", $str))
120: $n += 1;
121: if (preg_match("/S/", $str))
122: $n += 2;
123: if (preg_match("/C/", $str))
124: $n += 4;
125: return $n;
126: }
127:
128: // regs 数値形式をニーモニックに
129: function regnum2mnemonic($regnum)
130: {
131: if ($regnum == 0)
132: return "nofpc";
133:
134: $list = array();
135: if ($regnum & 4)
136: $list[] = "fpcr";
137: if ($regnum & 2)
138: $list[] = "fpsr";
139: if ($regnum & 1)
140: $list[] = "fpiar";
141: return join($list, "/");
142: }
143:
144: // regs 数値形式から転送レジスタ数に
145: function regnum2count($regnum)
146: {
147: $counts = array(0, 1, 1, 2, 1, 2, 2, 3);
148: return $counts[$regnum];
149: }
150:
151: // regs 数値形式からマスクを返す。
152: // regs は1ビットだけ立っていること。
153: // %100=FPCR, %010=FPSR, %001=FPIAR
154: function regmask($regnum)
155: {
156: $masks = array(
157: /*0*/ 0,
158: /*1*/ 0xffffffff, // FPIAR
159: /*2*/ 0x0ffffff8, // FPSR
160: /*3*/ 0,
161: /*4*/ 0x0000fff0, // FPCR
162: );
163: return $masks[$regnum];
164: }
165:
166: // EA 番号から命令ワードに。n はすべて0
167: function eanum2word($id)
168: {
169: switch ($id) {
170: case 0: // D0
171: return 0 << 3;
172: case 1: // A0
173: return 1 << 3;
174: case 2: // (A0)
175: return 2 << 3;
176: case 3: // (A0)+
177: return 3 << 3;
178: case 4: // -(An)
179: return 4 << 3;
180: case 5: // #imm
181: return 0x3c;
182: }
183: }
184:
185: // EA 番号をラベル文字列に。
186: function eanum2label($id)
187: {
188: $idstr = array(
189: 0 => "dn",
190: 1 => "an",
191: 2 => "anin",
192: 3 => "anpi",
193: 4 => "anpd",
194: 5 => "imm",
195: );
196: return $idstr[$id];
197: }
198:
199: // EA 番号をニーモニックに。
200: function eanum2mnem($id, $n = 0)
201: {
202: switch ($id) {
203: case 0: return "d{$n}";
204: case 1: return "a{$n}";
205: case 2: return "(a{$n})";
206: case 3: return "(a{$n})+";
207: case 4: return "-(a{$n})";
208: }
209: }
210:
211: function addfunc($name)
212: {
213: global $funclist;
214:
215: $funclist[] = $name;
216: out("test_{$name}:");
217: out(" PRINT msg_{$name}");
218: }
219:
220: // 結果表示のサブルーチンコールを出力
221: function out_result($msg, $exp, $act)
222: {
223: out(" pea.l {$msg}(pc)");
224: out(" move.l {$exp},-(sp)");
225: out(" move.l {$act},-(sp)");
226: out(" bsr result");
227: out(" lea.l 12(sp),sp");
228: }
229:
230: // 許されない組み合わせのテスト。
231: // Fライン例外が起きることをチェックする。
232: function subr_fail($dir, $regs, $id)
233: {
234: $regnum = reg2num($regs);
235: $mnem = regnum2mnemonic($regnum);
236: $label = eanum2label($id);
237:
238: $funcname = ($dir == "to")
239: ? "fmovem_{$label}_to_{$regs}"
240: : "fmovem_{$regs}_to_{$label}";
241: addfunc($funcname);
242:
243: $w1 = 0xf200 | eanum2word($id);
244: $w2 = 0x8000 | ($regnum << 10);
245: if ($dir == "from")
246: $w2 |= 0x2000;
247:
248: out(" SET_FLINE_TRAP");
249: out(" moveq.l #0,d7");
250: out(" lea.l @f,a3");
251: // アセンブルできない可能性があるので命令はバイナリを出力。
252: out(" .dc.w $%04x, $%04x", $w1, $w2);
253: out("@@:");
254:
255: out(" RESTORE_FLINE_TRAP");
256: // 例外が起きるはずなので D7 が非ゼロなら成功(次へ)
257: out(" tst.l d7");
258: out(" bne @f");
259: out(" PRINT msg_fail_notrap");
260: out(" rts");
261: out("@@:");
262: out(" PRINT msg_oktrap");
263: out(" rts");
264: out("");
265: }
266:
267: // アクセス可能な場合のテスト。FMOVEM <ea>,<FPcr>
268: function subr_success_to($regs, $id)
269: {
270: $regnum = reg2num($regs);
271: $mnem = regnum2mnemonic($regnum);
272: $label = eanum2label($id);
273:
274: $funcname = "fmovem_{$label}_to_{$regs}";
275: addfunc($funcname);
276:
277: $w1 = 0xf200 | eanum2word($id);
278: $w2 = 0x8000 | ($regnum << 10);
279: $cpureg = eanum2mnem($id);
280: // count は指定されたレジスタ数 (0..3)
281: // txcount は転送するレジスタ数 (1..3)
282: $count = regnum2count($regnum);
283: $txcount = ($count == 0) ? 1 : $count;
284:
285: // FPcr を空にしておく
286: out(" fmove.l #0,fpcr");
287: out(" fmove.l #0,fpsr");
288: out(" fmove.l #0,fpiar");
289: // 準備
290: switch ($id) {
291: case 0: // Dn (singleのみ)
292: out(" move.l #\$55555555,d0");
293: break;
294: case 1: // An (singleのみ)
295: out(" move.l #\$55555555,a0");
296: break;
297: case 2: // (An)
298: case 3: // (An)+
299: case 4: // -(An)
300: out(" move.l #\$55555555,workarea");
301: if ($count >= 2)
302: out(" move.l #\$aaaaaaaa,workarea+4");
303: if ($count == 3)
304: out(" move.l #\$33333333,workarea+8");
305:
306: if ($id == 4) {
307: // 後ろ基準
308: // nofpc でも転送は発生する
309: out(" lea.l workarea+%d(pc),a0", $txcount * 4);
310: } else {
311: // 前から
312: out(" lea.l workarea(pc),a0");
313: }
314: break;
315: case 5: // #imm
316: $cpureg = "#\$55555555";
317: if ($count >= 2)
318: $cpureg .= ",#\$aaaaaaaa";
319: if ($count == 3)
320: $cpureg .= ",#\$33333333";
321: break;
322: }
323:
324: out(" SET_FLINE_TRAP");
325: out(" moveq.l #0,d7");
326: out(" lea.l @f,a3");
327: // 実行
328: if ($mnem == "nofpc") {
329: out(" .dc.w $%04x, $%04x", $w1, $w2);
330: // #imm,nofpc はアセンブル出来ないのでここで即値をおく
331: if ($id == 5/*imm*/ && $count == 0) {
332: out(" .dc.l \$55555555");
333: }
334: } else {
335: out(" fmovem.l {$cpureg},{$mnem}");
336: }
337: out("@@:");
338:
339: out(" RESTORE_FLINE_TRAP");
340: // 例外は起きないはずなので D7 はゼロなら成功(次へ)
341: out(" tst.l d7");
342: out(" beq @f");
343: out(" PRINT msg_fail_trap");
344: out(" rts");
345: out("@@:");
346:
347: // 検証
348: $expected = array(
349: 0x55555555,
350: 0xaaaaaaaa,
351: 0x33333333,
352: );
353: $i = 0;
354:
355: // An の変化量が正しいか。
356: // この後のレジスタの検証で A0 を使うのでその前に行う。
357: // (An) なら workarea から変化しない
358: // (An)+ なら workarea+count*4
359: // -(An) なら workarea に戻ってくる (最初にオフセットつけてるので)
360: switch ($id) {
361: case 2: // (An)
362: case 4: // -(An)
363: out(" lea.l workarea(pc),a1");
364: out(" cmpa.l a1,a0");
365: out(" beq @f");
366: out_result("msg_fail_addr", "a1", "a0");
367: out("@@:");
368: break;
369: case 3: // (An)+
370: out(" lea.l workarea+%d(pc),a1", $txcount * 4);
371: out(" cmpa.l a1,a0");
372: out(" beq @f");
373: out_result("msg_fail_addr", "a1", "a0");
374: out("@@:");
375: break;
376: }
377:
378: // FPCR
379: out(" fmove.l fpcr,d0");
380: if (($regnum & 4)) {
381: out(" move.l #$%08x,d1", $expected[$i] & regmask(4));
382: $i++;
383: } else {
384: out(" moveq.l #0,d1");
385: }
386: out(" cmp.l d1,d0");
387: out(" beq @f");
388: out_result("msg_fail_cr", "d1", "d0");
389: out("@@:");
390:
391: // FPSR
392: out(" fmove.l fpsr,d0");
393: if (($regnum & 2)) {
394: out(" move.l #$%08x,d1", $expected[$i] & regmask(2));
395: $i++;
396: } else {
397: out(" moveq.l #0,d1");
398: }
399: out(" cmp.l d1,d0");
400: out(" beq @f");
401: out_result("msg_fail_sr", "d1", "d0");
402: out("@@:");
403:
404: // FPIAR
405: out(" fmove.l fpiar,a0");
406: // fmovem *,nofpc は FPIAR が受け取ってしまうようだ
407: if (($regnum & 1) || $regnum == 0) {
408: out(" move.l #$%08x,a1", $expected[$i] & regmask(1));
409: $i++;
410: } else {
411: out(" move.l d7,a1 ; d7=0");
412: }
413: out(" cmpa.l a1,a0");
414: out(" beq @f");
415: out_result("msg_fail_ir", "a1", "a0");
416: out("@@:");
417:
418: out(" tst.l d7");
419: out(" bne @f");
420: out(" PRINT msg_ok");
421: out("@@:");
422: out(" rts");
423: out("");
424: }
425:
426: // アクセス可能な場合のテスト。FMOVEM <FPcr>,<ea>
427: function subr_success_from($regs, $id)
428: {
429: $regnum = reg2num($regs);
430: $mnem = regnum2mnemonic($regnum);
431: $label = eanum2label($id);
432:
433: $funcname = "fmovem_{$regs}_to_{$label}";
434: addfunc($funcname);
435:
436: $w1 = 0xf200 | eanum2word($id);
437: $w2 = 0xa000 | ($regnum << 10);
438: $cpureg = eanum2mnem($id);
439: // count は指定されたレジスタ数 (0..3)
440: // txcount は転送するレジスタ数 (1..3)
441: $count = regnum2count($regnum);
442: $txcount = ($count == 0) ? 1 : $count;
443:
444: // FPcr に初期値をセット
445: // nofpc の時は FPIAR
446: $expected = array(
447: 0x55555555,
448: 0xaaaaaaaa,
449: 0x33333333,
450: );
451: $i = 0;
452: out(" fmove.l #$%08x,fpcr", ($regnum & 4) ? $expected[$i++] : 0);
453: out(" fmove.l #$%08x,fpsr", ($regnum & 2) ? $expected[$i++] : 0);
454: out(" fmove.l #$%08x,fpiar",
455: (($regnum & 1) || $count == 0) ? $expected[$i++] : 0);
456:
457: // 準備
458: switch ($id) {
459: case 2: // (An)
460: case 3: // (An)+
461: out(" lea.l workarea(pc),a0");
462: break;
463: case 4: // -(An)
464: // nofpc でも転送は発生する
465: out(" lea.l workarea+%d(pc),a0", $txcount * 4);
466: break;
467: case 5: // #imm は dst にならない
468: break;
469: }
470:
471: out(" SET_FLINE_TRAP");
472: out(" moveq.l #0,d7");
473: out(" lea.l @f,a3");
474: // 実行
475: if ($mnem == "nofpc")
476: out(" .dc.w $%04x, $%04x", $w1, $w2);
477: else
478: out(" fmovem.l {$mnem},{$cpureg}");
479: out("@@:");
480:
481: out(" RESTORE_FLINE_TRAP");
482: // 例外は起きないはずなので D7 はゼロなら成功(次へ)
483: out(" tst.l d7");
484: out(" beq @f");
485: out(" PRINT msg_fail_trap");
486: out(" rts");
487: out("@@:");
488:
489: // 検証
490:
491: // An の変化量が正しいか
492: // (An) なら workarea から変化しない
493: // (An)+ なら workarea+count*4
494: // -(An) なら workarea に戻ってくる (最初にオフセットつけてるので)
495: switch ($id) {
496: case 2: // (An)
497: case 4: // -(An)
498: out(" lea.l workarea(pc),a1");
499: out(" cmpa.l a1,a0");
500: out(" beq @f");
501: out_result("msg_fail_addr", "a1", "a0");
502: out("@@:");
503: break;
504: case 3: // (An)+
505: out(" lea.l workarea+%d(pc),a1", $txcount * 4);
506: out(" cmpa.l a1,a0");
507: out(" beq @f");
508: out_result("msg_fail_addr", "a1", "a0");
509: out("@@:");
510: break;
511: }
512:
513: $i = 0;
514: switch ($id) {
515: case 0: // Dn
516: for ($r = 4; $r >= 1; $r >>= 1) {
517: // 各 fpn の該当する時か、nofpc なら FPIAR
518: if (($regnum & $r) || ($r == 1 && $count == 0)) {
519: out(" move.l #$%08x,d1", $expected[$i] & regmask($r));
520: $i++;
521: out(" cmp.l d1,d0");
522: out(" beq @f");
523: out_result("msg_fail", "d1", "d0");
524: out("@@:");
525: }
526: }
527: break;
528: case 1: // An
529: for ($r = 4; $r >= 1; $r >>= 1) {
530: // 各 fpn の該当する時か、nofpc なら FPIAR
531: if (($regnum & $r) || ($r == 1 && $count == 0)) {
532: out(" movea.l #$%08x,a1", $expected[$i] & regmask($r));
533: $i++;
534: out(" cmp.l a1,a0");
535: out(" beq @f");
536: out_result("msg_fail", "a1", "a0");
537: out("@@:");
538: }
539: }
540: break;
541: case 2: // (An)
542: case 3: // (An)+
543: case 4: // -(An)
544: for ($r = 4; $r >= 1; $r >>= 1) {
545: // 各 fpn の該当する時か、nofpc なら FPIAR
546: if (($regnum & $r) || ($r == 1 && $count == 0)) {
547: out(" move.l #$%08x,d1", $expected[$i] & regmask($r));
548: out(" cmp.l workarea+%d,d1", $i * 4);
549: $i++;
550: out(" beq @f");
551: out_result("msg_fail", "d1", sprintf("workarea+%d", $i * 4));
552: out("@@:");
553: }
554: }
555: break;
556: }
557:
558: out(" tst.l d7");
559: out(" bne @f");
560: out(" PRINT msg_ok");
561: out("@@:");
562: out(" rts");
563: out("");
564: }
565: ?>
566: <?php
567: // lea.l $0000002c.l,a5 だと has.x に絶対アドレッシングだと
568: // 怒られてしまうため仕方なく
569: ?>
570: start:
571: clr.l -(sp)
572: DOS _SUPER
573: movem.l d7/a3-a5,-(sp)
574: moveq.l #$2c,d0 ; alternate of "lea.l $2c,a5"
575: move.l d0,a5 ;
576: <?php
577: foreach ($funclist as $name) {
578: out(" bsr test_{$name}");
579: }
580: ?>
581: movem.l (sp)+,d7/a3-a5
582: DOS _EXIT
583:
584: ; 結果表示
585: ; スタックには、メッセージ、期待値、実際の値の順で積む。
586: result:
587: link a6,#0
588: movem.l d0/a0,-(sp)
589:
590: move.l 8+8(a6),-(sp)
591: DOS _PRINT
592: addq.l #4,sp
593:
594: move.l 8+4(a6),d0
595: lea.l buf(pc),a0
596: bsr hexstr_long
597: PRINT buf
598: PRINT msg_but
599:
600: move.l 8+0(a6),a0
601: lea.l buf(pc),a0
602: bsr hexstr_long
603: PRINT buf
604: PRINT msg_crlf
605:
606: addq.l #1,d7 ; errcnt
607: movem.l (sp)+,d0/a0
608: unlk a6
609: rts
610:
611: ; Fライン例外ハンドラ
612: ; a3 に戻りアドレスをセットしてあること
613: ; d7 を 1 にして帰る
614: fline_handler:
615: moveq.l #1,d7
616: move.l a3,2(sp)
617: rte
618:
619: msg_oktrap: .dc.b $9,"ok(trap)",$d,$a,0, 0,0
620: msg_fail_notrap: .dc.b $9,"FAIL: trap expected but not occured",$d,$a,0
621: msg_fail_trap: .dc.b $9,"FAIL: unexpected trap occured",$d,$a,0
622:
623: msg_ok: .dc.b $9,"ok",$d,$a,0
624: msg_fail: .dc.b $9,"fail",$d,$a,0
625: msg_fail_cr: .dc.b $9,"FAIL: fpcr expects ",0
626: msg_fail_sr: .dc.b $9,"FAIL: fpsr expects ",0
627: msg_fail_ir: .dc.b $9,"FAIL: fpiar expects ",0
628: msg_fail_addr: .dc.b $9,"FAIL: an expects ",0
629: msg_but: .dc.b " but ",0
630: msg_crlf: .dc.b $d,$a,0
631:
632:
633: <?php
634: foreach ($funclist as $name) {
635: out("msg_{$name}: .dc.b \"{$name}\",0");
636: }
637: ?>
638:
639: .data
640: .even
641: workarea: .ds.b 24
642: buf: .dc.b 20
643:
644: .end start
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.