|
|
1.1 root 1: <?php
2: //
3: // nono
4: // Copyright (C) 2014 [email protected]
5: //
6: // gentable.php
7: // inst*.txt からディスパッチャ部分を生成
8: //
9: // switch10 switch-case (10bit) を出力
10: // switch13 switch-case (13bit) を出力
11: // goto10 computed goto (10bit) を出力
12: // mmu8 MMU の switch-case (8bit) を出力
13: //
14:
15: if ($argc < 2) {
16: usage();
17: }
18:
19: init_ea();
20: $mputype = 3;
21: switch ($argv[1]) {
22: case "switch10":
23: case "switch13":
24: case "goto10":
25: if (preg_match("/10$/", $argv[1])) {
26: $nb = 10;
27: } else {
28: $nb = 13;
29: }
30: $insttable = read_instructions($mputype, "instructions.txt");
31: $insttable = expandDST($insttable);
32: $insttable = expandSS($insttable);
33: $insttable = expandCond($insttable);
34: makeop16($insttable);
35: $op10table = makeop10table();
36: $op10func = makeop10func($op10table);
37: $op10hash = makeop10hash($op10func);
38: if (preg_match("/switch/", $argv[1])) {
39: output_switch($op10table, $op10func);
40: } else {
41: output_goto($op10table, $op10func);
42: }
43: output_header($op10hash);
44: break;
45:
46: case "mmu8":
47: $nb = 8;
48: $insttable = read_instructions($mputype, "instmmu.txt");
49: makeop16($insttable);
50: $op10table = makeop10table();
51: $op10func = makeop10func($op10table);
52: $op10hash = makeop10hash($op10func);
53: output_switch($op10table, $op10func);
54: output_header($op10hash);
55: break;
56: default:
57: usage();
58: }
59: exit(0);
60: ?>
61: <?php
62: function usage()
63: {
64: global $argv;
65:
66: print "Usage: {$argv[0]} switch10 | switch13\n";
67: print " input: instruction.txt\n";
68: print " output: switch.h.new, ops.cpp.new, ops.h.new\n";
69: print "Usage: {$argv[0]} mmu8\n";
70: print " input: instmmu.txt\n";
71: print " output: \n";
72: print "Usage: {$argv[0]} goto10\n";
73: print " input: instruction.txt\n";
74: print " output: goto.h.new, ops.cpp.new, ops.h.new\n";
75: exit(1);
76: }
77:
78: function init_ea()
79: {
80: global $ambits;
81:
82: // アドレッシングモードの展開パターン
83: $ambits = array(
84: "d" => "000rrr",
85: "a" => "001rrr",
86: "m" => "010rrr",
87: "+" => "011rrr",
88: "-" => "100rrr",
89: "r" => "101rrr",
90: "x" => "110rrr",
91: "w" => "11100r",
92: "p" => "11101r",
93: "i" => "111100",
94: );
95: }
96:
97: // instructions.txt を読み込んで $insttable[] 配列にする
98: function read_instructions($mputype, $filename)
99: {
100: $fp = fopen($filename, "r");
101: if ($fp === false) {
102: print "fopen failed: {$filename}\n";
103: exit(1);
104: }
105:
106: $insttable = array();
107:
108: while (($line = fgets($fp))) {
109: $line = trim(preg_replace("/;.*/", "", $line));
110: if ($line == "") {
111: continue;
112: }
113:
114: // 1行はこんな感じ
115: // 00000000SSmmmrrr d.m+-rxw.. 034 ori_S ORI.S #<imm>,<ea>
116: // 列は1つ以上のタブで区切られている。
117: // $bits … 1ワード目のビットパターン
118: // $addr … 対応しているアドレッシングモード
119: // $mpu … MPU ごとのサポート有無
120: // $name … 関数名
121: // $text … コメント
122:
123: list ($bits, $addr, $mpu, $name, $text) =
124: preg_split("/\t+/", $line, -1, PREG_SPLIT_NO_EMPTY);
125: $name = trim($name);
126: $text = trim($text);
127:
128: // ターゲット CPU の命令のみ対象にする
129: if (preg_match("/{$mputype}/", $mpu) == false) {
130: continue;
131: }
132:
133: $newinst = array(
134: "bits" => $bits,
135: "addr" => $addr,
136: "mpu" => $mpu,
137: "name" => $name,
138: "text" => $text,
139: );
140: // $insttable[] に追加する。
141: // ただし bits が同じものがあれば text だけ追加。
142: if (isset($insttable[$bits])) {
143: $insttable[$bits]["text"] .= ";{$text}";
144: } else {
145: $insttable[$bits] = $newinst;
146: }
147: }
148: fclose($fp);
149:
150: // デバッグ表示
151: if (0) {
152: print "read_instruction\n";
153: foreach ($insttable as $inst) {
154: printf("%s|%s|%-14s|%s\n",
155: $inst["bits"], $inst["addr"], $inst["name"], $inst["text"]);
156: }
157: }
158:
159: return $insttable;
160: }
161:
162: // $insttable のうち MOVE の DST を展開する
163: function expandDST($insttable)
164: {
165: $dst = array(
166: array("xxx000", "dn", "Dx"),
167: array("xxx010", "anin", "(Ax)"),
168: array("xxx011", "anpi", "(Ax)+"),
169: array("xxx100", "anpd", "-(Ax)"),
170: array("xxx101", "andi", "d16(Ax)"),
171: array("xxx110", "anix", "(Ax,IX)"),
172: array("000111", "absw", "Abs.W"),
173: array("001111", "absl", "Abs.L"),
174: );
175: $inst2table = array();
176: foreach ($insttable as $inst) {
177: if (preg_match("/RRRMMM/", $inst["bits"])) {
178: foreach ($dst as $d) {
179: $inst2 = $inst;
180: $inst2["bits"] = preg_replace("/RRRMMM/", $d[0], $inst["bits"]);
181: $inst2["name"] = preg_replace("/DD/", $d[1], $inst["name"]);
182: $inst2["text"] = preg_replace("/DD/", $d[2], $inst["text"]);
183:
184: $inst2table[] = $inst2;
185: }
186: } else {
187: $inst2table[] = $inst;
188: }
189: }
190:
191: // デバッグ表示
192: if (0) {
193: print "expandDST\n";
194: foreach ($inst2table as $inst) {
195: printf("%s|%s|%-14s|%s\n",
196: $inst["bits"], $inst["addr"], $inst["name"], $inst["text"]);
197: }
198: }
199:
200: return $inst2table;
201: }
202:
203: // $insttable の SS と s を展開する
204: // これらは必ず上位10ビット内にあるので (というか下位6ビット以内に現れる
205: // やつはテキストにする時点で手動で展開してあるので)、
206: // サイズ別の関数に展開できる。
207: function expandSS($insttable)
208: {
209: $s3 = array(
210: array("00", "_b", ".B"),
211: array("01", "_w", ".W"),
212: array("10", "_l", ".L"),
213: );
214: $s2 = array(
215: array("0", "_w", ".W"),
216: array("1", "_l", ".L"),
217: );
218:
219: $inst2table = array();
220: foreach ($insttable as $inst) {
221: if (preg_match("/SS/", $inst["bits"])) {
222: foreach ($s3 as $s) {
223: $inst2 = $inst;
224: $inst2["bits"] = preg_replace("/SS/", $s[0], $inst["bits"]);
225: $inst2["name"] = preg_replace("/_S/", $s[1], $inst["name"]);
226: $inst2["text"] = preg_replace("/\.S/", $s[2], $inst["text"]);
227:
228: $inst2table[] = $inst2;
229: }
230: } else if (preg_match("/s/", $inst["bits"])) {
231: foreach ($s2 as $s) {
232: $inst2 = $inst;
233: $inst2["bits"] = preg_replace("/s/", $s[0], $inst["bits"]);
234: $inst2["name"] = preg_replace("/_S/", $s[1], $inst["name"]);
235: $inst2["text"] = preg_replace("/\.S/", $s[2], $inst["text"]);
236:
237: $inst2table[] = $inst2;
238: }
239: } else {
240: $inst2table[] = $inst;
241: }
242: }
243:
244: // デバッグ表示
245: if (0) {
246: print "expandSS\n";
247: foreach ($inst2table as $inst) {
248: printf("%s|%s|%-14s|%s\n",
249: $inst["bits"], $inst["addr"], $inst["name"], $inst["text"]);
250: }
251: }
252:
253: return $inst2table;
254: }
255:
256: // $insttable の cccc を展開する。
257: function expandCond($insttable)
258: {
259: $cccc = array(
260: "0000" => "t",
261: "0001" => "f",
262: "0010" => "hi",
263: "0011" => "ls",
264: "0100" => "cc",
265: "0101" => "cs",
266: "0110" => "ne",
267: "0111" => "eq",
268: "1000" => "vc",
269: "1001" => "vs",
270: "1010" => "pl",
271: "1011" => "mi",
272: "1100" => "ge",
273: "1101" => "lt",
274: "1110" => "gt",
275: "1111" => "le",
276: );
277: $inst2table = array();
278: foreach ($insttable as $inst) {
279: if (preg_match("/cccc/", $inst["bits"])) {
280: foreach ($cccc as $cbit => $cname) {
281: $uname = strtoupper($cname);
282: $inst2 = $inst;
283: $inst2["bits"] = preg_replace("/cccc/", $cbit, $inst["bits"]);
284: $inst2["name"] = preg_replace("/cc/", $cname, $inst["name"]);
285: $inst2["text"] = preg_replace("/cc/", $uname, $inst["text"]);
286: $inst2table[] = $inst2;
287: }
288: } else {
289: $inst2table[] = $inst;
290: }
291: }
292:
293: // デバッグ表示
294: if (0) {
295: print "expandCond\n";
296: foreach ($inst2table as $inst) {
297: printf("%s|%s|%-14s|%s\n",
298: $inst["bits"], $inst["addr"], $inst["name"], $inst["text"]);
299: }
300: }
301:
302: return $inst2table;
303: }
304:
305: // insttable を16ビットの op16table に展開。
306: // $optable = array(
307: // 0 => &$inst0,
308: // 1 => &$inst1, ...
309: // )
310: function makeop16($insttable)
311: {
312: global $op16table;
313:
314: $op16table = array();
315:
316: foreach ($insttable as $inst) {
317: makeop16_sub($inst, $inst["bits"]);
318: }
319:
320: // デバッグ表示
321: if (0) {
322: print "makeop16\n";
323: for ($i = 0; $i < 65536; $i++) {
324: $b = str_repeat("0", 15) . decbin($i);
325: $b = substr($b, -16);
326: printf("%04x|%s|", $i, $b);
327:
328: if (isset($op16table[$i])) {
329: $inst = $op16table[$i];
330: printf("%s|%-14s|%s\n",
331: $inst["bits"], $inst["name"], $inst["text"]);
332: } else {
333: printf("illegal\n");
334: }
335: }
336: }
337: }
338:
339: // inst を1ビットずつ展開する再帰関数
340: // lv は再帰レベル (デバッグ用)
341: function makeop16_sub($inst, $bits, $lv = 0)
342: {
343: global $op16table;
344: global $ambits;
345:
346: // $pos は bits の 0/1 でない最初の文字の位置
347: $pos = strspn($bits, "01");
348: if ($pos == 16) {
349: // 0/1 しか現れていないので確定
350: // $optable に代入
351: $num16 = bindec($bits);
352: $op16table[$num16] = $inst;
353: } else if (substr($bits, 10) == "mmmrrr") {
354: // アドレッシングモードによって展開 (いるかな?)
355: $head = substr($bits, 0, 10);
356: for ($i = 0; $i < strlen($inst["addr"]); $i++) {
357: $a = substr($inst["addr"], $i, 1);
358: if (isset($ambits[$a])) {
359: makeop16_sub($inst, "{$head}{$ambits[$a]}", $lv + 1);
360: }
361: }
362: } else {
363: // pos 番目の文字を 0 と 1 に変えて再帰実行
364: $head = substr($bits, 0, $pos);
365: $tail = substr($bits, $pos + 1);
366: makeop16_sub($inst, "{$head}0{$tail}", $lv + 1);
367: makeop16_sub($inst, "{$head}1{$tail}", $lv + 1);
368: }
369: }
370:
371: // 16ビットテーブルから $nb (10 or 7) ビットテーブルを作成
372: function makeop10table()
373: {
374: global $op16table;
375: global $nb;
376:
377: // 1ブロックあたりの命令数 ($nb=10 なら 64)
378: $ipb = 2 ** (16 - $nb);
379:
380: $op10table = array();
381: for ($i = 0; $i < 2 ** $nb; $i++) {
382: $op10table[$i] = array();
383: }
384:
385: for ($i = 0; $i < 65536; $i++) {
386: if (!isset($op16table[$i])) {
387: continue;
388: }
389: $inst = $op16table[$i];
390: $j = $i / $ipb;
391:
392: // op10table[j][] にすでに同じエントリがなければ、追加
393: $found = false;
394: foreach ($op10table[$j] as $ji) {
395: if ($inst["bits"] == $ji["bits"]) {
396: $found = true;
397: break;
398: }
399: }
400: if (!$found) {
401: $op10table[$j][] = $inst;
402: }
403: }
404:
405: // デバッグ用
406: if (0) {
407: print "makeop10table\n";
408: foreach ($op10table as $j => $arr) {
409: printf("0x%04x|", $j, $j * $ipb);
410: foreach ($arr as $inst) {
411: printf(" %s", $inst["name"]);
412: }
413: print "\n";
414: }
415: }
416:
417: return $op10table;
418: }
419:
420: // op10table から op10func を作成
421: // op10table は [1024] => array(inst, inst, ...)
422: // op10func は [1024] => 代表name
423: function makeop10func($op10table)
424: {
425: global $nb;
426:
427: $op10func = array();
428: for ($i = 0; $i < 2 ** $nb; $i++) {
429: $op10func[$i] = "";
430: }
431:
432: foreach ($op10table as $i => $arr) {
433: if (count($arr) == 0) {
434: $op10func[$i] = "illegal";
435: continue;
436: }
437:
438: // 代表関数はこのブロックの中で最多数なもの。
439: $funcname = "";
440: $minbits = (16 - $nb) + 1;
441: foreach ($arr as $inst) {
442: // fixed は bits の末尾(16-nb)ビットのうち "0" と "1" の合計数
443: $chs = count_chars(substr($inst["bits"], $nb), 0);
444: $fixed = $chs[0x30] + $chs[0x31];
445: // fixed が小さい = 出力した命令の総数が大きい、なので採用
446: if ($minbits > $fixed) {
447: $minbits = $fixed;
448: $funcname = $inst["name"];
449: }
450: }
451:
452: $op10func[$i] = $funcname;
453: }
454:
455: // デバッグ用
456: if (0) {
457: print "makeop10func\n";
458: foreach ($op10func as $i => $name) {
459: printf("[%4d] %04x {$name}\n", $i, $i * 64);
460: }
461: }
462:
463: return $op10func;
464: }
465:
466: // op10hash は [代表name] => 代表name のハッシュ
467: // 実際に使われてる関数名一覧になる。
468: function makeop10hash($op10func)
469: {
470: $op10hash = array();
471: foreach ($op10func as $name) {
472: $op10hash[$name] = $name;
473: }
474:
475: return $op10hash;
476: }
477:
478: // switch 本体とソースの元を出力
479: function output_switch($op10table, $op10func)
480: {
481: global $nb;
482:
483: $shift = 16 - $nb;
484: $ipb = 2 ** (16 - $nb);
485:
486: $func2 = $op10func;
487:
488: // 先に不当命令ブロックだけ抜いておく
489: $illegals = array();
490: for ($i = 0; $i < 2 ** $nb; $i++) {
491: if (isset($func2[$i]) && $func2[$i] == "illegal") {
492: $illegals[$i] = $i;
493: unset($func2[$i]);
494: }
495: }
496:
497: $out = "";
498: $cpp = "";
499: for ($i = 0; $i < 2 ** $nb; $i++) {
500: if (!isset($func2[$i])) {
501: continue;
502: }
503: $funcname = $func2[$i];
504:
505: $cases = array();
506: $comments = array();
507:
508: // この関数名をもつブロックに属する人全員のコメントを集める。
509: // このブロック自身もここで集計するため $j は $i から始める。
510: for ($j = $i; $j < 2 ** $nb; $j++) {
511: if (isset($func2[$j]) && $func2[$j] == $funcname) {
512: foreach ($op10table[$j] as $inst) {
513: // case
514: $cases[$j] = $j;
515: // コメント
516: // 同一 bits に別の命令が割り当てられているケースは
517: // ここで2行のコメントに分解
518: foreach (split(";", $inst["text"]) as $text) {
519: $comm = "{$inst["bits"]}\t{$text}";
520: $comments[$comm] = $comm;
521: }
522: }
523: // 集計したら消す
524: unset($func2[$j]);
525: }
526: }
527: // case
528: foreach ($cases as $c) {
529: $out .= sprintf("\t case (0x%04x >> ${shift}):\n", $c * $ipb);
530: }
531: // コメント
532: foreach ($comments as $comm) {
533: if ($nb == 8) {
534: // というか MMU というべきか
535: preg_match("/(...)(.....)(...)(.*)/", $comm, $m);
536: $comm1 = "%{$m[1]}_{$m[2]}_{$m[3]}_{$m[4]}";
537: } else {
538: // 第1ワードというべきか
539: preg_match("/(....)(......)(.*)/", $comm, $m);
540: $comm1 = "%{$m[1]}_{$m[2]}_{$m[3]}";
541: }
542: $out .= "\t\t// {$comm1}\n";
543: $cpp .= "// {$comm1}\n";
544: }
545: // 関数
546: $out .= "\t\tOP_FUNC({$funcname});\n";
547: $out .= "\t\tbreak;\n";
548:
549: // ソース
550: $cpp .= output_func($funcname);
551: }
552:
553: // 不当命令ブロックを出力
554: foreach ($illegals as $i) {
555: $out .= sprintf("\t case (0x%04x >> ${shift}):\n", $i * $ipb);
556: }
557: $out .= "\t\tOP_FUNC(illegal);\n";
558: $out .= "\t\tbreak;\n";
559:
560: // 不当命令 (ILLEGAL 命令ではないので最終的にどうするかはある)
561: $cpp .= "// illegal instructions\n";
562: $cpp .= output_func("illegal");
563:
564: // ファイルに出力
565: write_file("switch.h.new", $out);
566: write_file("ops.cpp.new", $cpp);
567: }
568:
569: // computed-goto 本体とソースの元を出力
570: function output_goto($op10table, $op10func)
571: {
572: global $nb;
573:
574: $shift = 16 - $nb;
575: $ipb = 2 ** (16 - $nb);
576:
577: // ジャンプテーブルを作成
578: $table = "\t\tstatic const void *jumptable[] = {\n";
579: for ($i = 0; $i < 2 ** $nb; $i++) {
580: $table .= sprintf("\t\t\t/* $%04X */&&label_goto_%s,\n",
581: $i * $ipb, $op10func[$i]);
582: }
583: $table .= "\t\t};\n";
584:
585: $func2 = $op10func;
586:
587: // 先に不当命令ブロックだけ抜いておく
588: $illegals = array();
589: for ($i = 0; $i < 2 ** $nb; $i++) {
590: if (isset($func2[$i]) && $func2[$i] == "illegal") {
591: $illegals[$i] = $i;
592: unset($func2[$i]);
593: }
594: }
595:
596: $out = "";
597: $cpp = "";
598:
599: $out .= "\t\tJUMP;\n";
600:
601: for ($i = 0; $i < 2 ** $nb; $i++) {
602: if (!isset($func2[$i])) {
603: // 不当命令ブロック
604: continue;
605: }
606: $funcname = $func2[$i];
607:
608: $cases = array();
609: $comments = array();
610:
611: // この関数名をもつブロックに属する人全員のコメントを集める。
612: // このブロック自身もここで集計するため $j は $i から始める。
613: for ($j = $i; $j < 2 ** $nb; $j++) {
614: if (isset($func2[$j]) && $func2[$j] == $funcname) {
615: foreach ($op10table[$j] as $inst) {
616: // case
617: $cases[$j] = $j;
618: // コメント
619: // 同一 bits に別の命令が割り当てられているケースは
620: // ここで2行のコメントに分解
621: foreach (split(";", $inst["text"]) as $text) {
622: $comm = "{$inst["bits"]}\t{$text}";
623: $comments[$comm] = $comm;
624: }
625: }
626: // 集計したら消す
627: unset($func2[$j]);
628: }
629: }
630: // ラベル
631: $out .= "\t label_goto_{$funcname}:\n";
632: // コメント
633: foreach ($comments as $comm) {
634: if ($nb == 8) {
635: // というか MMU というべきか
636: preg_match("/(...)(.....)(...)(.*)/", $comm, $m);
637: $comm1 = "%{$m[1]}_{$m[2]}_{$m[3]}_{$m[4]}";
638: } else {
639: // 第1ワードというべきか
640: preg_match("/(....)(......)(.*)/", $comm, $m);
641: $comm1 = "%{$m[1]}_{$m[2]}_{$m[3]}";
642: }
643: $out .= "\t\t// {$comm1}\n";
644: $cpp .= "// {$comm1}\n";
645: }
646: // 関数
647: $out .= "\t\tOP_FUNC({$funcname});\n";
648: $out .= "\t\tCHECK_AND_JUMP;\n";
649:
650: // ソース
651: $cpp .= output_func($funcname);
652: }
653:
654: // 不当命令ブロックを出力
655: $out .= "\t label_goto_illegal:\n";
656: $out .= "\t\tOP_FUNC(illegal);\n";
657: $out .= "\t\tCHECK_AND_JUMP;\n";
658:
659: // ファイルに出力
660: write_file("goto.h.new", $table . $out);
661: write_file("ops.cpp.new", $cpp);
662: }
663:
664: // 関数ソースを出力
665: function output_func($name)
666: {
667: $cpp = "";
668: $cpp .= "OP_DEF({$name})\n";
669: $cpp .= "{\n";
670: $cpp .= "\tOP_FUNC(unimpl);\n";
671: $cpp .= "}\n";
672: $cpp .= "\n";
673:
674: return $cpp;
675: }
676:
677: // ヘッダを出力
678: function output_header($op10hash)
679: {
680: $out = "";
681: foreach ($op10hash as $name) {
682: $out .= "OP_PROTO({$name});\n";
683: }
684:
685: // ファイルに出力
686: write_file("ops.h.new", $out);
687: }
688:
689: // ファイル出力
690: function write_file($filename, $str)
691: {
692: $fp = fopen($filename, "w");
693: fwrite($fp, $str);
694: fclose($fp);
695:
696: print "Output: {$filename}\n";
697: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.