命令表

はじめて読むマシン語―ほんとうのコンピュータと出逢うために

はじめて読むマシン語―ほんとうのコンピュータと出逢うために

この本に紹介されている内容を実際に試してみるために、8bitマシンのエミュレータを作成しようとしています。


使用する言語はPHPで、PHPの学習もついで行います。


今までのところ、APPENDIXに記載されている、命令の1バイト目を解析するプログラムを作成しました。
以下、プログラムが生成した命令表。

HEX命令引数1引数2
00NOP
01LDBCM16
02LD(BC)A
03INCBC
04INCB
05DECB
06LDBM8
07ERROR
08ERR
09ADDHLBC
0ALDA(BC)
0BDECBC
0CINCC
0DDECC
0ELDCM8
0FERROR
10NOP
11LDDEM16
12LD(DE)A
13INCDE
14INCD
15DECD
16LDDM8
17ERROR
18ERR
19ADDHLDE
1ALDA(DE)
1BDECDE
1CINCE
1DDECE
1ELDEM8
1FERROR
20NOP
21LDHLM16
22LD(M16)HL
23INCHL
24INCH
25DECH
26LDHM8
27ERROR
28ERR
29ADDHLHL
2ALDHL(M16)
2BDECHL
2CINCL
2DDECL
2ELDLM8
2FCPL
30NOP
31LDSPM16
32LD(M16)A
33INCSP
34INC(HL)
35DEC(HL)
36LD(HL)M8
37SCF
38ERR
39ADDHLSP
3ALDA(M16)
3BDECSP
3CINCA
3DDECA
3ELDAM8
3FCCF
40LDBB
41LDBC
42LDBD
43LDBE
44LDBH
45LDBL
46LDB(HL)
47LDBA
48LDCB
49LDCC
4ALDCD
4BLDCE
4CLDCH
4DLDCL
4ELDC(HL)
4FLDCA
50LDDB
51LDDC
52LDDD
53LDDE
54LDDH
55LDDL
56LDD(HL)
57LDDA
58LDEB
59LDEC
5ALDED
5BLDEE
5CLDEH
5DLDEL
5ELDE(HL)
5FLDEA
60LDHB
61LDHC
62LDHD
63LDHE
64LDHH
65LDHL
66LDH(HL)
67LDHA
68LDLB
69LDLC
6ALDLD
6BLDLE
6CLDLH
6DLDLL
6ELDL(HL)
6FLDLA
70LD(HL)B
71LD(HL)C
72LD(HL)D
73LD(HL)E
74LD(HL)H
75LD(HL)L
76HALT
77LD(HL)A
78LDAB
79LDAC
7ALDAD
7BLDAE
7CLDAH
7DLDAL
7ELDA(HL)
7FLDAA
80ADDAB
81ADDAC
82ADDAD
83ADDAE
84ADDAH
85ADDAL
86ADDA(HL)
87ADDAA
88ADCAB
89ADCAC
8AADCAD
8BADCAE
8CADCAH
8DADCAL
8EADCA(HL)
8FADCAA
90SUBB
91SUBC
92SUBD
93SUBE
94SUBH
95SUBL
96SUB(HL)
97SUBA
98SBCAB
99SBCAC
9ASBCAD
9BSBCAE
9CSBCAH
9DSBCAL
9ESBCA(HL)
9FSBCAA
A0ANDB
A1ANDC
A2ANDD
A3ANDE
A4ANDH
A5ANDL
A6AND(HL)
A7ANDA
A8XORB
A9XORC
AAXORD
ABXORE
ACXORH
ADXORL
AEXOR(HL)
AFXORA
B0ORB
B1ORC
B2ORD
B3ORE
B4ORH
B5ORL
B6OR(HL)
B7ORA
B8CPB
B9CPC
BACPD
BBCPE
BCCPH
BDCPL
BECP(HL)
BFCPA
C0RETNZ
C1POPBC
C2JPNZM16
C3JPM16
C4CALLNZM16
C5PUSHBC
C6ADDAM8
C7JPM16
C8RETZ
C9RET
CAJPZM16
CBNE_RS
CCCALLZM16
CDCALLM16
CEADCAM8
CFNE_RS
D0RETNC
D1POPDE
D2JPNCM16
D3OUT(M8)A
D4CALLNCM16
D5PUSHDE
D6SUBM8
D7OUT(M8)A
D8RETC
D9ERR
DAJPCM16
DBINA(M8)
DCCALLCM16
DDCALLM16
DESBCAM8
DFINA(M8)
E0RETNZ
E1POPHL
E2JPNZM16
E3EX(SP)HL
E4CALLNZM16
E5PUSHHL
E6ANDM8
E7EXERRORHL
E8RETZ
E9JP(HL)
EAJPZM16
EBEXDEHL
ECCALLZM16
EDNE_ED
EEXORM8
EFEXERRORHL
F0RETNC
F1POPAF
F2JPNCM16
F3DI
F4CALLNCM16
F5PUSHAF
F6ORM8
F7DI
F8RETC
F9LDSPHL
FAJPCM16
FBEI
FCCALLCM16
FDNE_ED
FECPM8
FFEI
なお、上記の表についての注意点です:

  • 引数のM8とM16は、次の命令の内容から、それぞれ8bitデータと16ビットデータを取得するの意。
  • 命令のNE_〜は、次の命令も引き続き処理の判断に必要となる(2バイト命令)
  • 本の命令表に乗っていないコードに対する結果は未定義。


