about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-09-21 16:02:50 -0700
committerKartik Agaram <vc@akkartik.com>2018-09-21 16:03:31 -0700
commit45967d2106335dbd595cb43ae5732ba88b5d0553 (patch)
tree49b750a77571037df44967f8c14a1a8553e8205c
parentbd9f6d0cd069f3504c1825c6b25c7149c13ff57a (diff)
downloadmu-45967d2106335dbd595cb43ae5732ba88b5d0553.tar.gz
4578 - subx: implement inc/dec operations
-rw-r--r--subx/013direct_addressing.cc121
-rw-r--r--subx/014indirect_addressing.cc23
-rw-r--r--subx/031check_operands.cc18
-rw-r--r--subx/opcodes18
4 files changed, 162 insertions, 18 deletions
diff --git a/subx/013direct_addressing.cc b/subx/013direct_addressing.cc
index 2fb5c361..0ddb1ce8 100644
--- a/subx/013direct_addressing.cc
+++ b/subx/013direct_addressing.cc
@@ -370,6 +370,127 @@ case 0x87: {  // exchange r32 with r/m32
   break;
 }
 
+//:: 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)");
+
+:(scenario increment_r32)
+% Reg[ECX].u = 0x1f;
+== 0x1  # code segment
+# op  ModR/M  SIB   displacement  immediate
+  41                                          # increment ECX
++run: increment ECX
++run: storing value 0x00000020
+
+:(before "End Single-Byte Opcodes")
+case 0x40:
+case 0x41:
+case 0x42:
+case 0x43:
+case 0x44:
+case 0x45:
+case 0x46:
+case 0x47: {  // increment r32
+  uint8_t reg = op & 0x7;
+  trace(90, "run") << "increment " << rname(reg) << end();
+  ++Reg[reg].u;
+  trace(90, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
+  break;
+}
+
+:(before "End Initialize Op Names(name)")
+put(name, "ff", "inc/dec/jump/push/call rm32 based on subop");
+
+:(scenario increment_rm32)
+% Reg[EAX].u = 0x20;
+== 0x1  # code segment
+# op  ModR/M  SIB   displacement  immediate
+  ff  c0                                      # increment EAX
+# ModR/M in binary: 11 (direct mode) 000 (subop inc) 000 (EAX)
++run: increment r/m32
++run: r/m32 is EAX
++run: storing value 0x00000021
+
+:(before "End Single-Byte Opcodes")
+case 0xff: {
+  uint8_t modrm = next();
+  uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
+  switch (subop) {
+    case 0: {  // increment r/m32
+      trace(90, "run") << "increment r/m32" << end();
+      int32_t* arg = effective_address(modrm);
+      ++*arg;
+      trace(90, "run") << "storing value 0x" << HEXWORD << *arg << end();
+      break;
+    }
+    // End Op ff Subops
+  }
+  break;
+}
+
+//:: 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)");
+
+:(scenario decrement_r32)
+% Reg[ECX].u = 0x1f;
+== 0x1  # code segment
+# op  ModR/M  SIB   displacement  immediate
+  49                                          # decrement ECX
++run: decrement ECX
++run: storing value 0x0000001e
+
+:(before "End Single-Byte Opcodes")
+case 0x48:
+case 0x49:
+case 0x4a:
+case 0x4b:
+case 0x4c:
+case 0x4d:
+case 0x4e:
+case 0x4f: {  // decrement r32
+  uint8_t reg = op & 0x7;
+  trace(90, "run") << "decrement " << rname(reg) << end();
+  --Reg[reg].u;
+  trace(90, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
+  break;
+}
+
+:(scenario decrement_rm32)
+% Reg[EAX].u = 0x20;
+== 0x1  # code segment
+# op  ModR/M  SIB   displacement  immediate
+  ff  c8                                      # decrement EAX
+# ModR/M in binary: 11 (direct mode) 001 (subop inc) 000 (EAX)
++run: decrement r/m32
++run: r/m32 is EAX
++run: storing value 0x0000001f
+
+:(before "End Op ff Subops")
+case 1: {  // decrement r/m32
+  trace(90, "run") << "decrement r/m32" << end();
+  int32_t* arg = effective_address(modrm);
+  --*arg;
+  trace(90, "run") << "storing value 0x" << HEXWORD << *arg << end();
+  break;
+}
+
 //:: push
 
 :(before "End Initialize Op Names(name)")
diff --git a/subx/014indirect_addressing.cc b/subx/014indirect_addressing.cc
index 3a7bd3b6..9142728a 100644
--- a/subx/014indirect_addressing.cc
+++ b/subx/014indirect_addressing.cc
@@ -443,9 +443,6 @@ case 0x8a: {  // copy r/m8 to r8
 
 //:: jump
 
-:(before "End Initialize Op Names(name)")
-put(name, "ff", "jump/push/call rm32 based on subop");
-
 :(scenario jump_mem_at_r32)
 % Reg[EAX].i = 0x60;
 == 0x1  # code segment
@@ -463,20 +460,12 @@ put(name, "ff", "jump/push/call rm32 based on subop");
 +run: inst: 0x00000008
 -run: inst: 0x00000003
 
-:(before "End Single-Byte Opcodes")
-case 0xff: {
-  uint8_t modrm = next();
-  uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
-  switch (subop) {
-    case 4: {  // jump to r/m32
-      trace(90, "run") << "jump to r/m32" << end();
-      int32_t* arg2 = effective_address(modrm);
-      EIP = *arg2;
-      trace(90, "run") << "jumping to 0x" << HEXWORD << EIP << end();
-      break;
-    }
-    // End Op ff Subops
-  }
+:(before "End Op ff Subops")
+case 4: {  // jump to r/m32
+  trace(90, "run") << "jump to r/m32" << end();
+  int32_t* arg2 = effective_address(modrm);
+  EIP = *arg2;
+  trace(90, "run") << "jumping to 0x" << HEXWORD << EIP << end();
   break;
 }
 
diff --git a/subx/031check_operands.cc b/subx/031check_operands.cc
index c56761ed..5f99f7b0 100644
--- a/subx/031check_operands.cc
+++ b/subx/031check_operands.cc
@@ -98,6 +98,24 @@ void init_permitted_operands() {
   //// Class A: just op, no operands
   // halt
   put(Permitted_operands, "f4", 0x00);
+  // inc
+  put(Permitted_operands, "40", 0x00);
+  put(Permitted_operands, "41", 0x00);
+  put(Permitted_operands, "42", 0x00);
+  put(Permitted_operands, "43", 0x00);
+  put(Permitted_operands, "44", 0x00);
+  put(Permitted_operands, "45", 0x00);
+  put(Permitted_operands, "46", 0x00);
+  put(Permitted_operands, "47", 0x00);
+  // dec
+  put(Permitted_operands, "48", 0x00);
+  put(Permitted_operands, "49", 0x00);
+  put(Permitted_operands, "4a", 0x00);
+  put(Permitted_operands, "4b", 0x00);
+  put(Permitted_operands, "4c", 0x00);
+  put(Permitted_operands, "4d", 0x00);
+  put(Permitted_operands, "4e", 0x00);
+  put(Permitted_operands, "4f", 0x00);
   // push
   put(Permitted_operands, "50", 0x00);
   put(Permitted_operands, "51", 0x00);
diff --git a/subx/opcodes b/subx/opcodes
index 77630208..41f2e65d 100644
--- a/subx/opcodes
+++ b/subx/opcodes
@@ -17,6 +17,22 @@ Opcodes currently supported by SubX:
   39: compare: set SF if rm32 < r32
   3b: compare: set SF if r32 < rm32
   3d: compare: set SF if R0 < imm32
+  40: increment R0 (EAX)
+  41: increment R1 (ECX)
+  42: increment R2 (EDX)
+  43: increment R3 (EBX)
+  44: increment R4 (ESP)
+  45: increment R5 (EBP)
+  46: increment R6 (ESI)
+  47: increment R7 (EDI)
+  48: decrement R0 (EAX)
+  49: decrement R1 (ECX)
+  4a: decrement R2 (EDX)
+  4b: decrement R3 (EBX)
+  4c: decrement R4 (ESP)
+  4d: decrement R5 (EBP)
+  4e: decrement R6 (ESI)
+  4f: decrement R7 (EDI)
   50: push R0 (EAX) to stack
   51: push R1 (ECX) to stack
   52: push R2 (EDX) to stack
@@ -63,7 +79,7 @@ Opcodes currently supported by SubX:
   eb: jump disp8 bytes away
   f4: halt
   f7: bitwise complement of rm32
-  ff: jump/push/call rm32 based on subop
+  ff: inc/dec/jump/push/call rm32 based on subop
   0f 84: jump disp16 bytes away if ZF is set
   0f 85: jump disp16 bytes away if ZF is not set
   0f 8c: jump disp16 bytes away if lesser (SF != OF)