|
|
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.