Annotation of nono/exp/fmoveto.php, revision 1.1.1.1

1.1       root        1: ;
                      2: ; nono
                      3: ; Copyright (C) 2025 nono project
                      4: ;
                      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.
                     25: 
                     26: ; FMOVE.? FPn,<ea> で例外の起きる <ea> を確認する。
                     27: ; あと不当命令のところで命令を処理してしまわないことを確認する。
                     28: 
                     29: ; How to compile
                     30: ;  > has fmoveto.has
                     31: ;  > hlk fmoveto.o
                     32: 
                     33:        .include doscall.mac
                     34:        .include iocscall.mac
                     35:        .list
                     36:        .cpu    68030
                     37: 
                     38: PRINT  .macro  msg
                     39:        pea.l   msg
                     40:        DOS     _PRINT
                     41:        addq.l  #4,sp
                     42:        .endm
                     43: 
                     44:        .text
                     45:        .even
                     46: 
                     47: <?php
                     48:        // レジスタ割り当て
                     49:        // d0-d3        work
                     50:        // d4   d8(An,IX) の IX で使う。形式だけでいいので値は 0。
                     51:        // d7   1=検査対象命令でFライン例外がおきた
                     52:        //              2=FPSR の condition byte が変化した
                     53:        // a0-a1        work
                     54:        // a2   結果(1テストにつき、期待値.b と結果.b)バッファ
                     55:        // a3   検査対象命令の次の位置 (Fライン例外から戻るのに使用)
                     56:        // a4   元のFライン例外ハンドラ置き場
                     57: ?>
                     58: <?php
                     59:        // サイズ名から dstfmt への変換。
                     60:        $sizelist = array(
                     61:                "B" => 6,
                     62:                "W" => 4,
                     63:                "L" => 0,
                     64:                "S" => 1,
                     65:                "D" => 5,
                     66:                "X" => 2,
                     67:                "P" => 3,
                     68:        );
                     69:        // EA 種別と、テストに使うモード(6ビット)、表示名。        
                     70:        $ealist = array(
                     71:                "d"  => array("mode" => 006, "name" => "Dn"),   // d6 を使う
                     72:                "a"  => array("mode" => 010, "name" => "An"),
                     73:                "m"  => array("mode" => 020, "name" => "(An)"),
                     74:                "mi" => array("mode" => 030, "name" => "(An)+"),
                     75:                "md" => array("mode" => 040, "name" => "-(An)"),
                     76:                "r"  => array("mode" => 050, "name" => "d16(An)"),
                     77:                "x"  => array("mode" => 060, "name" => "d8(An,IX)"),
                     78:                // ちょっとテストが難しいので保留。
                     79:                //"w"  => array("mode" => 071, "name" => "Abs",
                     80:                "p"  => array("mode" => 072, "name" => "(PC)"),
                     81:                "i"  => array("mode" => 074, "name" => "#imm"),
                     82:                "o"  => array("mode" => 075, "name" => "075"),
                     83:        );
                     84: 
                     85:        // "exp_int", "exp_mem" はそれぞれ .BWLS と .DXP の場合の期待値。
                     86:        // 下位 4 ビットが FPSR の Condition Byte で、
                     87:        // 4ビット目はトラップの有無、%0 なら通過、%1 ならトラップを表す。
                     88:        // Condition Byte には通常絶対成立しない $b を入れておいて
                     89:        // これが変化するかしないかを調べる。
                     90:        $testlist = array();
                     91: 
                     92:        // FMOVE.? FPn,<ea>
                     93:        $table = array(
                     94:                //                        +----- .B/W/L/S の期待値 (0が通過、1がトラップ)
                     95:                //                        |      +-- .D/X/P   の期待値 (〃)
                     96:                "d"  => array(0, 1),
                     97:                "a"  => array(1, 1),
                     98:                "m"  => array(0, 0),
                     99:                "mi" => array(0, 0),
                    100:                "md" => array(0, 0),
                    101:                "r"  => array(0, 0),
                    102:                "x"  => array(0, 0),
                    103:                "w"  => array(0, 0),
                    104:                "p"  => array(1, 1),
                    105:                "i"  => array(1, 1),
                    106:                "o"  => array(1, 1),
                    107:        );
                    108:        foreach ($table as $eatype => $exparray) {
                    109:                list ($exp_int, $exp_mem) = $exparray;
                    110:                if (!isset($ealist[$eatype])) continue;
                    111:                $eamode = $ealist[$eatype]['mode'];
                    112:                $ei = ($exp_int == 1 ? 0x1b : 0x0b);
                    113:                $em = ($exp_mem == 1 ? 0x1b : 0x0b);
                    114:                $test = array(
                    115:                        "opname"        => "fmove",
                    116:                        "is_store"      => true,
                    117:                        "eatype"        => $eatype,
                    118:                        "eamode"        => $eamode,
                    119:                        "inst"          => 0xf2006000 | ($eamode << 16),
                    120:                        "has_dstfmt"=> true,
                    121:                        "expected"      => array(
                    122:                                "B" => $ei,
                    123:                                "W" => $ei,
                    124:                                "L" => $ei,
                    125:                                "S" => $ei,
                    126:                                "D" => $em,
                    127:                                "X" => $em,
                    128:                                "P" => $em,
                    129:                        ),
                    130:                );
                    131:                $testlist[] = $test;
                    132:        }
                    133: 
                    134:        // Fgen.? <ea>,FPn (代表として FMOVE を使う)
                    135:        $table = array(
                    136:                //                        +----- .B/W/L/S の期待値 (0が通過、1がトラップ)
                    137:                //                        |      +-- .D/X/P   の期待値 (〃)
                    138:                "d"  => array(0, 1),
                    139:                "a"  => array(1, 1),
                    140:                "m"  => array(0, 0),
                    141:                "mi" => array(0, 0),
                    142:                "md" => array(0, 0),
                    143:                "r"  => array(0, 0),
                    144:                "x"  => array(0, 0),
                    145:                "w"  => array(0, 0),
                    146:                "p"  => array(0, 0),
                    147:                "i"  => array(0, 0),
                    148:                "o"  => array(1, 1),
                    149:        );
                    150:        foreach ($table as $eatype => $exparray) {
                    151:                list ($exp_int, $exp_mem) = $exparray;
                    152:                if (!isset($ealist[$eatype])) continue;
                    153:                $eamode = $ealist[$eatype]['mode'];
                    154:                $ei = ($exp_int == 1 ? 0x1b : 0x04);
                    155:                $em = ($exp_mem == 1 ? 0x1b : 0x04);
                    156:                $test = array(
                    157:                        "opname"        => "fgen",
                    158:                        "is_store"      => false,
                    159:                        "eatype"        => $eatype,
                    160:                        "eamode"        => $eamode,
                    161:                        "inst"          => 0xf2004000 | ($eamode << 16),
                    162:                        "has_dstfmt"=> true,
                    163:                        "expected"      => array(
                    164:                                "B" => $ei,
                    165:                                "W" => $ei,
                    166:                                "L" => $ei,
                    167:                                "S" => $ei,
                    168:                                "D" => $em,
                    169:                                "X" => $em,
                    170:                                "P" => $em,
                    171:                        ),
                    172:                );
                    173:                $testlist[] = $test;
                    174:        }
                    175:        // FSCALE.? <ea>,FPn は NetBSD FPE が Fgen とは別パスで実装してあるので
                    176:        // 同じ結果になることを確認する。
                    177:        foreach ($table as $eatype => $exparray) {
                    178:                list ($exp_int, $exp_mem) = $exparray;
                    179:                if (!isset($ealist[$eatype])) continue;
                    180:                $eamode = $ealist[$eatype]['mode'];
                    181:                $ei = ($exp_int == 1 ? 0x1b : 0x04);
                    182:                $em = ($exp_mem == 1 ? 0x1b : 0x04);
                    183:                $test = array(
                    184:                        "opname"        => "fscale",
                    185:                        "is_store"      => false,
                    186:                        "eatype"        => $eatype,
                    187:                        "eamode"        => $eamode,
                    188:                        "inst"          => 0xf2004026 | ($eamode << 16),
                    189:                        "has_dstfmt"=> true,
                    190:                        "expected"      => array(
                    191:                                "B" => $ei,
                    192:                                "W" => $ei,
                    193:                                "L" => $ei,
                    194:                                "S" => $ei,
                    195:                                "D" => $em,
                    196:                                "X" => $em,
                    197:                                "P" => $em,
                    198:                        ),
                    199:                );
                    200:                $testlist[] = $test;
                    201:        }
                    202: 
                    203:        // FScc.B <ea>。サイズは .B のみ。
                    204:        // An と (PC), #imm に相当するところには FDBcc、FTRAPcc がいるので
                    205:        // 検査しない(出来ない)。
                    206:        $table = array(
                    207:                //              .B の期待値 (0が通過、1がトラップ)
                    208:                "d"  => 0,      
                    209:                "m"  => 0,
                    210:                "mi" => 0,
                    211:                "md" => 0,
                    212:                "r"  => 0,
                    213:                "x"  => 0,
                    214:                "w"  => 0,
                    215:                "o"  => 1,
                    216:        );
                    217:        foreach ($table as $eatype => $exp_int) {
                    218:                if (!isset($ealist[$eatype])) continue;
                    219:                $eamode = $ealist[$eatype]['mode'];
                    220:                $ei = ($exp_int == 1 ? 0x1b : 0x0b);    // フラグは変化しない
                    221:                $test = array(
                    222:                        "opname"        => "fscc",
                    223:                        "is_store"      => true,
                    224:                        "eatype"        => $eatype,
                    225:                        "eamode"        => $eamode,
                    226:                        "inst"          => 0xf2400000 | ($eamode << 16),        // FSF
                    227:                        "expected"      => array(
                    228:                                "B" => $ei,
                    229:                        ),
                    230:                );
                    231:                $testlist[] = $test;
                    232:        }
                    233: 
                    234:        // FMOVEM.X FPn,<ea>。
                    235:        // FMOVEM 自体のテストではないのでレジスタリストは FPn 1つのみ。
                    236:        $table = array(
                    237:                //              期待値 (0が通過、1がトラップ)
                    238:                "d"  => 1,
                    239:                "a"  => 1,
                    240:                "m"  => 0,
                    241:                "mi" => 1,
                    242:                "md" => 0,
                    243:                "r"  => 0,
                    244:                "x"  => 0,
                    245:                "w"  => 0,
                    246:                "p"  => 1,
                    247:                "i"  => 1,
                    248:                "o"  => 1,
                    249:        );
                    250:        foreach ($table as $eatype => $exp_int) {
                    251:                if (!isset($ealist[$eatype])) continue;
                    252:                $eamode = $ealist[$eatype]['mode'];
                    253:                $ei = ($exp_int == 1 ? 0x1b : 0x0b);    // フラグは変化しない
                    254:                $cmode = ($eatype == "md") ? 0 : 0x1000;
                    255:                $test = array(
                    256:                        "opname"        => "fmovem_rm",
                    257:                        "is_store"      => true,
                    258:                        "eatype"        => $eatype,
                    259:                        "eamode"        => $eamode,
                    260:                        "inst"          => 0xf200e001 | ($eamode << 16) | $cmode,
                    261:                        "expected"      => array(
                    262:                                "X" => $ei,
                    263:                        ),
                    264:                );
                    265:                $testlist[] = $test;
                    266:        }
                    267: 
                    268:        // FMOVEM.X <ea>,FPn。
                    269:        // FMOVEM 自体のテストではないのでレジスタリストは FPn 1つのみ。
                    270:        $table = array(
                    271:                //              期待値 (0が通過、1がトラップ)
                    272:                "d"  => 1,
                    273:                "a"  => 1,
                    274:                "m"  => 0,
                    275:                "mi" => 0,
                    276:                "md" => 1,
                    277:                "r"  => 0,
                    278:                "x"  => 0,
                    279:                "w"  => 0,
                    280:                "p"  => 0,
                    281:                "i"  => 1,
                    282:                "o"  => 1,
                    283:        );
                    284:        foreach ($table as $eatype => $exp_int) {
                    285:                if (!isset($ealist[$eatype])) continue;
                    286:                $eamode = $ealist[$eatype]['mode'];
                    287:                $ei = ($exp_int == 1 ? 0x1b : 0x0b);    // フラグは変化しない
                    288:                $cmode = ($eatype == "md") ? 0 : 0x1000;
                    289:                $test = array(
                    290:                        "opname"        => "fmovem_mr",
                    291:                        "is_store"      => false,
                    292:                        "eatype"        => $eatype,
                    293:                        "eamode"        => $eamode,
                    294:                        "inst"          => 0xf200c001 | ($eamode << 16) | $cmode,
                    295:                        "expected"      => array(
                    296:                                "X" => $ei,
                    297:                        ),
                    298:                );
                    299:                $testlist[] = $test;
                    300:        }
                    301: 
                    302:        $crlist = array(
                    303:                "c" => array("mode" => (4 << 10), "name" => "FPCR"),
                    304:                "s" => array("mode" => (2 << 10), "name" => "FPSR"),
                    305:                "i" => array("mode" => (1 << 10), "name" => "FPIAR"),
                    306:                "m" => array("mode" => (3 << 10), "name" => "FPSR/FPIAR"),
                    307:        );
                    308: 
                    309:        // FMOVEM.L FPcr,<ea>。
                    310:        // FPIAR かどうか、リストが複数かどうかで変わる。
                    311:        // 横はサイズではなくレジスタリストをとる。
                    312:        $table = array(
                    313:                //                      FPCR FPSR FPIAR multi
                    314:                "d"  => array(  0,      0,      0,      1),     // 単一レジスタのみ可能
                    315:                "a"  => array(  1,      1,      0,      1),     // FPIAR のみ可能
                    316:                "m"  => array(  0,      0,      0,      0),
                    317:                "mi" => array(  0,      0,      0,      0),
                    318:                "md" => array(  0,      0,      0,      0),
                    319:                "r"  => array(  0,      0,      0,      0),
                    320:                "x"  => array(  0,      0,      0,      0),
                    321:                "w"  => array(  0,      0,      0,      0),
                    322:                "p"  => array(  1,      1,      1,      1),
                    323:                "i"  => array(  1,      1,      1,      1),
                    324:                "o"  => array(  1,      1,      1,      1),
                    325:        );
                    326:        foreach ($table as $eatype => $exparray) {
                    327:                list ($exp_cr, $exp_sr, $exp_ir, $exp_m) = $exparray;
                    328:                if (!isset($ealist[$eatype])) continue;
                    329:                $eamode = $ealist[$eatype]['mode'];
                    330:                // フラグは変化しない
                    331:                $ec = ($exp_cr == 1 ? 0x1b : 0x0b);
                    332:                $es = ($exp_sr == 1 ? 0x1b : 0x0b);
                    333:                $ei = ($exp_ir == 1 ? 0x1b : 0x0b);
                    334:                $em = ($exp_m  == 1 ? 0x1b : 0x0b);
                    335:                $test = array(
                    336:                        "opname"        => "fmovem_cm",
                    337:                        "is_store"      => true,
                    338:                        "eatype"        => $eatype,
                    339:                        "eamode"        => $eamode,
                    340:                        "inst"          => 0xf200a000 | ($eamode << 16),
                    341:                        "fmovemc"       => true,
                    342:                        "expected"      => array(
                    343:                                "c" => $ec,
                    344:                                "s" => $es,
                    345:                                "i" => $ei,
                    346:                                "m" => $em,
                    347:                        ),
                    348:                );
                    349:                $testlist[] = $test;
                    350:        }
                    351: 
                    352:        // FMOVEM.L <ea>,FPcr。
                    353:        // FPIAR かどうか、リストが複数かどうかで変わる。
                    354:        $table = array(
                    355:                //                      FPCR FPSR FPIAR multi
                    356:                "d"  => array(  0,      0,      0,      1),     // 単一レジスタのみ可能
                    357:                "a"  => array(  1,      1,      0,      1),     // FPIAR のみ可能
                    358:                "m"  => array(  0,      0,      0,      0),
                    359:                "mi" => array(  0,      0,      0,      0),
                    360:                "md" => array(  0,      0,      0,      0),
                    361:                "r"  => array(  0,      0,      0,      0),
                    362:                "x"  => array(  0,      0,      0,      0),
                    363:                "w"  => array(  0,      0,      0,      0),
                    364:                "p"  => array(  0,      0,      0,      0),
                    365:                "i"  => array(  0,      0,      0,      0),
                    366:                "o"  => array(  1,      1,      1,      1),
                    367:        );
                    368:        foreach ($table as $eatype => $exparray) {
                    369:                list ($exp_cr, $exp_sr, $exp_ir, $exp_m) = $exparray;
                    370:                if (!isset($ealist[$eatype])) continue;
                    371:                $eamode = $ealist[$eatype]['mode'];
                    372:                // フラグは FPSR への代入だけ変化することになる
                    373:                $ec = ($exp_cr == 1 ? 0x1b : 0x0b);
                    374:                $es = ($exp_sr == 1 ? 0x1b : 0x00);     // FPSR
                    375:                $ei = ($exp_ir == 1 ? 0x1b : 0x0b);
                    376:                $em = ($exp_m  == 1 ? 0x1b : 0x00);     // FPSR/FPIAR
                    377:                $test = array(
                    378:                        "opname"        => "fmovem_mc",
                    379:                        "is_store"      => false,
                    380:                        "eatype"        => $eatype,
                    381:                        "eamode"        => $eamode,
                    382:                        "inst"          => 0xf2008000 | ($eamode << 16),
                    383:                        "fmovemc"       => true,
                    384:                        "expected"      => array(
                    385:                                "c" => $ec,
                    386:                                "s" => $es,
                    387:                                "i" => $ei,
                    388:                                "m" => $em,
                    389:                        ),
                    390:                );
                    391:                $testlist[] = $test;
                    392:        }
                    393: 
                    394: 
                    395:        // コマンド名を抽出する。
                    396:        $cmdlist = array();
                    397:        foreach ($testlist as $test) {
                    398:                $opname = $test['opname'];
                    399:                if (!isset($cmdlist[$opname])) {
                    400:                        $cmdlist[$opname] = $opname;
                    401:                }
                    402:        }
                    403: ?>
                    404: 
                    405: start:
                    406:        bsr     parse_arg
                    407:        clr.l   -(sp)
                    408:        DOS     _SUPER
                    409: 
                    410:        fmovem.x        fp0-fp7,-(sp)
                    411:        fmovem.l        fpcr/fpsr/fpiar,-(sp)
                    412: 
                    413:        moveq.l #0,d0
                    414:        fmove.s d0,fp0          ; FP0 = +0.0
                    415:        fmove.l d0,fpcr         ; Init round prec, round mode.
                    416:        move.l  d0,failed       ; Init failed count.
                    417: 
                    418: <?php
                    419:        $opname = "";
                    420:        foreach ($testlist as $test) {
                    421:                if ($opname != $test['opname']) {
                    422:                        $opname = $test['opname'];
                    423:                        out("@@:");
                    424:                        out("tst.b      is_{$opname}(pc)");
                    425:                        out("beq        @f");
                    426:                        out("PRINT      msg_head_{$opname}(pc)");
                    427:                        $n = count($test['expected']);
                    428:                        if ($n == 4 || $n == 7) {
                    429:                                out("PRINT      msg_head_guide{$n}(pc)");
                    430:                        }
                    431:                }
                    432:                out("   bsr     test_{$opname}_{$test['eatype']}");
                    433:        }
                    434: ?>
                    435: @@:
                    436:        tst.l   failed(pc)
                    437:        beq     @f
                    438:        PRINT   msg_failed(pc)
                    439: @@:
                    440:        fmovem.l        (sp)+,fpcr/fpsr/fpiar
                    441:        fmovem.x        (sp)+,fp0-fp7
                    442:        DOS     _EXIT
                    443: 
                    444: <?php
                    445:        // ここからテスト本体を展開。
                    446:        // テスト中では Dn の場合の格納先は d6、アドレスは A0。
                    447:        foreach ($testlist as $test) {
                    448:                $eatype = $test['eatype'];
                    449:                $eaname = $ealist[$eatype]['name'];
                    450:                $expected_array = $test['expected'];
                    451:                out("test_{$test['opname']}_{$eatype}:");
                    452:                out("   lea.l   result(pc),a2");
                    453:                foreach ($expected_array as $sizename => $expected) {
                    454:                        $inst = $test['inst'];
                    455:                        if (($test['has_dstfmt'] ?? false) != false) {
                    456:                                $dstfmt = $sizelist[$sizename];
                    457:                                $inst |= ($dstfmt << 10);
                    458:                        }
                    459:                        if (($test['fmovemc'] ?? false) != false) {
                    460:                                // FMOVEM FPcr の時だけループ変数は $sizename ではなく $crtype。
                    461:                                $crtype = $sizename;
                    462:                                $inst |= $crlist[$crtype]['mode'];
                    463:                                $crname = $crlist[$crtype]['name'];
                    464:                        }
                    465:                        switch ($test['opname']) {
                    466:                         case "fmove":
                    467:                                out("   ; FMOVE.{$sizename} FPn,{$eaname}");
                    468:                                break;
                    469:                         case "fgen":
                    470:                                out("   ; Fgen.{$sizename} {$eaname},FPn");
                    471:                                break;
                    472:                         case "fscale":
                    473:                                out("   ; FSCALE.{$sizename} {$eaname},FPn");
                    474:                                break;
                    475:                         case "fscc":
                    476:                                out("   ; FScc.B {$eaname}");
                    477:                                break;
                    478:                         case "fmovem_rm":
                    479:                                out("   ; FMOVEM.X FPn,{$eaname}");
                    480:                                break;
                    481:                         case "fmovem_mr":
                    482:                                out("   ; FMOVEM.X {$eaname},FPn");
                    483:                                break;
                    484:                         case "fmovem_cm":
                    485:                                out("   ; FMOVEM.L {$crname},{$eaname}");
                    486:                                break;
                    487:                         case "fmovem_mc":
                    488:                                out("   ; FMOVEM.L {$eaname},{$crname}");
                    489:                                break;
                    490:                        }
                    491:                        $expected = sprintf("$%02x", $expected);
                    492:                        out("   move.b  #{$expected},(a2)+");
                    493:                        // ConditionByte の N, Inf, NAN を立てる。Z は下げておく。
                    494:                        out("   fmovem.l        #$0b000000,fpsr");
                    495:                        out("   bsr     set_fline");
                    496:                        out("   moveq.l #0,d7");
                    497:                        // 命令を作成。
                    498:                        $post = "";
                    499:                        $dir = ($test['is_store'] ? "store" : "load");
                    500:                        switch ("{$dir}_{$eatype}") {
                    501:                         // 書き込み先のポインタだけ設定。
                    502:                         case "store_m":
                    503:                         case "store_mi":
                    504:                                out("   lea.l   workarea(pc),a0");
                    505:                                break;
                    506:                         case "store_md":
                    507:                                out("   lea.l   workarea+12(pc),a0");
                    508:                                break;
                    509:                         case "store_r":
                    510:                                out("   lea.l   workarea(pc),a0");
                    511:                                $post = ".dc.w  $0000";
                    512:                                break;
                    513:                         case "store_x":
                    514:                                out("   moveq.l #0,d4");
                    515:                                out("   lea.l   workarea(pc),a0");
                    516:                                $post = ".dc.w  $4000";
                    517:                                break;
                    518: 
                    519:                         // 読み込み元になるデータもゼロで用意する必要がある。
                    520:                         case "load_d":
                    521:                                out("   moveq.l #0,d6");
                    522:                                break;
                    523:                         case "load_m":
                    524:                         case "load_mi":
                    525:                                out("   lea.l   workarea+12(pc),a0");
                    526:                                out("   move.l  d7,-(a0)");
                    527:                                out("   move.l  d7,-(a0)");
                    528:                                out("   move.l  d7,-(a0)");
                    529:                                break;
                    530:                         case "load_md":
                    531:                                out("   lea.l   workarea(pc),a0");
                    532:                                out("   move.l  d7,(a0)+");
                    533:                                out("   move.l  d7,(a0)+");
                    534:                                out("   move.l  d7,(a0)+");
                    535:                                break;
                    536:                         case "load_r":
                    537:                                out("   lea.l   workarea+12(pc),a0");
                    538:                                out("   move.l  d7,-(a0)");
                    539:                                out("   move.l  d7,-(a0)");
                    540:                                out("   move.l  d7,-(a0)");
                    541:                                $post = ".dc.w  $0000";
                    542:                                break;
                    543:                         case "load_x":
                    544:                                out("   moveq.l #0,d4");
                    545:                                out("   lea.l   workarea+12(pc),a0");
                    546:                                out("   move.l  d7,-(a0)");
                    547:                                out("   move.l  d7,-(a0)");
                    548:                                out("   move.l  d7,-(a0)");
                    549:                                $post = ".dc.w  $4000";
                    550:                                break;
                    551:                         case "load_p":
                    552:                                out("   bra     @f");
                    553:                                out("   .dc.l   0, 0, 0");
                    554:                                out("@@:");
                    555:                                // 命令本体(4) + 直前のLEA(6) + ここ(12)
                    556:                                $post = ".dc.w  -4-6-12";
                    557:                                break;
                    558:                         case "load_i":
                    559:                                switch ($sizename) {
                    560:                                 case "B":
                    561:                                 case "W":
                    562:                                        $post = ".dc.w  0";
                    563:                                        break;
                    564:                                 case "L":
                    565:                                 case "S":
                    566:                                 case "c":      // FPCR
                    567:                                 case "s":      // FPSR
                    568:                                 case "i":      // FPIAR
                    569:                                        $post = ".dc.l  0";
                    570:                                        break;
                    571:                                 case "D":
                    572:                                 case "m":      // FPSR/FPIAR
                    573:                                        $post = ".dc.l  0, 0";
                    574:                                        break;
                    575:                                 case "X":
                    576:                                 case "P":
                    577:                                        $post = ".dc.l  0, 0, 0";
                    578:                                        break;
                    579:                                }
                    580:                                break;
                    581: 
                    582:                         default:
                    583:                                break;
                    584:                        }
                    585:                        out("   lea.l   @f,a3");
                    586:                        out("   .dc.l   $%08x", $inst);
                    587:                        if (strlen($post) > 0) {
                    588:                                out("   {$post}");
                    589:                        }
                    590:                        out("@@:");
                    591:                        out("   bsr     restore_fline");
                    592:                        out("   fmovem.l        fpsr,d0");
                    593:                        out("   rol.l   #8,d0");
                    594:                        out("   or.l    d7,d0");
                    595:                        out("   move.b  d0,(a2)+");
                    596:                        out("");
                    597:                }
                    598:                out("   lea.l   msg_test_{$test['eatype']},a0");
                    599:                out("   moveq.l #" . count($expected_array) . "-1,d0");
                    600:                out("   bsr     print_result");
                    601:                out("   rts");
                    602:                out("");
                    603:        }
                    604: ?>
                    605: <?php
                    606: // 1行を出力する。引数は printf のように fmt... で指定可能。
                    607: // 改行はこちらで付加する。
                    608: function out()
                    609: {
                    610:        $args = func_get_args();
                    611:        $fmt = array_shift($args);
                    612:        print vsprintf($fmt, $args);
                    613:        print "\n";
                    614: }
                    615: ?>
                    616: 
                    617: ; 引数を処理する。
                    618: ; 引数がなければヘルプを表示。
                    619: ; 引数... があれば列挙されたテストを実行。
                    620: ; "all" ならすべて実行。
                    621: parse_arg:
                    622:        movem.l d0-d2/a0,-(sp)
                    623:        tst.b   (a2)
                    624:        beq     parse_done
                    625: parse_loop:
                    626:        adda.l  #1,a2
                    627:        move.b  (a2),d0                 ; '\0' なら終了
                    628:        beq     parse_done
                    629: 
                    630:        cmpi.b  #' ',d0
                    631:        beq     parse_loop
                    632:        cmpi.b  #$09,d0
                    633:        beq     parse_loop
                    634: 
                    635:        ; "help"
                    636:        lea.l   cmd_help(pc),a0
                    637:        bsr match
                    638:        beq     print_help
                    639: 
                    640:        ; "all"
                    641:        lea.l   cmd_all(pc),a0
                    642:        bsr     match
                    643:        bne     @f
                    644: <?php
                    645:        foreach ($cmdlist as $cmd) {
                    646:                out("   st.b    is_{$cmd}");
                    647:        }
                    648: ?>
                    649:        ; 後は無視していいだろう。
                    650:        bra     parse_done
                    651: @@:
                    652: <?php
                    653:        // 個別コマンドのループ
                    654:        foreach ($cmdlist as $cmd) {
                    655:                out("   ; \"{$cmd}\"");
                    656:                out("   lea.l   cmd_{$cmd}(pc),a0");
                    657:                out("   bsr     match");
                    658:                out("   bne     @f");
                    659:                out("   st.b    is_{$cmd}");
                    660:                out("   bra     parse_loop");
                    661:                out("@@:");
                    662:        }
                    663: ?>
                    664: 
                    665: parse_done:
                    666:        ; どのコマンドも実行になってなければヘルプを表示。
                    667:        moveq.l #0,d0
                    668:        lea.l   is_tests(pc),a0
                    669:        moveq.l #<?php print count($cmdlist); ?>-1,d1
                    670: @@:
                    671:        or.b    (a0)+,d0
                    672:        dbra    d1,@b
                    673:        beq     print_help
                    674: 
                    675:        movem.l (sp)+,d0-d2/a0
                    676:        rts
                    677: 
                    678: ; ヘルプを表示して終了。
                    679: print_help:
                    680:        PRINT   msg_help(pc)
                    681:        DOS     _EXIT
                    682: 
                    683: ; (a2) からの単語が (a0) からのゼロ終端文字列と一致するか。
                    684: ; 一致すれば d0 = 0 を返して (a2) は単語の最後の1文字を指すようにする。
                    685: ; 一致しなければ d0 != 0 を返して (a2) は元の位置のまま。
                    686: match:
                    687:        movem.l a1,-(sp)
                    688:        movea.l a2,a1           ; 戻り値用
                    689: match_loop:
                    690:        move.b  (a2)+,d0
                    691:        cmpi.b  #' ',d0         ; d0 が ' ' なら '\0' に
                    692:        bne     @f
                    693:        moveq.l #0,d0
                    694:        bra     match_main
                    695: @@:
                    696:        cmpi.b  #$09,d0         ; d0 が TAB なら '\0' に
                    697:        bne     match_main
                    698:        moveq.l #0,d0
                    699: match_main:
                    700:        ; この状態で比較
                    701:        cmp.b   (a0)+,d0
                    702:        bne     not_match
                    703:        ; '\0' 以外で一致したら次の文字へ。
                    704:        tst.b   d0
                    705:        bne     match_loop
                    706:        ; '\0' で一致したので完了。
                    707:        suba.l  #1,a2
                    708:        moveq.l #0,d0
                    709:        movem.l (sp)+,a1
                    710:        rts
                    711: 
                    712: not_match:
                    713:        ; 不一致なので a2 を元に戻す。
                    714:        movea.l a1,a2
                    715:        moveq.l #1,d0
                    716:        movem.l (sp)+,a1
                    717:        rts
                    718: 
                    719: ; 結果を1行表示する。
                    720: ; A0 にテスト名、D0 に(テスト数-1)を入れて呼ぶこと。
                    721: ;
                    722: ; A2 からの result バッファは 2バイト1組で、
                    723: ; +0 バイト目が期待値、bit4 がトラップの有無、bit3-0 が ConditionByte。
                    724: ; +1 バイト目が結果値、構造は同じ。
                    725: ;
                    726: ; 期待値            結果
                    727: ; (0<<4)|(x)   (0<<4)|(x)      pass:OK
                    728: ; (0<<4)|(x)   (0<<4)|(y)      flag:FAIL
                    729: ; (0<<4)|(x)   (1<<4)|(x)      trap:FAIL
                    730: ; (0<<4)|(x)   (1<<4)|(y)      trap:FAIL
                    731: ; (1<<4)|(x)   (0<<4)|(x)      pass:FAIL
                    732: ; (1<<4)|(x)   (0<<4)|(y)      pass:FAIL
                    733: ; (1<<4)|(x)   (1<<4)|(x)      trap:OK
                    734: ; (1<<4)|(x)   (1<<4)|(y)      flag:FAIL
                    735: print_result:
                    736:        movem.l d0-d4/a2,-(sp)
                    737:        move.l  d0,d4
                    738:        PRINT   (a0)
                    739:        lea.l   result(pc),a2
                    740:        moveq.l #0,d0
                    741:        moveq.l #0,d1
                    742: prloop:
                    743:        move.b  (a2)+,d0                ; 期待値
                    744:        move.b  (a2)+,d1                ; 結果
                    745:        ; 先に failed のカウント
                    746:        cmp.b   d1,d0
                    747:        beq     @f
                    748:        addi.l  #1,failed
                    749: @@:
                    750:        bfextu  d0{#27:#1},d2   ; 期待値のトラップビット
                    751:        bfextu  d1{#27:#1},d3   ; 結果のトラップビット
                    752:        andi.b  #$0f,d0
                    753:        andi.b  #$0f,d1
                    754:        cmp.b   d1,d0
                    755:        sne.b   d0
                    756:        neg.b   d0                              ; d0 は一致なら $0、そうでなければ $1
                    757:        lsl.l   #1,d3                   ; d3 は結果がトラップなら $2、通過なら $0
                    758:        or.b    d3,d0
                    759:        lsl.l   #2,d2                   ; d2 は期待値がトラップなら $4、通過なら $0
                    760:        or.b    d2,d0
                    761:        add.b   d0,d0                   ; d0 *= 2
                    762:        PRINT   msg_result(pc,d0.w*8)
                    763:        dbra    d4,prloop
                    764:        PRINT   msg_crlf(pc)
                    765:        movem.l (sp)+,d0-d4/a2
                    766:        rts
                    767: 
                    768: ; Fライン例外をテスト用のものに差し替える。
                    769: ; 変更前のアドレスを a4 に格納する。
                    770: set_fline:
                    771:        movem.l d0-d1/a1,-(sp)
                    772:        moveq.l #$b,d1
                    773:        lea.l   fline_handler(pc),a1
                    774:        IOCS    _B_INTVCS
                    775:        movea.l d0,a4
                    776:        movem.l (sp)+,d0-d1/a1
                    777:        rts
                    778: 
                    779: ; Fライン例外を元に戻す。
                    780: restore_fline:
                    781:        movem.l d0-d1/a1,-(sp)
                    782:        moveq.l #$b,d1
                    783:        movea.l a4,a1
                    784:        IOCS    _B_INTVCS
                    785:        movem.l (sp)+,d0-d1/a1
                    786:        rts
                    787: 
                    788: ; Fライン例外ハンドラ
                    789: ; a3 に戻りアドレスをセットしてあること
                    790: ; d7 を $10 にして帰る
                    791: fline_handler:
                    792:        moveq.l #$10,d7
                    793:        move.l  a3,2(sp)
                    794:        rte
                    795: 
                    796: <?php
                    797:        foreach ($ealist as $eatype => $arr) {
                    798:                $eaname = $arr['name'];
                    799:                while (strlen($eaname) < 9) {
                    800:                        $eaname .= " ";
                    801:                }
                    802:                out("msg_test_{$eatype}:        .dc.b   \" {$eaname}\",0");
                    803:        }
                    804: ?>
                    805: 
                    806: msg_head_fmove:
                    807:        .dc.b   "FMOVEtomem ",0
                    808: msg_head_fgen:
                    809:        .dc.b   "Fgen       ",0
                    810: msg_head_fscale:
                    811:        .dc.b   "FSCALE     ",0
                    812: msg_head_fmovem_cm:
                    813:        .dc.b   "FMOVEM_cm  ",0
                    814: msg_head_fmovem_mc:
                    815:        .dc.b   "FMOVEM_mc  ",0
                    816: msg_head_fscc:
                    817:        .dc.b   "FScc       .B",$d,$a,0
                    818: msg_head_fmovem_rm:
                    819:        .dc.b   "FMOVEM_rm  .X",$d,$a,0
                    820: msg_head_fmovem_mr:
                    821:        .dc.b   "FMOVEM_mr  .X",$d,$a,0
                    822: 
                    823: msg_head_guide4:
                    824:        .dc.b   "FPCR      "
                    825:        .dc.b   "FPSR      "
                    826:        .dc.b   "FPIAR     "
                    827:        .dc.b   "FPSR/FPIAR",$d,$a,0
                    828: 
                    829: msg_head_guide7:
                    830:        .dc.b   ".B        "
                    831:        .dc.b   ".W        "
                    832:        .dc.b   ".L        "
                    833:        .dc.b   ".S        "
                    834:        .dc.b   ".D        "
                    835:        .dc.b   ".X        "
                    836:        .dc.b   ".P",$d,$a,0
                    837: 
                    838: msg_result:
                    839:        .dc.b   " pass:OK  ",0,0,0,0,0,0
                    840:        .dc.b   " flag:FAIL",0,0,0,0,0,0
                    841:        .dc.b   " trap:FAIL",0,0,0,0,0,0
                    842:        .dc.b   " trap:FAIL",0,0,0,0,0,0
                    843:        .dc.b   " pass:FAIL",0,0,0,0,0,0
                    844:        .dc.b   " pass:FAIL",0,0,0,0,0,0
                    845:        .dc.b   " trap:OK  ",0,0,0,0,0,0
                    846:        .dc.b   " flag:FAIL",0
                    847: 
                    848: msg_failed:
                    849:        .dc.b   "FAILED"        ; ,$d,$a,0
                    850: msg_crlf:
                    851:        .dc.b   $d,$a,0
                    852: 
                    853: msg_help:
                    854:        .dc.b   "usage: { 'all' | 'help' | testnames... }",$d,$a
                    855:        .dc.b   " testnames:"
                    856: <?php
                    857:        foreach ($cmdlist as $cmd) {
                    858:                out("   .dc.b   \" {$cmd}\"");
                    859:        }
                    860: ?>
                    861:        .dc.b   $d,$a,0
                    862: 
                    863: cmd_help:
                    864:        .dc.b   "help",0
                    865: cmd_all:
                    866:        .dc.b   "all",0
                    867: <?php
                    868:        foreach ($cmdlist as $cmd) {
                    869:                out("cmd_{$cmd}:");
                    870:                out("   .dc.b   \"{$cmd}\",0");
                    871:        }
                    872: ?>
                    873: 
                    874:        .bss
                    875:        .even
                    876: result:
                    877:        .ds.w   <?php print count($sizelist)."\n"; ?>
                    878:        .align  4
                    879: workarea:
                    880:        .ds.l   3
                    881: failed:
                    882:        .ds.l   1
                    883: 
                    884:        ; テストを実行する場合は !0
                    885: is_tests:
                    886: <?php
                    887:        foreach ($cmdlist as $cmd) {
                    888:                out("is_{$cmd}:");
                    889:                out("   .ds.b   1");
                    890:        }
                    891: ?>
                    892: 
                    893:        .end    start

unix.superglobalmegacorp.com

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