https://github.com/akkartik/mu/blob/master/021byte_addressing.cc
  1 //: SubX mostly deals with instructions operating on 32-bit operands, but we
  2 //: still need to deal with raw bytes for strings and so on.
  3 
  4 //: Unfortunately the register encodings when dealing with bytes are a mess.
  5 //: We need a special case for them.
  6 :(code)
  7 string rname_8bit(uint8_t r) {
  8   switch (r) {
  9   case 0: return "AL";  // lowest byte of EAX
 10   case 1: return "CL";  // lowest byte of ECX
 11   case 2: return "DL";  // lowest byte of EDX
 12   case 3: return "BL";  // lowest byte of EBX
 13   case 4: return "AH";  // second lowest byte of EAX
 14   case 5: return "CH";  // second lowest byte of ECX
 15   case 6: return "DH";  // second lowest byte of EDX
 16   case 7: return "BH";  // second lowest byte of EBX
 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 (pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
<HTML>
<HEAD>
<TITLE>Computer Science Logo Style vol 2:Acknowledgments</TITLE>
</HEAD>
<BODY>
<CITE>Computer Science Logo Style</CITE> volume 2:
<CITE>Advanced Techniques</CITE> 2/e Copyright (C) 1997 MIT
<H1>Acknowledgments</H1>

<TABLE width="100%"><TR><TD>
<IMG SRC="../csls2.jpg" ALT="cover photo">
<TD><TABLE>
<TR><TD align="right"><CITE><A HREF="http://www.cs.berkeley.edu/~bh/">Brian
Harvey</A><BR>University of California, Berkeley</CITE>
<TR><TD align="right"><BR>
<TR><TD align="right"><A HREF="../pdf/v2ch00.pdf">Download PDF version</A>
<TR><TD align="right"><A HREF="../v2-toc2.html">Back to Table of Contents</A>
<TR><TD align="right"><A HREF="preface.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../v2ch1/v2ch1.html"><STRONG>NEXT</STRONG></A>
<TR><TD align="right"><A HREF="https://mitpress.mit.edu/books/computer-science-logo-style-second-edition-volume-2">MIT
Press web page for <CITE>Computer Science Logo Style</CITE></A>
</TABLE></TABLE>

<HR>

<P>Cynthia Solomon and Margaret Minsky are the people who
got me started at the enterprise of developing exemplary Logo projects.
People in the Logo community had been talking for many years about the need
for an advanced Logo project book, but nobody got around to it until 1982
when Atari had all the money in the world and used some of it to establish a
Corporate Research Department.  Cynthia was in charge of the Atari research
lab in Cambridge, where many MIT old-timers were gathered.  She and Margaret
decided that this was the time for the project book.  I was one of several
people they recruited to contribute projects.  The result of that effort is
called <EM>LogoWorks: Challenging Programs in Logo</EM> (McGraw-Hill, 1985).

<P>This book is somewhat different from <EM>LogoWorks</EM> in that it's part of
a series, so I can make assumptions here about what the reader already knows
from having read the first volume.  Still, I've benefited greatly from what
I learned from Cynthia and Margaret about how to explain the structure of a
large programming project.

<P>The people who have read and commented on early drafts of this book include
Hal Abelson, Alison Birch, Sharon Yoder,
Mike Clancy, Jim Davis, Batya Friedman,
Paul Goldenberg, Margaret Minsky, and Cynthia Solomon.  As for
the first volume, I am particularly indebted to Hal and Paul for their
strong encouragement and their deep insights into issues both in computer
science and in education.  Matthew Wright reviewed some chapters
for the second edition.

<P>Berkeley Logo, the interpreter used in this edition, is a collective effort
of many people, both at Berkeley and across the Internet.  My main debt in
that project is to three former students: Dan van Blerkom, 
Michael Katz, and Doug Orleans.
At the risk of missing someone, I also want to acknowledge
substantial contributions by Freeman Deutsch,
Khang Dao, Fred Gilham, Yehuda Katz,
George Mills, and Randy Sargent.

<P>

<P><A HREF="../v2-toc2.html">(back to Table of Contents)</A>
<P><A HREF="preface.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../v2ch1/v2ch1.html"><STRONG>NEXT</STRONG></A>

<P>
<ADDRESS>
<A HREF="../index.html">Brian Harvey</A>, 
<CODE>bh@cs.berkeley.edu</CODE>
</ADDRESS>
</BODY>
</HTML>
0x" << HEXWORD << Reg[rdest_32bit].u << end(); 114 break; 115 } 116 117 :(code) 118 void test_cannot_copy_byte_to_ESP_EBP_ESI_EDI() { 119 Reg[ESI].u = 0xaabbccdd; 120 Reg[EBX].u = 0x11223344; 121 run( 122 "== code 0x1\n" 123 // op ModR/M SIB displacement immediate 124 " 8a f3 \n" // copy just the byte at *EBX to 8-bit register '6' 125 // ModR/M in binary: 11 (direct mode) 110 (dest 8-bit 'register 6') 011 (src EBX) 126 ); 127 CHECK_TRACE_CONTENTS( 128 // ensure 8-bit register '6' is DH, not ESI 129 "run: copy r8/m8-at-r32 to DH\n" 130 "run: storing 0x44\n" 131 ); 132 // ensure ESI is unchanged 133 CHECK_EQ(Reg[ESI].u, 0xaabbccdd); 134 } 135 136 //: 137 138 :(before "End Initialize Op Names") 139 put_new(Name, "c6", "copy imm8 to r8/m8-at-r32 (mov)"); 140 141 :(code) 142 void test_copy_imm8_to_mem_at_r32() { 143 Reg[EAX].i = 0x2000; 144 run( 145 "== code 0x1\n" 146 // op ModR/M SIB displacement immediate 147 " c6 00 dd \n" // copy to the byte at *EAX 148 // ModR/M in binary: 00 (indirect mode) 000 (unused) 000 (dest EAX) 149 "== data 0x2000\n" 150 "f0 cc bb aa\n" 151 ); 152 CHECK_TRACE_CONTENTS( 153 "run: copy imm8 to r8/m8-at-r32\n" 154 "run: effective address is 0x00002000 (EAX)\n" 155 "run: storing 0xdd\n" 156 ); 157 CHECK_EQ(0xaabbccdd, read_mem_u32(0x2000)); 158 } 159 160 :(before "End Single-Byte Opcodes") 161 case 0xc6: { // copy imm8 to r/m8 162 const uint8_t modrm = next(); 163 const uint8_t src = next(); 164 trace(Callstack_depth+1, "run") << "copy imm8 to r8/m8-at-r32" << end(); 165 trace(Callstack_depth+1, "run") << "imm8 is 0x" << HEXWORD << NUM(src) << end(); 166 const uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits 167 if (subop != 0) { 168 cerr << "unrecognized subop for opcode c6: " << NUM(subop) << " (only 0/copy currently implemented)\n"; 169 exit(1); 170 } 171 // use unsigned to zero-extend 8-bit value to 32 bits 172 uint8_t* dest = effective_byte_address(modrm); 173 *dest = src; // Write multiple elements of vector<uint8_t> at once. Assumes sizeof(int) == 4 on the host as well. 174 trace(Callstack_depth+1, "run") << "storing 0x" << HEXBYTE << NUM(*dest) << end(); 175 break; 176 } 177 178 //:: set flags (setcc) 179 180 :(before "End Initialize Op Names") 181 put_new(Name_0f, "94", "set r8/m8-at-rm32 to 1 if equal, if ZF is set, 0 otherwise (setcc/setz/sete)"); 182 put_new(Name_0f, "95", "set r8/m8-at-rm32 to 1 if not equal, if ZF is not set, 0 otherwise (setcc/setnz/setne)"); 183 put_new(Name_0f, "9f", "set r8/m8-at-rm32 to 1 if greater (signed), if ZF is unset and SF == OF, 0 otherwise (setcc/setg/setnle)"); 184 put_new(Name_0f, "97", "set r8/m8-at-rm32 to 1 if greater (unsigned), if ZF is unset and CF is unset, 0 otherwise (setcc/seta/setnbe)"); 185 put_new(Name_0f, "9d", "set r8/m8-at-rm32 to 1 if greater or equal (signed), if SF == OF, 0 otherwise (setcc/setge/setnl)"); 186 put_new(Name_0f, "93", "set r8/m8-at-rm32 to 1 if greater or equal (unsigned), if CF is unset, 0 otherwise (setcc/setae/setnb)"); 187 put_new(Name_0f, "9c", "set r8/m8-at-rm32 to 1 if lesser (signed), if SF != OF, 0 otherwise (setcc/setl/setnge)"); 188 put_new(Name_0f, "92", "set r8/m8-at-rm32 to 1 if lesser (unsigned), if CF is set, 0 otherwise (setcc/setb/setnae)"); 189 put_new(Name_0f, "9e", "set r8/m8-at-rm32 to 1 if lesser or equal (signed), if ZF is set or SF != OF, 0 otherwise (setcc/setle/setng)"); 190 put_new(Name_0f, "96", "set r8/m8-at-rm32 to 1 if lesser or equal (unsigned), if ZF is set or CF is set, 0 otherwise (setcc/setbe/setna)"); 191 192 :(before "End Two-Byte Opcodes Starting With 0f") 193 case 0x94: { // set r8/m8-at-rm32 if ZF 194 const uint8_t modrm = next(); 195 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 196 uint8_t* dest = effective_byte_address(modrm); 197 *dest = ZF; 198 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 199 break; 200 } 201 case 0x95: { // set r8/m8-at-rm32 if !ZF 202 const uint8_t modrm = next(); 203 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 204 uint8_t* dest = effective_byte_address(modrm); 205 *dest = !ZF; 206 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 207 break; 208 } 209 case 0x9f: { // set r8/m8-at-rm32 if !SF and !ZF 210 const uint8_t modrm = next(); 211 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 212 uint8_t* dest = effective_byte_address(modrm); 213 *dest = !ZF && SF == OF; 214 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 215 break; 216 } 217 case 0x97: { // set r8/m8-at-rm32 if !CF and !ZF 218 const uint8_t modrm = next(); 219 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 220 uint8_t* dest = effective_byte_address(modrm); 221 *dest = (!CF && !ZF); 222 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 223 break; 224 } 225 case 0x9d: { // set r8/m8-at-rm32 if !SF 226 const uint8_t modrm = next(); 227 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 228 uint8_t* dest = effective_byte_address(modrm); 229 *dest = (SF == OF); 230 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 231 break; 232 } 233 case 0x93: { // set r8/m8-at-rm32 if !CF 234 const uint8_t modrm = next(); 235 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 236 uint8_t* dest = effective_byte_address(modrm); 237 *dest = !CF; 238 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 239 break; 240 } 241 case 0x9c: { // set r8/m8-at-rm32 if SF and !ZF 242 const uint8_t modrm = next(); 243 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 244 uint8_t* dest = effective_byte_address(modrm); 245 *dest = (SF != OF); 246 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 247 break; 248 } 249 case 0x92: { // set r8/m8-at-rm32 if CF 250 const uint8_t modrm = next(); 251 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 252 uint8_t* dest = effective_byte_address(modrm); 253 *dest = CF; 254 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 255 break; 256 } 257 case 0x9e: { // set r8/m8-at-rm32 if SF or ZF 258 const uint8_t modrm = next(); 259 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 260 uint8_t* dest = effective_byte_address(modrm); 261 *dest = (ZF || SF != OF); 262 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 263 break; 264 } 265 case 0x96: { // set r8/m8-at-rm32 if ZF or CF 266 const uint8_t modrm = next(); 267 trace(Callstack_depth+1, "run") << "set r8/m8-at-rm32" << end(); 268 uint8_t* dest = effective_byte_address(modrm); 269 *dest = (ZF || CF); 270 trace(Callstack_depth+1, "run") << "storing " << NUM(*dest) << end(); 271 break; 272 }