about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--subx/010---vm.cc40
-rw-r--r--subx/011run.cc2
-rw-r--r--subx/013direct_addressing.cc64
-rw-r--r--subx/015immediate_addressing.cc26
-rw-r--r--subx/030---operands.cc56
-rw-r--r--subx/modrm.pdfbin0 -> 46205 bytes
-rw-r--r--subx/sib.pdfbin0 -> 51968 bytes
7 files changed, 113 insertions, 75 deletions
diff --git a/subx/010---vm.cc b/subx/010---vm.cc
index 745d64e0..cae54aec 100644
--- a/subx/010---vm.cc
+++ b/subx/010---vm.cc
@@ -35,21 +35,43 @@ EIP = 1;  // preserve null pointer
 cerr << "  registers\n";
 :(before "End Help Texts")
 put(Help, "registers",
-  "SubX currently supports eight 32-bit integer registers: R0 to R7.\n"
-  "R4 (ESP) contains the top of the stack.\n"
+  "SubX currently supports eight 32-bit integer registers. From 0 to 7, they are:\n"
+  "  EAX ECX EDX EBX ESP EBP ESI EDI\n"
+  "ESP contains the top of the stack.\n"
   "\n"
-  "There's also a register for the address of the currently executing\n"
-  "instruction. It is modified by jumps.\n"
+  "-- 8-bit registers\n"
+  "Some instructions operate on eight *overlapping* 8-bit registers.\n"
+  "From 0 to 7, they are:\n"
+  "  AL CL DL BL AH CH DH BH\n"
+  "The 8-bit registers overlap with the 32-bit ones. AL is the lowest signicant byte\n"
+  "of EAX, AH is the second lowest significant byte, and so on.\n"
   "\n"
-  "Various instructions modify one or more of three 1-bit 'flag' registers,\n"
-  "as a side-effect:\n"
+  "For example, if EBX contains 0x11223344, then BL contains 0x44, and BH contains 0x33.\n"
+  "\n"
+  "There is no way to access bytes within ESP, EBP, ESI or EDI.\n"
+  "\n"
+  "For complete details consult the IA-32 software developer's manual, volume 2,\n"
+  "table 2-2, \"32-bit addressing forms with the ModR/M byte\".\n"
+  "It is included in this repository as 'modrm.pdf'.\n"
+  "The register encodings are described in the top row of the table, but you'll need\n"
+  "to spend some time with it.\n"
+  "\n"
+  "-- flag registers\n"
+  "Various instructions (particularly 'compare') modify one or more of three 1-bit 'flag'\n"
+  "registers, as a side-effect:\n"
   "- the sign flag (SF): usually set if an arithmetic result is negative, or\n"
   "  reset if not.\n"
   "- the zero flag (ZF): usually set if a result is zero, or reset if not.\n"
   "- the overflow flag (OF): usually set if an arithmetic result overflows.\n"
   "The flag bits are read by conditional jumps.\n"
   "\n"
-  "We don't support non-integer (floating-point) registers yet.\n"
+  "For complete details on how different instructions update the flags, consult the IA-32\n"
+  "manual (volume 2). There's various versions of it online, such as https://c9x.me/x86,\n"
+  "though of course you'll need to be careful to ignore instructions and flag registers\n"
+  "that SubX doesn't support.\n"
+  "\n"
+  "It isn't simple, but if this is the processor you have running on your computer,\n"
+  "might as well get good at it.\n"
 );
 
 :(before "End Globals")
@@ -366,7 +388,9 @@ if (key == "opcodes") {
     cerr << "  f3 " << p->first << ": " << p->second << '\n';
   for (map<string, string>::iterator p = name_f3_0f.begin();  p != name_f3_0f.end();  ++p)
     cerr << "  f3 0f " << p->first << ": " << p->second << '\n';
-  cerr << "Run `subx help instructions` for details on words like 'r32' and 'disp8'.\n";
+  cerr << "Run `subx help instructions` for details on words like 'r32' and 'disp8'.\n"
+          "For complete details on these instructions, consult the IA-32 manual (volume 2).\n"
+          "There's various versions of it online, such as https://c9x.me/x86.\n";
   return 0;
 }
 :(before "End Help Contents")
