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