この表を生成したコードは以下です。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>ParseInst</title>
    </head>
    <body>

	<?php

	#$hex_ins = $_GET["instruction"]; 
	#echo "\$hex_ins:$hex_ins<br>";

	#$num_ins = hexdec( $hex_ins );
	#echo "\$num_ins:$num_ins<br>";

	#$parsed = parse_inst( $num_ins );
	#echo "\$parsed:$parsed<br>";


	echo "<table border=1>";
	echo "<tr>";
	echo "<th>HEX</th>";
	echo "<th>命令</th>";
	echo "<th>引数1</th>";
	echo "<th>引数2</th>";
	echo "</tr>";
	for ( $i = 0; $i < 256; ++$i ) {
		echo "<tr>";

		$tmp = "00" . strtoupper( dechex( $i ) );
		echo "<td>" . substr( $tmp, strlen( $tmp ) - 2 ) . "</td>";

		$inst = parse_inst( $i );

		echo "<td>" . $inst[0] . "</td>";
		echo "<td>" . $inst[1] . "</td>";
		echo "<td>" . $inst[2] . "</td>";

		echo "</tr>";
	}
	echo "</table>";
			
	function parse_inst( $target ) {
		try {
			if ( ( ( $target | 0x30 ) == 0x30 ) && ( ( $target & 0x00 ) == 0x00 ) ) return parse_nop( $target );
			if ( ( ( $target | 0x31 ) == 0x31 ) && ( ( $target & 0x01 ) == 0x01 ) ) return parse_ld_16_data( $target );
			if ( ( ( $target | 0x39 ) == 0x39 ) && ( ( $target & 0x09 ) == 0x09 ) ) return parse_add_hl_16( $target );
			if ( ( ( $target | 0x3A ) == 0x3A ) && ( ( $target & 0x02 ) == 0x02 ) ) return parse_ld_8_addr( $target );
			if ( ( ( $target | 0x3B ) == 0x3B ) && ( ( $target & 0x03 ) == 0x03 ) ) return parse_incdec_16( $target );
			if ( ( ( $target | 0x3D ) == 0x3D ) && ( ( $target & 0x04 ) == 0x04 ) ) return parse_incdec_8( $target );
			if ( ( ( $target | 0x3E ) == 0x3E ) && ( ( $target & 0x06 ) == 0x06 ) ) return parse_ld_8_data( $target );
			if ( ( ( $target | 0x76 ) == 0x76 ) && ( ( $target & 0x76 ) == 0x76 ) ) return parse_halt( $target );
			if ( ( ( $target | 0x7F ) == 0x7F ) && ( ( $target & 0x40 ) == 0x40 ) ) return parse_ld_8_8( $target );
			if ( ( ( $target | 0xBF ) == 0xBF ) && ( ( $target & 0x80 ) == 0x80 ) ) return parse_arilog_8( $target );
			if ( ( ( $target | 0xF8 ) == 0xF8 ) && ( ( $target & 0xC0 ) == 0xC0 ) ) return parse_ret_flg( $target );
			if ( ( ( $target | 0xE9 ) == 0xE9 ) && ( ( $target & 0xE9 ) == 0xE9 ) ) return parse_jp_hl( $target );
			if ( ( ( $target | 0xC9 ) == 0xC9 ) && ( ( $target & 0xC9 ) == 0xC9 ) ) return parse_ret( $target );
			if ( ( ( $target | 0xF1 ) == 0xF1 ) && ( ( $target & 0xC1 ) == 0xC1 ) ) return parse_pop_16( $target );
			if ( ( ( $target | 0xF9 ) == 0xF9 ) && ( ( $target & 0xF9 ) == 0xF9 ) ) return parse_ld_sp_hl( $target );
			if ( ( ( $target | 0xFA ) == 0xFA ) && ( ( $target & 0xC2 ) == 0xC2 ) ) return parse_jp_flg_data( $target );
			if ( ( ( $target | 0xC7 ) == 0xC7 ) && ( ( $target & 0xC3 ) == 0xC3 ) ) return parse_jp_data( $target );
			if ( ( ( $target | 0xCF ) == 0xCF ) && ( ( $target & 0xCB ) == 0xCB ) ) return parse_rotshf_8( $target );
			if ( ( ( $target | 0xDF ) == 0xDF ) && ( ( $target & 0xD3 ) == 0xD3 ) ) return parse_inout( $target );
			if ( ( ( $target | 0xFF ) == 0xFF ) && ( ( $target & 0xF3 ) == 0xF3 ) ) return parse_eidi( $target );
			if ( ( ( $target | 0xEF ) == 0xEF ) && ( ( $target & 0xE3 ) == 0xE3 ) ) return parse_ex( $target );
			if ( ( ( $target | 0xFC ) == 0xFC ) && ( ( $target & 0xC4 ) == 0xC4 ) ) return parse_call_flg_data( $target );
			if ( ( ( $target | 0xDD ) == 0xDD ) && ( ( $target & 0xCD ) == 0xCD ) ) return parse_call_data( $target );
			if ( ( ( $target | 0xF5 ) == 0xF5 ) && ( ( $target & 0xC5 ) == 0xC5 ) ) return parse_push_16( $target );
			if ( ( ( $target | 0xFD ) == 0xFD ) && ( ( $target & 0xED ) == 0xED ) ) return parse_ed_2byte( $target );
			if ( ( ( $target | 0xFE ) == 0xFE ) && ( ( $target & 0xC6 ) == 0xC6 ) ) return parse_arilog_data( $target );
			if ( ( ( $target | 0x3F ) == 0x3F ) && ( ( $target & 0x07 ) == 0x07 ) ) return parse_acu( $target );
		} catch ( ErrorException $e ) {
			return "ERROR";
		}

		return "ERROR";
	}


