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

1.1       root        1: <?php
                      2: //
                      3: // nono
1.1.1.2   root        4: // Copyright (C) 2020 nono project
                      5: // Licensed under nono-license.txt
1.1       root        6: //
                      7: 
                      8:        if ($argc < 2) {
                      9:                usage();
                     10:        }
                     11: 
                     12:        $insttable = read_instructions("instructions.txt");
                     13:        $insttable = expand($insttable);
                     14:        makeop12($insttable);
                     15:        makeop12hash();
                     16:        output_goto();
                     17:        output_switch();
                     18:        output_header();
                     19:        exit(0);
                     20: ?>
                     21: <?php
                     22: function usage()
                     23: {
                     24:        global $argv;
                     25: 
                     26:        print "Usage: ${argv[0]}\n";
                     27:        exit(1);
                     28: }
                     29: 
                     30: 
                     31: // instructions.txt を読み込んで $insttable[] 配列にする
                     32: function read_instructions($filename)
                     33: {
                     34:        $fp = fopen($filename, "r");
                     35:        if ($fp === false) {
                     36:                print "fopen failed: {$filename}\n";
                     37:                exit(1);
                     38:        }
                     39: 
                     40:        $insttable = array();
                     41: 
                     42:        while (($line = fgets($fp))) {
                     43:                $line = trim(preg_replace("/;.*/", "", $line));
                     44:                if ($line == "") {
                     45:                        continue;
                     46:                }
                     47: 
                     48:                // 1行はこんな感じ
                     49:                // 000000_DDDDD_SSSSS_nnnnnn_nnnnnnnnnn ld_d_xrf        ld.d(XRF)
                     50:                // 列は1つ以上のタブで区切られている。
                     51:                // $bits … ビットパターン
                     52:                // $name … 関数名
                     53:                // $text … コメント
                     54: 
                     55:                $column = preg_split("/\t+/", $line, -1, PREG_SPLIT_NO_EMPTY);
                     56:                $bits = $column[0];
                     57:                $name = $column[1];
                     58:                $text = isset($column[2]) ? $column[2] : "";
                     59: 
                     60:                $name = trim($name);
                     61:                $text = trim($text);
                     62: 
                     63:                // 命令ワード32ビットは 6-5-5 6-5-5 ビットに分解でき、ここでは
                     64:                // 上位下位ハーフワードの上位6ビットずつを合わせた12ビットを使う。
                     65:                $bits12 = preg_replace("/(......)_.........._(......)_........../",
                     66:                        "$1$2", $bits);
                     67:                $bits12 = preg_replace("/[^10n]/", "n", $bits12);
                     68:                $newinst = array(
                     69:                        "bits" => $bits,
                     70:                        "bits12" => $bits12,
                     71:                        "name" => $name,
                     72:                        "text" => $text,
                     73:                );
                     74:                // $insttable[] に追加する。
                     75:                // ただし bits が同じものがあれば text だけ追加。
                     76:                if (isset($insttable[$bits])) {
                     77:                        $insttable[$bits]["text"] .= ";{$text}";
                     78:                } else {
                     79:                        $insttable[$bits] = $newinst;
                     80:                }
                     81:        }
                     82:        fclose($fp);
                     83: 
                     84:        // デバッグ表示
                     85:        if (0) {
                     86:                print "read_instruction\n";
                     87:                foreach ($insttable as $inst) {
                     88:                        printf("%s|%s|%-10s|%s\n",
                     89:                                $inst["bits"], $inst["bits12"], $inst["name"], $inst["text"]);
                     90:                }
                     91:        }
                     92: 
                     93:        return $insttable;
                     94: }
                     95: 
                     96: // $insttable を bit12 で展開する。
                     97: // これで bits12 には未確定部分がなくなる。
                     98: function expand($insttable)
                     99: {
                    100:        do {
                    101:                $expanded = false;
                    102:                $inst2table = array();
                    103:                foreach ($insttable as $inst) {
                    104:                        if (preg_match("/^([01]*)n(.*)/", $inst["bits12"], $m)) {
                    105:                                // $m[1] は先頭から確定部分
                    106:                                // $m[2] が未処理部分
                    107: 
                    108:                                $inst2table[] = array(
                    109:                                        "bits" => $inst["bits"],
                    110:                                        "bits12" => "{$m[1]}0{$m[2]}",
                    111:                                        "name" => $inst["name"],
                    112:                                        "text" => $inst["text"],
                    113:                                );
                    114:                                $inst2table[] = array(
                    115:                                        "bits" => $inst["bits"],
                    116:                                        "bits12" => "{$m[1]}1{$m[2]}",
                    117:                                        "name" => $inst["name"],
                    118:                                        "text" => $inst["text"],
                    119:                                );
                    120:                                $expanded = true;
                    121:                        } else {
                    122:                                $inst2table[] = $inst;
                    123:                        }
                    124:                }
                    125: 
                    126:                // 出来上がったのを差し替える
                    127:                $insttable = $inst2table;
                    128:        } while ($expanded);
                    129: 
                    130:        // デバッグ表示
                    131:        if (0) {
                    132:                print "expand\n";
                    133:                foreach ($insttable as $inst) {
                    134:                        printf("%s| %s|%s\n",
                    135:                                $inst["bits12"], $inst["bits"], $inst["name"]);
                    136:                }
                    137:        }
                    138: 
                    139:        return $insttable;
                    140: }
                    141: 
                    142: // $insttable を12ビット(4096個)の $op12table に展開。
                    143: // $optable = array(
                    144: //     0 => &$inst0,
                    145: //     1 => &$inst1,
                    146: //     :
