https://github.com/akkartik/mu/blob/master/subx/021byte_addressing.cc
1
2
3
4
5
6 :(code)
7 string rname_8bit(uint8_t r) {
8 switch (r) {
9 case 0: return "AL";
10 case 1: return "CL";
11 case 2: return "DL";
12 case 3: return "BL";
13 case 4: return "AH";
14 case 5: return "CH";
15 case 6: return "DH";
16 case 7: return "BH";
17 default: raise << "invalid 8-bit register " << r << '\n' << end(); return "";
18 }
19 }
20
21 uint8_t* effective_byte_address(uint8_t modrm) {
22 uint8_t mod = (modrm>>6);
23 uint8_t rm = modrm & 0x7;
24 if (mod == 3) {
25
26 trace(90, "run") << "r/m8 is " << rname_8bit(rm) << end();
27 return reg_8bit(rm);
28 }
29
30 return mem_addr_u8(effective_address_number(modrm));
31 }
32
33 uint8_t* reg_8bit(uint8_t rm) {
34 uint8_t* result = reinterpret_cast<uint8_t*>(&Reg[rm & 0x3].i);
35 if (rm & 0x4)
36 ++result;
37 return result;
38 }
39
40 :(before "End Initialize Op Names")
41 put_new(Name, "88", "copy r8 to r8/m8-at-r32");
42
43 :(scenario copy_r8_to_mem_at_r32)
44 % Reg[EBX].i = 0x224488ab;
45 % Reg[EAX].i = 0x2000;
46 == 0x1
47
48 88 18
49
50 == 0x2000
51 f0 cc bb aa
52 +run: copy BL to r8/m8-at-r32
53 +run: effective address is 0x00002000 (EAX)
54 +run: storing 0xab
55 % CHECK_EQ(0xaabbccab, read_mem_u32(0x2000));
56
57 :(before "End Single-Byte Opcodes")
58 case 0x88: {
59 const uint8_t modrm = next();
60 const uint8_t rsrc = (modrm>>3)&0x7;
61 trace(90, "run") << "copy " << rname_8bit(rsrc) << " to r8/m8-at-r32" << end();
62
63 uint8_t* dest = reinterpret_cast<uint8_t*>(effective_byte_address(modrm));
64 const uint8_t* src = reg_8bit(rsrc);
65 *dest = *src;
66 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*dest) << end();
67 break;
68 }
69
70
71
72 :(before "End Initialize Op Names")
73 put_new(Name, "8a", "copy r8/m8-at-r32 to r8");
74
75 :(scenario copy_mem_at_r32_to_r8)
76 % Reg[EBX].i = 0xaabbcc0f; // one nibble each of lowest byte set to all 0s and all 1s, to maximize value of this test
77 % Reg[EAX].i = 0x2000;
78 == 0x1
79
80 8a 18
81
82 == 0x2000
83 ab ff ff ff
84 +run: copy r8/m8-at-r32 to BL
85 +run: effective address is 0x00002000 (EAX)
86 +run: storing 0xab
87
88 +run: EBX now contains 0xaabbccab
89
90 :(before "End Single-Byte Opcodes")
91 case 0x8a: {
92 const uint8_t modrm = next();
93 const uint8_t rdest = (modrm>>3)&0x7;
94 trace(90, "run") << "copy r8/m8-at-r32 to " << rname_8bit(rdest) << end();
95
96 const uint8_t* src = reinterpret_cast<uint8_t*>(effective_byte_address(modrm));
97 uint8_t* dest = reg_8bit(rdest);
98 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*src) << end();
99 *dest = *src;
100 const uint8_t rdest_32bit = rdest & 0x3;
101 trace(90, "run") << rname(rdest_32bit) << " now contains 0x" << HEXWORD << Reg[rdest_32bit].u << end();
102 break;
103 }
104
105 :(scenario cannot_copy_byte_to_ESP_EBP_ESI_EDI)
106 % Reg[ESI].u = 0xaabbccdd;
107 % Reg[EBX].u = 0x11223344;
108 == 0x1
109
110 8a f3
111
112
113 +run: copy r8/m8-at-r32 to DH
114 +run: storing 0x44
115
116 % CHECK_EQ(Reg[ESI].u, 0xaabbccdd);
117
118
119
120 :(before "End Initialize Op Names")
121 put_new(Name, "c6", "copy imm8 to r8/m8-at-r32 (mov)");
122
123 :(scenario copy_imm8_to_mem_at_r32)
124 % Reg[EAX].i = 0x2000;
125 == 0x1
126
127 c6 00 dd
128
129 == 0x2000
130 f0 cc bb aa
131 +run: copy imm8 to r8/m8-at-r32
132 +run: effective address is 0x00002000 (EAX)
133 +run: storing 0xdd
134 % CHECK_EQ(0xaabbccdd, read_mem_u32(0x2000));
135
136 :(before "End Single-Byte Opcodes")
137 case 0xc6: {
138 const uint8_t modrm = next();
139 const uint8_t src = next();
140 trace(90, "run") << "copy imm8 to r8/m8-at-r32" << end();
141 trace(90, "run") << "imm8 is 0x" << HEXWORD << src << end();
142 const uint8_t subop = (modrm>>3)&0x7;
143 if (subop != 0) {
144 cerr << "unrecognized subop for opcode c6: " << NUM(subop) << " (only 0/copy currently implemented)\n";
145 exit(1);
146 }
147
148 uint8_t* dest = reinterpret_cast<uint8_t*>(effective_byte_address(modrm));
149 *dest = src;
150 trace(90, "run") << "storing 0x" << HEXBYTE << NUM(*dest) << end();
151 break;
152 }