#START PARSE_INST
	function parse_nop( $target ) {
		return array( "NOP", "", "" );
	}
	function parse_ld_16_data( $target ) {
		return array( "LD", af_to_sp( decide_reg16_1( $target ) ), "M16" );
	}
	function parse_add_hl_16( $target ) {
		return array( "ADD", "HL", af_to_sp( decide_reg16_1( $target ) ) );
	}
	function parse_ld_8_addr( $target ) {
		return decide_ld_8_addr( $target, af_to_addr( ref_addr(decide_reg16_1( $target )) ) );
	}
	function parse_incdec_16( $target ) {
		return array( decide_incdec_16( $target ), af_to_sp( decide_reg16_1( $target ) ), "" );
	}
	function parse_incdec_8( $target ) {
		return array( decide_incdec_8( $target ), decide_reg8_1( $target ), "" );
	}
	function parse_ld_8_data( $target ) {
		return array( "LD", decide_reg8_1( $target ), "M8" );
	}
	function parse_halt( $target ) {
		return array( "HALT", "", "" );
	}
	function parse_ld_8_8( $target ) {
		return array( "LD", decide_reg8_1( $target ), decide_reg8_2( $target ) );
	}
	function parse_arilog_8( $target ) {
		return decide_arilog_8( $target, decide_reg8_2( $target ) );
	}
	function parse_ret_flg( $target ) {
		return array( "RET", decide_flg( $target ), "" );
	}
	function parse_jp_hl( $target ) {
		return array( "JP", ref_addr("HL"), "" );
	}
	function parse_ret( $target ) {
		return array( "RET", "", "" );
	}
	function parse_pop_16( $target ) {
		return array( "POP", decide_reg16_1( $target ), "" );
	}
	function parse_ld_sp_hl( $target ) {
		return array( "LD", "SP", "HL" );
	}
	function parse_jp_flg_data( $target ) {
		return array( "JP", decide_flg( $target ), "M16" );
	}
	function parse_jp_data( $target ) {
		return array( "JP", "M16", "" );
	}
	function parse_rotshf_8( $target ) {
		return array( "NE_RS", "", "" );
	}
	function parse_inout( $target ) {
		return decide_inout( $target, "A", ref_addr("M8") );
	}
	function parse_eidi( $target ) {
		return decide_eidi( $target );
	}
	function parse_ex( $target ) {
		return decide_ex( $target );
	}
	function parse_call_flg_data( $target ) {
		return array( "CALL", decide_flg( $target ), "M16" );
	}
	function parse_call_data( $target ) {
		return array( "CALL", "M16", "" );
	}
	function parse_push_16( $target ) {
		return array( "PUSH", decide_reg16_1( $target ), "" );
	}
	function parse_ed_2byte( $target ) {
		return array( "NE_ED", "", "" );
	}
	function parse_arilog_data( $target ) {
		return decide_arilog_data( $target );
	}
	function parse_acu( $target ) {
		return array( decide_acu( $target ), "", "" );
	}