diff --git a/subx/011run.cc b/subx/011run.cc
index 88729871..d5d1c074 100644
--- a/subx/011run.cc
+++ b/subx/011run.cc
@@ -327,7 +327,7 @@ void parse_and_load(const string& text_bytes) {
 //:: run
 
 :(before "End Initialize Op Names(name)")
-put(name, "05", "add imm32 to R0 (EAX)");
+put(name, "05", "add imm32 to EAX");
 
 //: our first opcode
 :(before "End Single-Byte Opcodes")
diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc
index 5f44d49d..2767f32b 100644
--- a/subx/013direct_addressing.cc
+++ b/subx/013direct_addressing.cc
@@ -385,14 +385,14 @@ case 0x87: {  // exchange r32 with r/m32
 //:: increment
 
 :(before "End Initialize Op Names(name)")
-put(name, "40", "increment R0 (EAX)");
-put(name, "41", "increment R1 (ECX)");
-put(name, "42", "increment R2 (EDX)");
-put(name, "43", "increment R3 (EBX)");
-put(name, "44", "increment R4 (ESP)");
-put(name, "45", "increment R5 (EBP)");
-put(name, "46", "increment R6 (ESI)");
-put(name, "47", "increment R7 (EDI)");
+put(name, "40", "increment EAX");
+put(name, "41", "increment ECX");
+put(name, "42", "increment EDX");
+put(name, "43", "increment EBX");
+put(name, "44", "increment ESP");
+put(name, "45", "increment EBP");
+put(name, "46", "increment ESI");
+put(name, "47", "increment EDI");
 
 :(scenario increment_r32)
 % Reg[ECX].u = 0x1f;
@@ -451,14 +451,14 @@ case 0xff: {
 //:: decrement
 
 :(before "End Initialize Op Names(name)")
-put(name, "48", "decrement R0 (EAX)");
-put(name, "49", "decrement R1 (ECX)");
-put(name, "4a", "decrement R2 (EDX)");
-put(name, "4b", "decrement R3 (EBX)");
-put(name, "4c", "decrement R4 (ESP)");
-put(name, "4d", "decrement R5 (EBP)");
-put(name, "4e", "decrement R6 (ESI)");
-put(name, "4f", "decrement R7 (EDI)");
+put(name, "48", "decrement EAX");
+put(name, "49", "decrement ECX");
+put(name, "4a", "decrement EDX");
+put(name, "4b", "decrement EBX");
+put(name, "4c", "decrement ESP");
+put(name, "4d", "decrement EBP");
+put(name, "4e", "decrement ESI");
+put(name, "4f", "decrement EDI");
 
 :(scenario decrement_r32)
 % Reg[ECX].u = 0x1f;
@@ -506,14 +506,14 @@ case 1: {  // decrement r/m32
 //:: push
 
 :(before "End Initialize Op Names(name)")
-put(name, "50", "push R0 (EAX) to stack");
-put(name, "51", "push R1 (ECX) to stack");
-put(name, "52", "push R2 (EDX) to stack");
-put(name, "53", "push R3 (EBX) to stack");
-put(name, "54", "push R4 (ESP) to stack");
-put(name, "55", "push R5 (EBP) to stack");
-put(name, "56", "push R6 (ESI) to stack");
-put(name, "57", "push R7 (EDI) to stack");
+put(name, "50", "push EAX to stack");
+put(name, "51", "push ECX to stack");
+put(name, "52", "push EDX to stack");
+put(name, "53", "push EBX to stack");
+put(name, "54", "push ESP to stack");
+put(name, "55", "push EBP to stack");
+put(name, "56", "push ESI to stack");
+put(name, "57", "push EDI to stack");
 
 :(scenario push_r32)
 % Reg[ESP].u = 0x64;
@@ -544,14 +544,14 @@ case 0x57: {  // push r32 to stack
 //:: pop
 
 :(before "End Initialize Op Names(name)")
-put(name, "58", "pop top of stack to R0 (EAX)");
-put(name, "59", "pop top of stack to R1 (ECX)");
-put(name, "5a", "pop top of stack to R2 (EDX)");
-put(name, "5b", "pop top of stack to R3 (EBX)");
-put(name, "5c", "pop top of stack to R4 (ESP)");
-put(name, "5d", "pop top of stack to R5 (EBP)");
-put(name, "5e", "pop top of stack to R6 (ESI)");
-put(name, "5f", "pop top of stack to R7 (EDI)");
+put(name, "58", "pop top of stack to EAX");
+put(name, "59", "pop top of stack to ECX");
+put(name, "5a", "pop top of stack to EDX");
+put(name, "5b", "pop top of stack to EBX");
+put(name, "5c", "pop top of stack to ESP");
+put(name, "5d", "pop top of stack to EBP");
+put(name, "5e", "pop top of stack to ESI");
+put(name, "5f", "pop top of stack to EDI");
 
 :(scenario pop_r32)
 % Reg[ESP].u = 0x2000;
diff --git a/subx/015immediate_addressing.cc b/subx/015immediate_addressing.cc
index 01f7e040..7f1f1a7e 100644
--- a/subx/015immediate_addressing.cc
+++ b/subx/015immediate_addressing.cc
@@ -55,7 +55,7 @@ case 0x81: {  // combine imm32 with r/m32
 //:: subtract
 
 :(before "End Initialize Op Names(name)")
-put(name, "2d", "subtract imm32 from R0 (EAX)");
+put(name, "2d", "subtract imm32 from EAX");
 
 :(scenario subtract_imm32_from_eax)
 % Reg[EAX].i = 0x0d0c0baa;
@@ -113,7 +113,7 @@ case 5: {
 //:: and
 
 :(before "End Initialize Op Names(name)")
-put(name, "25", "R0 = bitwise AND of imm32 with R0 (EAX)");
+put(name, "25", "EAX = bitwise AND of imm32 with EAX");
 
 :(scenario and_imm32_with_eax)
 % Reg[EAX].i = 0xff;
@@ -171,7 +171,7 @@ case 4: {
 //:: or
 
 :(before "End Initialize Op Names(name)")
-put(name, "0d", "R0 = bitwise OR of imm32 with R0 (EAX)");
+put(name, "0d", "EAX = bitwise OR of imm32 with EAX");
 
 :(scenario or_imm32_with_eax)
 % Reg[EAX].i = 0xd0c0b0a0;
@@ -227,7 +227,7 @@ case 1: {
 //:: xor
 
 :(before "End Initialize Op Names(name)")
-put(name, "35", "R0 = bitwise XOR of imm32 with R0 (EAX)");
+put(name, "35", "EAX = bitwise XOR of imm32 with EAX");
 
 :(scenario xor_imm32_with_eax)
 % Reg[EAX].i = 0xddccb0a0;
@@ -283,7 +283,7 @@ case 6: {
 //:: compare (cmp)
 
 :(before "End Initialize Op Names(name)")
-put(name, "3d", "compare: set SF if R0 < imm32");
+put(name, "3d", "compare: set SF if EAX < imm32");
 
 :(scenario compare_imm32_with_eax_greater)
 % Reg[EAX].i = 0x0d0c0b0a;
@@ -413,14 +413,14 @@ case 7: {
 //:: copy (mov)
 
 :(before "End Initialize Op Names(name)")
-put(name, "b8", "copy imm32 to R0 (EAX)");
-put(name, "b9", "copy imm32 to R1 (ECX)");
-put(name, "ba", "copy imm32 to R2 (EDX)");
-put(name, "bb", "copy imm32 to R3 (EBX)");
-put(name, "bc", "copy imm32 to R4 (ESP)");
-put(name, "bd", "copy imm32 to R5 (EBP)");
-put(name, "be", "copy imm32 to R6 (ESI)");
-put(name, "bf", "copy imm32 to R7 (EDI)");
+put(name, "b8", "copy imm32 to EAX");
+put(name, "b9", "copy imm32 to ECX");
+put(name, "ba", "copy imm32 to EDX");
+put(name, "bb", "copy imm32 to EBX");
+put(name, "bc", "copy imm32 to ESP");
+put(name, "bd", "copy imm32 to EBP");
+put(name, "be", "copy imm32 to ESI");
+put(name, "bf", "copy imm32 to EDI");
 
 :(scenario copy_imm32_to_r32)
 == 0x1
diff --git a/subx/030---operands.cc b/subx/030---operands.cc
index 196e8556..4015174b 100644
--- a/subx/030---operands.cc
+++ b/subx/030---operands.cc
@@ -72,9 +72,10 @@ void init_operand_type_help() {
     "     Using it as an address gets more involved. For more details,\n"
     "     try reading the help pages for 'base', 'index' and 'scale'.)\n"
     "\n"
-    "For complete details consult the IA-32 software developer's manual, table 2-2,\n"
-    "\"32-bit addressing forms with the ModR/M byte\".\n"
-    "  https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n"
+    "For complete details, spend some time with two tables in the IA-32 software\n"
+    "developer's manual that are also included in this repo:\n"
+    "  - modrm.pdf: volume 2, table 2-2, \"32-bit addressing with the ModR/M byte.\".\n"
+    "  - sib.pdf: volume 2, table 2-3, \"32-bit addressing with the SIB byte.\".\n"
   );
   put(Help, "subop",
     "Additional 3-bit operand for determining the instruction when the opcode is 81, 8f or ff.\n"
@@ -84,34 +85,47 @@ void init_operand_type_help() {
     "3-bit operand specifying a register operand used directly, without any further addressing modes.\n"
   );
   put(Help, "rm32",
-    "32-bit value in register or memory. The precise details of its construction depend on the eponymous 3-bit\n"
-    "'rm32' operand, the 'mod' operand, and also potentially the 'SIB' operands ('scale', 'index' and 'base')\n"
-    "and a displacement ('disp8' or 'disp32').\n"
-    "For complete details consult the IA-32 software developer's manual, table 2-2,\n"
-    "\"32-bit addressing forms with the ModR/M byte\".\n"
-    "  https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n"
+    "32-bit value in register or memory. The precise details of its construction\n"
+    "depend on the eponymous 3-bit 'rm32' operand, the 'mod' operand, and also\n"
+    "potentially the 'SIB' operands ('scale', 'index' and 'base') and a displacement\n"
+    "('disp8' or 'disp32').\n"
+    "\n"
+    "For complete details, spend some time with two tables in the IA-32 software\n"
+    "developer's manual that are also included in this repo:\n"
+    "  - modrm.pdf: volume 2, table 2-2, \"32-bit addressing with the ModR/M byte.\".\n"
+    "  - sib.pdf: volume 2, table 2-3, \"32-bit addressing with the SIB byte.\".\n"
   );
   put(Help, "base",
-    "Additional 3-bit operand (when 'rm32' is 4 unless 'mod' is 3) specifying the register containing an address to look up.\n"
+    "Additional 3-bit operand (when 'rm32' is 4, unless 'mod' is 3) specifying the\n"
+    "register containing an address to look up.\n"
     "This address may be further modified by 'index' and 'scale' operands.\n"
     "  effective address = base + index*scale + displacement (disp8 or disp32)\n"
-    "For complete details consult the IA-32 software developer's manual, table 2-3,\n"
-    "\"32-bit addressing forms with the SIB byte\".\n"
-    "  https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n"
+    "For complete details, spend some time with the IA-32 software developer's manual,\n"
+    "volume 2, table 2-3, \"32-bit addressing with the SIB byte\".\n"
+    "It is included in this repository as 'sib.pdf'.\n"
   );
   put(Help, "index",
-    "Optional 3-bit operand (when 'rm32' is 4 unless 'mod' is 3) that can be added to the 'base' operand to compute the 'effective address' at which to look up memory.\n"
+    "Optional 3-bit operand (when 'rm32' is 4 unless 'mod' is 3) that can be added to\n"
+    "the 'base' operand to compute the 'effective address' at which to look up memory.\n"
     "  effective address = base + index*scale + displacement (disp8 or disp32)\n"
-    "For complete details consult the IA-32 software developer's manual, table 2-3,\n"
-    "\"32-bit addressing forms with the SIB byte\".\n"
-    "  https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n"
+    "For complete details, spend some time with the IA-32 software developer's manual,\n"
+    "volume 2, table 2-3, \"32-bit addressing with the SIB byte\".\n"
+    "It is included in this repository as 'sib.pdf'.\n"
   );
   put(Help, "scale",
-    "Optional 2-bit operand (when 'rm32' is 4 unless 'mod' is 3) that can be multiplied to the 'index' operand before adding the result to the 'base' operand to compute the _effective address_ to operate on.\n"
+    "Optional 2-bit operand (when 'rm32' is 4 unless 'mod' is 3) that encodes a\n"
+    "power of 2 to be multiplied to the 'index' operand before adding the result to\n"
+    "the 'base' operand to compute the _effective address_ to operate on.\n"
     "  effective address = base + index * scale + displacement (disp8 or disp32)\n"
-    "For complete details consult the IA-32 software developer's manual, table 2-3,\n"
-    "\"32-bit addressing forms with the SIB byte\".\n"
-    "  https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf\n"
+    "\n"
+    "When scale is 0, use index unmodified.\n"
+    "When scale is 1, multiply index by 2.\n"
+    "When scale is 2, multiply index by 4.\n"
+    "When scale is 3, multiply index by 8.\n"
+    "\n"
+    "For complete details, spend some time with the IA-32 software developer's manual,\n"
+    "volume 2, table 2-3, \"32-bit addressing with the SIB byte\".\n"
+    "It is included in this repository as 'sib.pdf'.\n"
   );
   put(Help, "disp8",
     "8-bit value to be added in many instructions.\n"
diff --git a/subx/modrm.pdf b/subx/modrm.pdf
new file mode 100644
index 00000000..552aec53
--- /dev/null
+++ b/subx/modrm.pdf
Binary files differdiff --git a/subx/sib.pdf b/subx/sib.pdf
new file mode 100644
index 00000000..735a40ca
--- /dev/null
+++ b/subx/sib.pdf
Binary files differ