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

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

unix.superglobalmegacorp.com

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