#END_PARSE_INST

	function decide_reg16_1( $target ) {
		return decide_reg16( slice( $target, 2, 2 ) );
	}

	function decide_reg8_1( $target ) {
		return decide_reg8( slice( $target, 2, 3 ) );
	}

	function decide_reg8_2( $target ) {
		return decide_reg8( slice( $target, 5, 3 ) );
	}

#START DECIDE_INST

	function decide_incdec_16( $target ) {
		return decide_incdec( slice( $target, 4, 1 ) );
	}

	function decide_incdec_8( $target ) {
		return decide_incdec( slice( $target, 7, 1 ) );
	}

	function decide_incdec( $target ) {
		if ( $target == 0x0 ) return "INC";
		if ( $target == 0x1 ) return "DEC";
		return "ERROR";
	}

	function decide_arilog_8( $target, $reg ) {
		return decide_arilog( slice( $target, 2, 3 ), $reg );
	}

	function decide_arilog_data( $target ) {
		return decide_arilog( slice( $target, 2, 3 ), "M8" );
	}

	function decide_arilog( $target, $reg ) {
		if ( $target == 0x0 ) return array( "ADD", "A",  $reg );
		if ( $target == 0x1 ) return array( "ADC", "A",  $reg );
		if ( $target == 0x2 ) return array( "SUB",  $reg );
		if ( $target == 0x3 ) return array( "SBC", "A",  $reg );
		if ( $target == 0x4 ) return array( "AND",  $reg );
		if ( $target == 0x5 ) return array( "XOR",  $reg );
		if ( $target == 0x6 ) return array( "OR",  $reg );
		if ( $target == 0x7 ) return array( "CP",  $reg );
		return "ERROR";
	}

	function decide_inout( $target, $arg1, $arg2 ) {
		$slice = slice( $target, 4, 1 );
		if ( $slice == 0x0 ) return array( "OUT", $arg2, $arg1 );
		if ( $slice == 0x1 ) return array( "IN", $arg1, $arg2 );
		return "ERROR";
	}

	function decide_eidi( $target ) {
		$slice = slice( $target, 4, 1 );
		if ( $slice == 0x0 ) return array( "DI" );
		if ( $slice == 0x1 ) return array( "EI" );
		return "ERROR";
	}

	function decide_ld_8_addr( $target, $arg ) {
		$args_dir = slice( $target, 4, 1 );
		$slice = slice( $target, 2, 2 );
		if ( $slice == 0x0 ) return args_dir( $args_dir, "LD", "A", $arg );
		if ( $slice == 0x1 ) return args_dir( $args_dir, "LD", "A", $arg );
		if ( $slice == 0x3 ) return args_dir( $args_dir, "LD", "A", ref_addr("M16") );
		if ( $slice == 0x2 ) return args_dir( $args_dir, "LD", "HL", ref_addr("M16") );
		return "ERROR";
	}
	
	function decide_acu( $target ) {
		$slice = slice( $target, 2, 3 );
		if ( $slice == 0x5 ) return "CPL";
		if ( $slice == 0x7 ) return "CCF";
		if ( $slice == 0x6 ) return "SCF";
		return "ERROR";
	}

	#@not used
	function decide_rotshf() {
		$slice = slice( $target, 7, 1 );
		if ( $slice == 0x0 ) return "RLC";
		if ( $slice == 0x1 ) return "RRC";
		if ( $slice == 0x2 ) return "RL";
		if ( $slice == 0x3 ) return "RR";
		if ( $slice == 0x4 ) return "SLA";
		if ( $slice == 0x5 ) return "SRA";
		if ( $slice == 0x7 ) return "SRL";
		return "ERROR";
	}

