about summary refs log tree commit diff stats
path: root/subx
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2017-10-12 21:38:02 -0700
committerKartik K. Agaram <vc@akkartik.com>2017-10-12 21:38:02 -0700
commitbdcb8015d4bd32eaa6f3e21554afcae426b571a5 (patch)
tree8e9b86379b9d8c533829f6d28ba1625a17240bd1 /subx
parentd4df57d62a51e26f81f2c6552c1b7b14ff38fe1f (diff)
downloadmu-bdcb8015d4bd32eaa6f3e21554afcae426b571a5.tar.gz
4040
subx: add immediate

First example of a more complex opcode that needs to do its own decoding
to decide what instruction to run.
Diffstat (limited to 'subx')
-rw-r--r--subx/010core.cc4
-rw-r--r--subx/011add.cc36
2 files changed, 37 insertions, 3 deletions
diff --git a/subx/010core.cc b/subx/010core.cc
index 2816f559..61ae583e 100644
--- a/subx/010core.cc
+++ b/subx/010core.cc
@@ -40,7 +40,7 @@ SF = ZF = OF = false;
   /* arg1 and arg2 must be signed */ \
   int64_t tmp = arg1 op arg2; \
   arg1 = arg1 op arg2; \
-  trace(2, "run") << "storing 0x" << std::hex << arg1 << end(); \
+  trace(2, "run") << "storing 0x" << HEXWORD << arg1 << end(); \
   SF = (arg1 < 0); \
   ZF = (arg1 == 0); \
   OF = (arg1 != tmp); \
@@ -49,7 +49,7 @@ SF = ZF = OF = false;
 #define BINARY_BITWISE_OP(op, arg1, arg2) { \
   /* arg1 and arg2 must be unsigned */ \
   arg1 = arg1 op arg2; \
-  trace(2, "run") << "storing 0x" << std::hex << arg1 << end(); \
+  trace(2, "run") << "storing 0x" << HEXWORD << arg1 << end(); \
   SF = (arg1 >> 31); \
   ZF = (arg1 == 0); \
   OF = false; \
diff --git a/subx/011add.cc b/subx/011add.cc
index 836b227b..03e25c07 100644
--- a/subx/011add.cc
+++ b/subx/011add.cc
@@ -7,7 +7,7 @@
   01  18                                     # add EBX (reg 3) to *EAX (reg 0)
 +run: add reg 3 to effective address
 +run: effective address is mem at address 0x60 (reg 0)
-+run: storing 0x11
++run: storing 0x00000011
 
 :(before "End Single-Byte Opcodes")
 case 0x01: {  // add r32 to r/m32
@@ -47,3 +47,37 @@ int32_t* effective_address(uint8_t modrm) {
   }
   return result;
 }
+
+:(scenario add_imm32_to_rm32)
+% Reg[3].i = 1;
+# op  ModRM   SIB   displacement  immediate
+  81  c3                          0a 0b 0c 0d  # add 0x0d0c0b0a to EBX (reg 3)
++run: add imm32 0x0d0c0b0a to effective address
++run: effective address is reg 3
++run: storing 0x0d0c0b0b
+
+:(before "End Single-Byte Opcodes")
+case 0x81: {  // combine imm32 with r/m32
+  uint8_t modrm = next();
+  int32_t arg2 = imm32();
+  trace(2, "run") << "add imm32 0x" << HEXWORD << arg2 << " to effective address" << end();
+  int32_t* arg1 = effective_address(modrm);
+  uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
+  switch (subop) {
+  case 0:
+    BINARY_ARITHMETIC_OP(+, *arg1, arg2);
+    break;
+  // End Op 81 Subops
+  default:
+    cerr << "unrecognized sub-opcode after 81: " << NUM(subop) << '\n';
+    exit(1);
+  }
+  break;
+}
+
+:(before "End Mod Special-cases")
+case 3:
+  // mod 3 is just register direct addressing
+  trace(2, "run") << "effective address is reg " << NUM(rm) << end();
+  result = &Reg[rm].i;
+  break;