File:  [Isaki's NoNo m68k/m88k emulator] / nono / m88xx0 / gentable.php
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:47 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, HEAD
nono 1.5.0

<?php
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

	if ($argc < 2) {
		usage();
	}

	$insttable = read_instructions("instructions.txt");
	$insttable = expand($insttable);
	makeop12($insttable);
	makeop12hash();
	output_cpp();
	output_switch();
	output_header();
	exit(0);
?>
<?php
function usage()
{
	global $argv;

	print "Usage: ${argv[0]}\n";
	exit(1);
}


// instructions.txt を読み込んで $insttable[] 配列にする
function read_instructions($filename)
{
	$fp = fopen($filename, "r");
	if ($fp === false) {
		print "fopen failed: {$filename}\n";
		exit(1);
	}

	$insttable = array();

	while (($line = fgets($fp))) {
		$line = trim(preg_replace("/;.*/", "", $line));
		if ($line == "") {
			continue;
		}

		// 1行はこんな感じ
		// 000000_DDDDD_SSSSS_nnnnnn_nnnnnnnnnn	ld_d_xrf	ld.d(XRF)
		// 列は1つ以上のタブで区切られている。
		// $bits … ビットパターン
		// $name … 関数名
		// $text … コメント

		$column = preg_split("/\t+/", $line, -1, PREG_SPLIT_NO_EMPTY);
		$bits = $column[0];
		$name = $column[1];
		$text = isset($column[2]) ? $column[2] : "";

		$name = trim($name);
		$text = trim($text);

		// 命令ワード32ビットは 6-5-5 6-5-5 ビットに分解でき、ここでは
		// 上位下位ハーフワードの上位6ビットずつを合わせた12ビットを使う。
		$bits12 = preg_replace("/(......)_.........._(......)_........../",
			"$1$2", $bits);
		$bits12 = preg_replace("/[^10n]/", "n", $bits12);
		$newinst = array(
			"bits" => $bits,
			"bits12" => $bits12,
			"name" => $name,
			"text" => $text,
		);
		// $insttable[] に追加する。
		// ただし bits が同じものがあれば text だけ追加。
		if (isset($insttable[$bits])) {
			$insttable[$bits]["text"] .= ";{$text}";
		} else {
			$insttable[$bits] = $newinst;
		}
	}
	fclose($fp);

	// デバッグ表示
	if (0) {
		print "read_instruction\n";
		foreach ($insttable as $inst) {
			printf("%s|%s|%-10s|%s\n",
				$inst["bits"], $inst["bits12"], $inst["name"], $inst["text"]);
		}
	}

	return $insttable;
}

// $insttable を bit12 で展開する。
// これで bits12 には未確定部分がなくなる。
function expand($insttable)
{
	do {
		$expanded = false;
		$inst2table = array();
		foreach ($insttable as $inst) {
			if (preg_match("/^([01]*)n(.*)/", $inst["bits12"], $m)) {
				// $m[1] は先頭から確定部分
				// $m[2] が未処理部分

				$inst2table[] = array(
					"bits" => $inst["bits"],
					"bits12" => "{$m[1]}0{$m[2]}",
					"name" => $inst["name"],
					"text" => $inst["text"],
				);
				$inst2table[] = array(
					"bits" => $inst["bits"],
					"bits12" => "{$m[1]}1{$m[2]}",
					"name" => $inst["name"],
					"text" => $inst["text"],
				);
				$expanded = true;
			} else {
				$inst2table[] = $inst;
			}
		}

		// 出来上がったのを差し替える
		$insttable = $inst2table;
	} while ($expanded);

	// デバッグ表示
	if (0) {
		print "expand\n";
		foreach ($insttable as $inst) {
			printf("%s| %s|%s\n",
				$inst["bits12"], $inst["bits"], $inst["name"]);
		}
	}

	return $insttable;
}

// $insttable を12ビット(4096個)の $op12table に展開。
// $optable = array(
//	0 => &$inst0,
//	1 => &$inst1,
//	:
// 命令の存在するところだけ埋められる。
// )
function makeop12($insttable)
{
	global $op12table;

	$op12table = array();
	foreach ($insttable as $inst) {
		$num12 = bindec($inst["bits12"]);
		$op12table[$num12] = $inst;
	}

	// デバッグ表示
	if (0) {
		print "makeop12\n";
		for ($i = 0; $i < 4096; $i++) {
			$b = str_repeat("0", 11) . decbin($i);
			$b = substr($b, -12);
			printf("%03x|%s|", $i, $b);

			if (isset($op12table[$i])) {
				$inst = $op12table[$i];
				print "{$inst["bits"]}|{$inst["name"]}\n";
			} else {
				print "illegal\n";
			}
		}
	}
}

// op12table から op12hash を作成
// op12table は [4096] => array(inst, inst, ...)
// op12hash は [name] => name のハッシュで、実際に使われてる関数名一覧。
function makeop12hash()
{
	global $op12table;
	global $op12hash;

	$op12hash = array();
	foreach ($op12table as $inst) {
		$name = $inst["name"];
		$op12hash[$name] = $name;
	}
}

// ソースの雛形を出力
function output_cpp()
{
	global $insttable;
	global $op12table;
	global $op12hash;

	$cpp = "";

	foreach ($op12hash as $name) {
		// name から $inst を引く。うーん。
		$inst = array();
		foreach ($insttable as $i) {
			if ($i["name"] == $name) {
				$inst = $i;
				break;
			}
		}

		$text = "";
		if ($inst["text"] != "") {
			$text = "\t{$inst["text"]}";
		}

		// ソース
		$cpp .= <<<__EOM__
// {$inst["bits"]}{$text}
OP_DEF({$name})
{
	OP_FUNC(unimpl);
}


__EOM__;
	}

	// ファイルに出力
	write_file("ops.cpp.new", $cpp);
}

// disasm 用の switch-case 文を出力
function output_switch()
{
	global $op12table;

	// func2 は [1024] => name 形式で不当命令ブロックを抜いたもの
	$func2 = array();
	foreach ($op12table as $i => $inst) {
		$func2[$i] = $inst["name"];
	}

	$out = "";
	for ($i = 0; $i < 4096; $i++) {
		if (!isset($func2[$i])) {
			continue;
		}
		$funcname = $func2[$i];

		$cases = array();
		// この関数名を持つブロックに属する人全員のコメント集める。
		// このブロック自身もここで集計するため $j は $i から始める。
		for ($j = $i; $j < 4096; $j++) {
			if (isset($func2[$j]) && $func2[$j] == $funcname) {
				// case
				$cases[] = $j;

				// 今のところコメントはないのでスルー

				// 集計したら消す
				unset($func2[$j]);
			}
		}

		// case 部分の出力
		// 4個くらいまでなら case 文を羅列、
		// それ以上連続してたら範囲で出力。
		$cont = true;
		for ($k = 1; $k < count($cases); $k++) {
			if ($cases[$k] - $cases[$k - 1] != 1) {
				$cont = false;
				break;
			}
		}
		if ($cont == true && count($cases) > 4) {
			$c = array_shift($cases);
			$bits12 = str_repeat("0", 11) . decbin($c);
			$bits12 = preg_replace("/.*(......)(......)/", "$1_$2", $bits12);
			$out .= sprintf("\t case 0x%03x", $c);
			$out .= "\t// {$bits12}\n";

			$c = array_pop($cases);
			$bits12 = str_repeat("0", 11) . decbin($c);
			$bits12 = preg_replace("/.*(......)(......)/", "$1_$2", $bits12);
			$out .= sprintf("\t  ... 0x%03x:", $c);
			$out .= "\t// {$bits12}\n";
		} else {
			foreach ($cases as $c) {
				$bits12 = str_repeat("0", 11) . decbin($c);
				$bits12 = preg_replace("/.*(......)(......)/", "$1_$2",$bits12);
				$out .= sprintf("\t case 0x%03x:", $c);
				$out .= "\t// {$bits12}\n";
			}
		}
		// 関数
		$out .= "\t\tOP_FUNC({$funcname});\n";
		$out .= "\t\tbreak;\n";
	}
	write_file("switch.inc.new", $out);
}

// ヘッダを出力
function output_header()
{
	global $op12hash;

	$out = "";
	foreach ($op12hash as $name) {
		$out .= "OP_PROTO({$name});\n";
	}

	// ファイルに出力
	write_file("ops.h.new", $out);
}

// ファイル出力
function write_file($filename, $str)
{
	$fp = fopen($filename, "w");
	fwrite($fp, $str);
	fclose($fp);

	print "Output: {$filename}\n";
}
?>

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.