#END DECIDE_INST

	function decide_reg16( $target ) {
		if ( $target == 0x3 ) return "AF";
		if ( $target == 0x0 ) return "BC";
		if ( $target == 0x1 ) return "DE";
		if ( $target == 0x2 ) return "HL";
		return "ERROR";
	}

	function decide_reg8( $target ) {
		if ( $target == 0x7 ) return "A";
		if ( $target == 0x0 ) return "B";
		if ( $target == 0x1 ) return "C";
		if ( $target == 0x2 ) return "D";
		if ( $target == 0x3 ) return "E";
		if ( $target == 0x4 ) return "H";
		if ( $target == 0x5 ) return "L";
		if ( $target == 0x6 ) return "(HL)";
		return "ERROR";
	}

	function decide_ex( $target ) {
		return array( "EX", decide_ex_reg( slice( $target, 4, 2 ) ), "HL" );
	}

	function decide_ex_reg( $target ) {
		if ( $target == 0x2 ) return "DE";
		if ( $target == 0x0 ) return "(SP)";
		return "ERROR";
	}

	function decide_flg( $target ) {
		$slice = slice( $target, 3, 2 );
		if ( $slice == 0x3 ) return "C";
		if ( $slice == 0x2 ) return "NC";
		if ( $slice == 0x1 ) return "Z";
		if ( $slice == 0x0 ) return "NZ";
		return "ERROR";
	}

#START AF_CONVERTER

	function af_to_sp( $target ) {
		return $target == "AF" ? "SP"
			: $target;
	}

	function af_to_addr( $target ) {
		return $target == "AF" ? "M16"
			: $target;
	}

#END AF_CONVERTER

	function args_dir( $target, $inst, $arg1, $arg2 ) {
		if ( $target == 0x0 ) return array( $inst, $arg2, $arg1 );
		if ( $target == 0x1 ) return array( $inst, $arg1, $arg2 );
		return "ERROR";
	}

	function ref_addr( $target ) {
		return "($target)";
	}

	function slice( $target, $start, $length ) {
		$mask = 0;
		for ( $i = 0; $i < $length; ++$i ) {
			$mask <<= 1;
			$mask |= 1;
		}
		return ( $target >> 8 - $start - $length ) & $mask;
	}

	?>

     </body>
</html>