Annotation of nono/hd64180/gentable.php, revision 1.1.1.1

1.1       root        1: <?php
                      2: //
                      3: // nono
                      4: // Copyright (C) 2022 nono project
                      5: // Licensed under nono-license.txt
                      6: //
                      7: 
                      8:        $inst0table = read_instructions("instructions.txt");
                      9:        $funchash = make_funchash($inst0table);
                     10: 
                     11:        $insttable = expand_rrr($inst0table, "rrr", "r");
                     12:        $insttable = expand_rrr($insttable, "sss", "s");
                     13:        $insttable = expand_fff($insttable);
                     14:        $insttable = expand_ww($insttable);
                     15:        $insttable = expand_zz($insttable);
                     16:        $insttable = expand_vvv($insttable);
                     17:        $insttable = expand_bbb($insttable);
                     18: 
                     19:        $insttable = make($insttable);
                     20: 
                     21:        output_switch($insttable);
                     22:        output_header();
                     23: 
                     24:        exit(0);
                     25: ?>
                     26: <?php
                     27: function usage()
                     28: {
                     29:        global $argv;
                     30: 
                     31:        print "Usage: ${argv[0]}\n";
                     32:        exit(1);
                     33: }
                     34: 
                     35: // instructions.txt を読み込んで $insttable*[] 配列にする
                     36: function read_instructions($filename)
                     37: {
                     38:        $fp = fopen($filename, "r");
                     39:        if ($fp === false) {
                     40:                print "fopen failed: {$filename}\n";
                     41:                exit(1);
                     42:        }
                     43: 
                     44:        $insttable = array();
                     45: 
                     46:        while (($line = fgets($fp))) {
                     47:                $line = trim(preg_replace("/;.*/", "", $line));
                     48:                if ($line == "") {
                     49:                        continue;
                     50:                }
                     51: 
                     52:                // 1行はこんな感じ
                     53:                // 00rrr100             01      inc_r   INC r
                     54:                // CB:00000rrr  01      rlc             RLC r
                     55:                // 列は1つ以上のタブで区切られている。
                     56:                // $bits … ビットパターン
                     57:                // $cpus … CPU 区別
                     58:                // $name … 関数名
                     59:                // $text … ニーモニック
                     60: 
                     61:                $column = preg_split("/\t+/", $line, -1, PREG_SPLIT_NO_EMPTY);
                     62:                $bits = $column[0];
                     63:                // 1バイト目なら ":" をつけて書式を揃えておく
                     64:                if (!preg_match("/:/", $bits)) {
                     65:                        $bits = ":{$bits}";
                     66:                }
                     67:                $cpus = $column[1];
                     68:                $name = $column[2];
                     69:                $text = isset($column[3]) ? $column[3] : strtoupper($name);
                     70: 
                     71:                $newinst = array(
                     72:                        "bits"  => trim($bits),
                     73:                        "cpus"  => trim($cpus),
                     74:                        "name"  => trim($name),
                     75:                        "text"  => trim($text),
                     76:                );
                     77: 
                     78:                // $insttable[] に追加。
                     79:                $insttable[$bits] = $newinst;
                     80:        }
                     81:        fclose($fp);
                     82: 
                     83:        if (0) {
                     84:                print "read_instruction:\n";
                     85:                foreach ($insttable as $bits => $inst) {
                     86:                        printf("%s|%s|%-10s|%s\n",
                     87:                                $inst["bits"], $inst["cpus"], $inst["name"], $inst["text"]);
                     88:                }
                     89:                print "\n";
                     90:        }
                     91: 
                     92:        return $insttable;
                     93: }
                     94: 
                     95: // 展開前の $insttable から $funchash[] を作成する。
                     96: // $funchash は関数名をキーにしたハッシュで
                     97: // $funchash = array(
                     98: //  "add_hl_ww" => array("00ww1001|ADD HL,ww", "DD:00ww1001|ADD IX,ww"),
                     99: //  :
                    100: // ); のように、関数名とそれに紐づくニーモニックを集めたもの。
                    101: function make_funchash($insttable)
                    102: {
                    103:        $funchash = array();
                    104:        foreach ($insttable as $bits => $inst) {
                    105:                // $bits は1ワード目なら : から始まっているので取り除く
                    106:                $bit2 = preg_replace("/^:/", "", $bits);
                    107:                $name = $inst["name"];
                    108:                $text = $inst["text"];
                    109:                switch ($inst["cpus"]) {
                    110:                 case "01R":
                    111:                        break;
                    112:                 case "-1-":    // HD64*180 専用命令
                    113:                        $text .= "\t(HD64*180 only)";
                    114:                        break;
                    115:                 case "--R":    // R800 専用命令
                    116:                        $text .= "\t(R800 only)";
                    117:                        break;
                    118:                 case "0-R":    // Z80/R800 命令 (HD64*180 未実装命令)
                    119:                        $text .= "\t(Z80/R800)";
                    120:                        break;
                    121:                 default:
                    122:                        printf("unknown cpu field: {$inst["cpus"]}\n");
                    123:                        exit(1);
                    124:                }
                    125: 
                    126:                if (!isset($funchash[$name])) {
                    127:                        $funchash[$name] = array();
                    128:                }
                    129:                $funchash[$name][] = "{$bit2}|{$text}";
                    130:        }
                    131: 
                    132:        if (0) {
                    133:                print "make_funchash:\n";
                    134:                foreach ($funchash as $name => $lines) {
                    135:                        printf("%-10s",  $name);
                    136:                        foreach ($lines as $str) {
                    137:                                print " \"{$str}\"";
                    138:                        }
                    139:                        print "\n";
                    140:                }
                    141:                print "\n";
                    142:        }
                    143: 
                    144:        return $funchash;
                    145: }
                    146: 
                    147: // $insttable の rrr を展開する。
                    148: // regbits は "rrr" か "sss" で、bits 内を置換する文字列。
                    149: // regtext は "r" か "s" で、text 内を置換する文字列。
                    150: function expand_rrr($insttable, $regbits, $regtext)
                    151: {
                    152:        $rrr = array(
                    153:                "000" => "B",
                    154:                "001" => "C",
                    155:                "010" => "D",
                    156:                "011" => "E",
                    157:                "100" => "H",
                    158:                "101" => "L",
                    159:        //      "110" (HL) は出力しない
                    160:                "111" => "A",
                    161:        );
                    162:        $inst2table = array();
                    163:        foreach ($insttable as $bits => $inst) {
                    164:                if (preg_match("/{$regbits}/", $bits)) {
                    165:                        foreach ($rrr as $rbits => $rname) {
                    166:                                $inst2 = $inst;
                    167:                                $newbits = preg_replace("/{$regbits}/", $rbits, $bits);
                    168:                                $inst2["bits"] = $newbits;
                    169:                                $inst2["text"] =
                    170:                                        preg_replace("/{$regtext}/", $rname, $inst["text"]);
                    171:                                $inst2table[$newbits] = $inst2;
                    172:                        }
                    173:                } else {
                    174:                        // 上書きする際は後者優先
                    175:                        $inst2table[$bits] = $inst;
                    176:                }
                    177:        }
                    178: 
                    179:        // デバッグ表示
                    180:        if (0) {
                    181:                print "expand_rrr({$regbits})\n";
                    182:                foreach ($inst2table as $inst) {
                    183:                        printf("%s|%-10s|%s\n",
                    184:                                $inst["bits"], $inst["name"], $inst["text"]);
                    185:                }
                    186:        }
                    187: 
                    188:        return $inst2table;
                    189: }
                    190: 
                    191: // $insttable の fff を展開する。
                    192: function expand_fff($insttable)
                    193: {
                    194:        $fff = array(
                    195:                "000" => "NZ",
                    196:                "001" => "NC",
                    197:                "010" => "PO",
                    198:                "011" => "P",
                    199:                "100" => "Z",
                    200:                "101" => "C",
                    201:                "110" => "PE",
                    202:                "111" => "M",
                    203:        );
                    204: 
                    205:        $inst2table = array();
                    206:        foreach ($insttable as $bits => $inst) {
                    207:                if (preg_match("/fff/", $bits)) {
                    208:                        foreach ($fff as $fbits => $fname) {
                    209:                                $inst2 = $inst;
                    210:                                $newbits = preg_replace("/fff/", $fbits, $bits);
                    211:                                $inst2["bits"] = $newbits;
                    212:                                $inst2["text"] = preg_replace("/f/", $fname, $inst["text"]);
                    213:                                $inst2table[$newbits] = $inst2;
                    214:                        }
                    215:                } else {
                    216:                        // 上書きする際は後者優先
                    217:                        $inst2table[$bits] = $inst;
                    218:                }
                    219:        }
                    220: 
                    221:        // デバッグ表示
                    222:        if (0) {
                    223:                print "expand_fff\n";
                    224:                foreach ($inst2table as $inst) {
                    225:                        printf("%s|%-10s|%s\n",
                    226:                                $inst["bits"], $inst["name"], $inst["text"]);
                    227:                }
                    228:        }
                    229: 
                    230:        return $inst2table;
                    231: }
                    232: 
                    233: // $insttable の ww を展開する。
                    234: function expand_ww($insttable)
                    235: {
                    236:        $ww = array(
                    237:                "00" => "BC",
                    238:                "01" => "DE",
                    239:                "10" => "HL",
                    240:                "11" => "SP",
                    241:        );
                    242: 
                    243:        $inst2table = array();
                    244:        foreach ($insttable as $bits => $inst) {
                    245:                if (preg_match("/ww/", $bits)) {
                    246:                        foreach ($ww as $wbits => $wname) {
                    247:                                $inst2 = $inst;
                    248:                                $newbits = preg_replace("/ww/", $wbits, $bits);
                    249:                                $inst2["bits"] = $newbits;
                    250:                                $inst2["text"] = preg_replace("/ww/", $wname, $inst["text"]);
                    251:                                $inst2table[$newbits] = $inst2;
                    252:                        }
                    253:                } else {
                    254:                        // 上書きする際は後者優先
                    255:                        $inst2table[$bits] = $inst;
                    256:                }
                    257:        }
                    258: 
                    259:        // デバッグ表示
                    260:        if (0) {
                    261:                print "expand_ww\n";
                    262:                foreach ($inst2table as $inst) {
                    263:                        printf("%s|%-10s|%s\n",
                    264:                                $inst["bits"], $inst["name"], $inst["text"]);
                    265:                }
                    266:        }
                    267: 
                    268:        return $inst2table;
                    269: }
                    270: 
                    271: // $insttable の zz を展開する。
                    272: function expand_zz($insttable)
                    273: {
                    274:        $zz = array(
                    275:                "00" => "BC",
                    276:                "01" => "DE",
                    277:                "10" => "HL",
                    278:                "11" => "AF",
                    279:        );
                    280: 
                    281:        $inst2table = array();
                    282:        foreach ($insttable as $bits => $inst) {
                    283:                if (preg_match("/zz/", $bits)) {
                    284:                        foreach ($zz as $zbits => $zname) {
                    285:                                $inst2 = $inst;
                    286:                                $newbits = preg_replace("/zz/", $zbits, $bits);
                    287:                                $inst2["bits"] = $newbits;
                    288:                                $inst2["text"] = preg_replace("/zz/", $zname, $inst["text"]);
                    289:                                $inst2table[$newbits] = $inst2;
                    290:                        }
                    291:                } else {
                    292:                        // 上書きする際は後者優先
                    293:                        $inst2table[$bits] = $inst;
                    294:                }
                    295:        }
                    296: 
                    297:        // デバッグ表示
                    298:        if (0) {
                    299:                print "expand_zz\n";
                    300:                foreach ($inst2table as $inst) {
                    301:                        printf("%s|%-10s|%s\n",
                    302:                                $inst["bits"], $inst["name"], $inst["text"]);
                    303:                }
                    304:        }
                    305: 
                    306:        return $inst2table;
                    307: }
                    308: 
                    309: // $insttable の vvv を展開する。
                    310: function expand_vvv($insttable)
                    311: {
                    312:        $vvv = array(
                    313:                "000" => "00H",
                    314:                "001" => "10H",
                    315:                "010" => "20H",
                    316:                "011" => "30H",
                    317:                "100" => "08H",
                    318:                "101" => "18H",
                    319:                "110" => "28H",
                    320:                "111" => "38H",
                    321:        );
                    322: 
                    323:        $inst2table = array();
                    324:        foreach ($insttable as $bits => $inst) {
                    325:                if (preg_match("/vvv/", $bits)) {
                    326:                        foreach ($vvv as $vbits => $vname) {
                    327:                                $inst2 = $inst;
                    328:                                $newbits = preg_replace("/vvv/", $vbits, $bits);
                    329:                                $inst2["bits"] = $newbits;
                    330:                                $inst2["text"] = preg_replace("/v/", $vname, $inst["text"]);
                    331:                                $inst2table[$newbits] = $inst2;
                    332:                        }
                    333:                } else {
                    334:                        // 上書きする際は後者優先
                    335:                        $inst2table[$bits] = $inst;
                    336:                }
                    337:        }
                    338: 
                    339:        // デバッグ表示
                    340:        if (0) {
                    341:                print "expand_vvv\n";
                    342:                foreach ($inst2table as $inst) {
                    343:                        printf("%s|%-10s|%s\n",
                    344:                                $inst["bits"], $inst["name"], $inst["text"]);
                    345:                }
                    346:        }
                    347: 
                    348:        return $inst2table;
                    349: }
                    350: 
                    351: // $insttable の bbb を展開する。
                    352: function expand_bbb($insttable)
                    353: {
                    354:        $inst2table = array();
                    355:        foreach ($insttable as $bits => $inst) {
                    356:                if (preg_match("/bbb/", $bits)) {
                    357:                        for ($b = 0; $b < 8; $b++) {
                    358:                                $inst2 = $inst;
                    359:                                $nbits = "00" . base_convert($b, 10, 2);
                    360:                                $nbits = substr($nbits, -3);
                    361:                                $newbits = preg_replace("/bbb/", $nbits, $bits);
                    362:                                $inst2["bits"] = $newbits;
                    363:                                $inst2["text"] = preg_replace("/b/", "{$b}", $inst["text"]);
                    364:                                $inst2table[$newbits] = $inst2;
                    365:                        }
                    366:                } else {
                    367:                        // 上書きする際は後者優先
                    368:                        $inst2table[$bits] = $inst;
                    369:                }
                    370:        }
                    371: 
                    372:        // デバッグ表示
                    373:        if (0) {
                    374:                print "expand_bbb\n";
                    375:                foreach ($inst2table as $inst) {
                    376:                        printf("%s|%-10s|%s\n",
                    377:                                $inst["bits"], $inst["name"], $inst["text"]);
                    378:                }
                    379:        }
                    380: 
                    381:        return $inst2table;
                    382: }
                    383: 
                    384: // ":00000000" => {
                    385: //   "bits" => ":00000000",
                    386: //   "name" => "nop", ...
                    387: // }
                    388: // 形式をプレフィックスを1段目にして
                    389: // "" => {
                    390: //   "00000000" => {
                    391: //     "bits" => "00000000",
                    392: //     "name" => "nop", ...
                    393: //   },
                    394: // }
                    395: // の形式に組み替えたものを返す。
                    396: //
                    397: // ついでに namehash[$name] => $name の一覧もグローバル変数で返す。
                    398: function make($insttable)
                    399: {
                    400:        global $argv;
                    401:        global $namehash;
                    402: 
                    403:        $inst2table = array();
                    404: 
                    405:        ksort($insttable);
                    406:        foreach ($insttable as $bits => $inst) {
                    407:                preg_match("/^([^:]*):(.*)/", $bits, $m);
                    408:                $pre  = $m[1];
                    409:                $bits = $m[2];
                    410: 
                    411:                $inst2 = $inst;
                    412:                $inst2["bits"] = $bits;
                    413: 
                    414:                if (!isset($inst2table[$pre])) {
                    415:                        $inst2table[$pre] = array();
                    416:                }
                    417:                $inst2table[$pre][$bits] = $inst2;
                    418:        }
                    419: 
                    420:        if (0) {
                    421:                print "make:\n";
                    422:                foreach ($inst2table as $pre => $table) {
                    423:                        foreach ($table as $bits => $inst) {
                    424:                                printf("%5s|%s|%-10s|%s\n",
                    425:                                        $pre, $inst["bits"], $inst["name"], $inst["text"]);
                    426:                        }
                    427:                }
                    428:                print "\n";
                    429:        }
                    430: 
                    431:        // 00 テーブルはすべて埋まっていると分かっているので、ここでチェック。
                    432:        // $bits によるハッシュになっているので数だけ数えればいいか?
                    433:        if (count($inst2table[""]) != 256) {
                    434:                printf("{$argv[0]}: Number of entries in table 00 is wrong: %d\n",
                    435:                        count($inst2table[""]));
                    436:                exit(1);
                    437:        }
                    438:        // 他のテーブルはすべて埋まってるわけではないので、数えない。
                    439: 
                    440:        foreach ($inst2table as $pre => $table) {
                    441:                foreach ($table as $bits => $inst) {
                    442:                        $name = $inst["name"];
                    443:                        $namehash[$name] = $name;
                    444:                }
                    445:        }
                    446:        ksort($namehash);
                    447: 
                    448:        return $inst2table;
                    449: }
                    450: 
                    451: 
                    452: function output_switch($insttable)
                    453: {
                    454:        foreach ($insttable as $pre => $table) {
                    455:                output_switch_sub($pre, $table);
                    456:        }
                    457: }
                    458: 
                    459: function output_switch_sub($pre, $table)
                    460: {
                    461:        global $inst0table;
                    462:        global $funchash;
                    463: 
                    464:        // func2 は [256] => name 形式で、存在してるものだけ抜き出したもの。
                    465:        $func2 = array();
                    466:        foreach ($table as $bits => $inst) {
                    467:                $i = base_convert($bits, 2, 10);
                    468:                $i += 0;
                    469:                $func2[$i] = $inst["name"];
                    470:        }
                    471: 
                    472:        $out = "";
                    473:        $cpp = "";
                    474:        for ($i = 0; $i < 256; $i++) {
                    475:                if (!isset($func2[$i])) {
                    476:                        continue;
                    477:                }
                    478:                $funcname = $func2[$i];
                    479: 
                    480:                $cases = array();
                    481:                // この関数名を持つブロックに属する人全員のコメント集める。
                    482:                // このブロック自身もここで集計するため $j は $i から始める。
                    483:                for ($j = $i; $j < 256; $j++) {
                    484:                        if (isset($func2[$j]) && $func2[$j] == $funcname) {
                    485:                                $cases[] = $j;
                    486: 
                    487:                                // 集計したら消す
                    488:                                unset($func2[$j]);
                    489:                        }
                    490:                }
                    491: 
                    492:                // case 部分の出力。
                    493:                // 4個くらいまでなら case 文を羅列、
                    494:                // それ以上連続してたら範囲で出力。
                    495:                $cont = true;
                    496:                for ($k = 1; $k < count($cases); $k++) {
                    497:                        if ($cases[$k] - $cases[$k - 1] != 1) {
                    498:                                $cont = false;
                    499:                                break;
                    500:                        }
                    501:                }
                    502:                if ($cont == true && count($cases) > 4) {
                    503:                        $c = array_shift($cases);
                    504:                        $bits = decbin8($c);
                    505:                        $out .= sprintf("\t case 0b{$bits}      // 0x%02x\n", $c);
                    506: 
                    507:                        $c = array_pop($cases);
                    508:                        $bits = decbin8($c);
                    509:                        $out .= sprintf("\t  ... 0b{$bits}:     // 0x%02x\n", $c);
                    510:                } else {
                    511:                        foreach ($cases as $c) {
                    512:                                $bits = decbin8($c);
                    513:                                $out .= sprintf("\t case 0b{$bits}:     // 0x%02x\n", $c);
                    514:                        }
                    515:                }
                    516:                // 関数
                    517:                $out .= "\t\tOP_FUNC({$funcname});\n";
                    518:                $out .= "\t\tbreak;\n";
                    519: 
                    520:                // ソースの雛形を出力。
                    521:                // DD は基本 00 と同じ処理関数を使うので、関数本体の出力は1回のみ。
                    522:                if (!isset($funchash[$funcname])) {
                    523:                        print "$funcname not found\n";
                    524:                        exit(1);
                    525:                }
                    526:                if (!isset($funchash[$funcname]["processed"])) {
                    527:                        // $funchash からこの関数のコメントを生成
                    528:                        $lines = $funchash[$funcname];
                    529:                        $comm = array();
                    530:                        // プレフィックスの長さを調べる
                    531:                        $plen = 0;
                    532:                        foreach ($lines as $line) {
                    533:                                $m = preg_split("/\|/", $line);
                    534:                                preg_match("/([A-Z_]+:)?(.*)/", $m[0], $b);
                    535:                                $plen = max($plen, strlen($b[1]));
                    536:                        }
                    537:                        foreach ($lines as $line) {
                    538:                                $m = preg_split("/\|/", $line);
                    539:                                preg_match("/([A-Z_]+:)?(.*)/", $m[0], $b);
                    540:                                $cpp .= sprintf("// %{$plen}s%s: %s\n", $b[1], $b[2], $m[1]);
                    541:                        }
                    542:                        $cpp .= "OP_DEF({$funcname})\n";
                    543:                        $cpp .= "{\n";
                    544:                        $cpp .= "\tOP_FUNC(unimpl);\n";
                    545:                        $cpp .= "}\n";
                    546:                        $cpp .= "\n";
                    547: 
                    548:                        $funchash[$funcname]["processed"] = true;
                    549:                }
                    550:        }
                    551: 
                    552:        if ($pre == "") {
                    553:                $pre = "00";
                    554:        } else {
                    555:                $pre = strtolower($pre);
                    556:        }
                    557:        write_file("switch_{$pre}.inc.new", $out);
                    558:        write_file("ops_{$pre}.cpp.new", $cpp);
                    559: }
                    560: 
                    561: // ヘッダを出力
                    562: function output_header()
                    563: {
                    564:        global $namehash;
                    565: 
                    566:        $out = "";
                    567:        foreach ($namehash as $name) {
                    568:                $out .= "OP_PROTO({$name});\n";
                    569:        }
                    570: 
                    571:        write_file("ops.h.new", $out);
                    572: }
                    573: 
                    574: // 数値 $num を2進数8桁の文字列にして返す
                    575: function decbin8($num)
                    576: {
                    577:        $str = str_repeat("0", 7) . decbin($num);
                    578:        $str = substr($str, -8);
                    579:        return $str;
                    580: }
                    581: 
                    582: // ファイル出力
                    583: function write_file($filename, $str)
                    584: {
                    585:        $fp = fopen($filename, "w");
                    586:        fwrite($fp, $str);
                    587:        fclose($fp);
                    588: 
                    589:        print "Output: {$filename}\n";
                    590: }
                    591: ?>

unix.superglobalmegacorp.com

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