|
|
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: ?>
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.