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