1.1.1.2   root      147: // 命令の存在するところだけ埋められる。
1.1       root      148: // )
                    149: function makeop12($insttable)
                    150: {
                    151:        global $op12table;
                    152: 
                    153:        $op12table = array();
                    154:        foreach ($insttable as $inst) {
                    155:                $num12 = bindec($inst["bits12"]);
                    156:                $op12table[$num12] = $inst;
                    157:        }
                    158: 
                    159:        // デバッグ表示
                    160:        if (0) {
                    161:                print "makeop12\n";
                    162:                for ($i = 0; $i < 4096; $i++) {
                    163:                        $b = str_repeat("0", 11) . decbin($i);
                    164:                        $b = substr($b, -12);
                    165:                        printf("%03x|%s|", $i, $b);
                    166: 
                    167:                        if (isset($op12table[$i])) {
                    168:                                $inst = $op12table[$i];
                    169:                                print "{$inst["bits"]}|{$inst["name"]}\n";
                    170:                        } else {
                    171:                                print "illegal\n";
                    172:                        }
                    173:                }
                    174:        }
                    175: }
                    176: 
                    177: // op12table から op12hash を作成
                    178: // op12table は [4096] => array(inst, inst, ...)
                    179: // op12hash は [name] => name のハッシュで、実際に使われてる関数名一覧。
                    180: function makeop12hash()
                    181: {
                    182:        global $op12table;
                    183:        global $op12hash;
                    184: 
                    185:        $op12hash = array();
                    186:        foreach ($op12table as $inst) {
                    187:                $name = $inst["name"];
                    188:                $op12hash[$name] = $name;
                    189:        }
                    190: }
                    191: 
                    192: // ディスパッチャ用の computed-goto 本体とソースの元を出力
                    193: function output_goto()
                    194: {
                    195:        global $insttable;
                    196:        global $op12table;
                    197:        global $op12hash;
                    198: 
                    199:        $out = "";
                    200:        $cpp = "";
                    201: 
                    202:        // ジャンプテーブルを作成
                    203:        $out = "\t\tstatic const void *jumptable[] = {\n";
                    204:        for ($i = 0; $i < 4096; $i++) {
                    205:                $bits12 = str_repeat("0", 11) . decbin($i);
                    206:                $bits12 = preg_replace("/.*(......)(......)/", "$1_$2", $bits12);
                    207:                $name = isset($op12table[$i]) ? $op12table[$i]["name"] : "illegal";
                    208:                $out .= sprintf("\t\t\t/* %%%s */ &&label_goto_%s,\n",
                    209:                        $bits12, $name);
                    210:        }
                    211:        $out .= "\t\t};\n";
                    212:        $out .= "\t\tJUMP;\n";
                    213:        foreach ($op12hash as $name) {
                    214:                $out .= "\t label_goto_{$name}:\n";
                    215:                $out .= "\t\tOP_FUNC({$name});\n";
                    216:                $out .= "\t\tCHECK_AND_JUMP;\n";
                    217: 
                    218:                // name から $inst を引く。うーん。
                    219:                $inst = array();
                    220:                foreach ($insttable as $i) {
                    221:                        if ($i["name"] == $name) {
                    222:                                $inst = $i;
                    223:                                break;
                    224:                        }
                    225:                }
                    226: 
                    227:                $text = "";
                    228:                if ($inst["text"] != "") {
                    229:                        $text = "\t{$inst["text"]}";
                    230:                }
                    231: 
                    232:                // ソース
                    233:                $cpp .= <<<__EOM__
                    234: // {$inst["bits"]}{$text}
                    235: OP_DEF({$name})
                    236: {
                    237:        OP_FUNC(unimpl);
                    238: }
                    239: 
                    240: 
                    241: __EOM__;
                    242:        }
                    243: 
                    244:        // 不当命令ブロックを出力
                    245:        $out .= "\t label_goto_illegal:\n";
                    246:        $out .= "\t\tOP_FUNC(illegal);\n";
                    247:        $out .= "\t\tCHECK_AND_JUMP;\n";
                    248: 
                    249:        // ファイルに出力
                    250:        write_file("goto.inc.new", $out);
                    251:        write_file("ops.cpp.new", $cpp);
                    252: }
                    253: 
                    254: // disasm 用の switch-case 文を出力
                    255: function output_switch()
                    256: {
                    257:        global $op12table;
                    258: 
                    259:        // func2 は [1024] => name 形式で不当命令ブロックを抜いたもの
                    260:        $func2 = array();
                    261:        foreach ($op12table as $i => $inst) {
                    262:                $func2[$i] = $inst["name"];
                    263:        }
                    264: 
                    265:        $out = "";
                    266:        for ($i = 0; $i < 4096; $i++) {
                    267:                if (!isset($func2[$i])) {
                    268:                        continue;
                    269:                }
                    270:                $funcname = $func2[$i];
                    271: 
                    272:                $cases = array();
                    273:                // この関数名を持つブロックに属する人全員のコメント集める。
                    274:                // このブロック自身もここで集計するため $j は $i から始める。
                    275:                for ($j = $i; $j < 4096; $j++) {
                    276:                        if (isset($func2[$j]) && $func2[$j] == $funcname) {
                    277:                                // case
                    278:                                $cases[] = $j;
                    279: 
                    280:                                // 今のところコメントはないのでスルー
                    281: 
                    282:                                // 集計したら消す
                    283:                                unset($func2[$j]);
                    284:                        }
                    285:                }
                    286: 
                    287:                // case 部分の出力
                    288:                // 4個くらいまでなら case 文を羅列、
                    289:                // それ以上連続してたら範囲で出力。
                    290:                $cont = true;
                    291:                for ($k = 1; $k < count($cases); $k++) {
                    292:                        if ($cases[$k] - $cases[$k - 1] != 1) {
                    293:                                $cont = false;
                    294:                                break;
                    295:                        }
                    296:                }
                    297:                if ($cont == true && count($cases) > 4) {
                    298:                        $c = array_shift($cases);
                    299:                        $bits12 = str_repeat("0", 11) . decbin($c);
                    300:                        $bits12 = preg_replace("/.*(......)(......)/", "$1_$2", $bits12);
                    301:                        $out .= sprintf("\t case 0x%03x", $c);
                    302:                        $out .= "\t// {$bits12}\n";
                    303: 
                    304:                        $c = array_pop($cases);
                    305:                        $bits12 = str_repeat("0", 11) . decbin($c);
                    306:                        $bits12 = preg_replace("/.*(......)(......)/", "$1_$2", $bits12);
                    307:                        $out .= sprintf("\t  ... 0x%03x:", $c);
                    308:                        $out .= "\t// {$bits12}\n";
                    309:                } else {
                    310:                        foreach ($cases as $c) {
                    311:                                $bits12 = str_repeat("0", 11) . decbin($c);
                    312:                                $bits12 = preg_replace("/.*(......)(......)/", "$1_$2",$bits12);
                    313:                                $out .= sprintf("\t case 0x%03x:", $c);
                    314:                                $out .= "\t// {$bits12}\n";
                    315:                        }
                    316:                }
                    317:                // 関数
                    318:                $out .= "\t\tOP_FUNC({$funcname});\n";
                    319:                $out .= "\t\tbreak;\n";
                    320:        }
                    321:        write_file("switch.inc.new", $out);
                    322: }
                    323: 
                    324: // ヘッダを出力
                    325: function output_header()
                    326: {
                    327:        global $op12hash;
                    328: 
                    329:        $out = "";
                    330:        foreach ($op12hash as $name) {
                    331:                $out .= "OP_PROTO({$name});\n";
                    332:        }
                    333: 
                    334:        // ファイルに出力
                    335:        write_file("ops.h.new", $out);
                    336: }
1.1.1.3 ! root      337: 
1.1       root      338: // ファイル出力
                    339: function write_file($filename, $str)
                    340: {
                    341:        $fp = fopen($filename, "w");
                    342:        fwrite($fp, $str);
                    343:        fclose($fp);
                    344: 
                    345:        print "Output: {$filename}\n";
                    346: }
1.1.1.3 ! root      347: ?>

unix.superglobalmegacorp.com

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