about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--subx/010vm.cc9
-rw-r--r--subx/012direct_addressing.cc5
-rw-r--r--subx/014immediate_addressing.cc1
-rw-r--r--subx/018functions.cc1
-rw-r--r--subx/ex7bin0 -> 156 bytes
-rw-r--r--subx/ex7.subx90
6 files changed, 105 insertions, 1 deletions
diff --git a/subx/010vm.cc b/subx/010vm.cc
index e89e2566..0a549982 100644
--- a/subx/010vm.cc
+++ b/subx/010vm.cc
@@ -147,6 +147,7 @@ inline void write_mem_i32(uint32_t addr, int32_t val) {
 void run_one_instruction() {
   uint8_t op=0, op2=0, op3=0;
   trace(90, "run") << "inst: 0x" << HEXWORD << EIP << end();
+//?   dump_registers();
 //?   cerr << "inst: 0x" << EIP << '\n';
   switch (op = next()) {
   case 0xf4:  // hlt
@@ -191,6 +192,14 @@ inline uint8_t next() {
   return read_mem_u8(EIP++);
 }
 
+void dump_registers() {
+  for (int i = 0;  i < NUM_INT_REGISTERS;  ++i) {
+    if (i > 0) cerr << "; ";
+    cerr << "  " << i << ": " << HEXWORD << Reg[i].u;
+  }
+  cerr << '\n';
+}
+
 //: start tracking supported opcodes
 :(before "End Globals")
 map</*op*/string, string> name;
diff --git a/subx/012direct_addressing.cc b/subx/012direct_addressing.cc
index aefe3214..e4f7f8a9 100644
--- a/subx/012direct_addressing.cc
+++ b/subx/012direct_addressing.cc
@@ -109,7 +109,7 @@ case 0xaf: {  // multiply r32 into r/m32
   uint8_t arg2 = (modrm>>3)&0x7;
   trace(90, "run") << "multiply " << rname(arg2) << " into r/m32" << end();
   int32_t* arg1 = effective_address(modrm);
-  BINARY_ARITHMETIC_OP(*, *arg1, Reg[arg2].i);
+  BINARY_ARITHMETIC_OP(*, Reg[arg2].i, *arg1);
   break;
 }
 
@@ -363,6 +363,7 @@ case 0x56:
 case 0x57: {  // push r32 to stack
   uint8_t reg = op & 0x7;
   trace(90, "run") << "push " << rname(reg) << end();
+//?   cerr << "push: " << NUM(reg) << ": " << Reg[reg].u << " => " << Reg[ESP].u << '\n';
   push(Reg[reg].u);
   break;
 }
@@ -409,7 +410,9 @@ case 0x5e:
 case 0x5f: {  // pop stack into r32
   uint8_t reg = op & 0x7;
   trace(90, "run") << "pop into " << rname(reg) << end();
+//?   cerr << "pop from " << Reg[ESP].u << '\n';
   Reg[reg].u = pop();
+//?   cerr << "=> " << NUM(reg) << ": " << Reg[reg].u << '\n';
   break;
 }
 :(code)
diff --git a/subx/014immediate_addressing.cc b/subx/014immediate_addressing.cc
index 8ef36f95..c75c419e 100644
--- a/subx/014immediate_addressing.cc
+++ b/subx/014immediate_addressing.cc
@@ -469,6 +469,7 @@ put(name, "68", "push imm32 to stack");
 case 0x68: {
   uint32_t val = static_cast<uint32_t>(imm32());
   trace(90, "run") << "push imm32 0x" << HEXWORD << val << end();
+//?   cerr << "push: " << val << " => " << Reg[ESP].u << '\n';
   push(val);
   trace(90, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end();
   trace(90, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
diff --git a/subx/018functions.cc b/subx/018functions.cc
index a557abf5..964ca977 100644
--- a/subx/018functions.cc
+++ b/subx/018functions.cc
@@ -18,6 +18,7 @@ put(name, "e8", "call disp32");
 case 0xe8: {  // call disp32 relative to next EIP
   int32_t offset = imm32();
   trace(90, "run") << "call imm32 0x" << HEXWORD << offset << end();
+//?   cerr << "push: EIP: " << EIP << " => " << Reg[ESP].u << '\n';
   push(EIP);
   EIP += offset;
   trace(90, "run") << "jumping to 0x" << HEXWORD << EIP << end();
diff --git a/subx/ex7 b/subx/ex7
new file mode 100644
index 00000000..daea2cf4
--- /dev/null
+++ b/subx/ex7
Binary files differdiff --git a/subx/ex7.subx b/subx/ex7.subx
new file mode 100644
index 00000000..c95ed361
--- /dev/null
+++ b/subx/ex7.subx
@@ -0,0 +1,90 @@
+## compute the factorial of 5, and return the result in the exit code
+#
+# To run:
+#   $ subx translate ex7.subx ex7
+#   $ subx run ex7
+# Expected result:
+#   $ echo $?
+#   120
+
+== 0x08048054  # code segment, after leaving room for ELF header
+# instruction                     effective address                                           operand     displacement    immediate
+# op          subop               mod             rm32          base      index     scale     r32
+# 1-3 bytes   3 bits              2 bits          3 bits        3 bits    3 bits    2 bits    2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+
+# main:
+  # prepare to make a call
+# 54
+  55/push                                                                                                                                   # push EBP
+# 55
+  89/copy                         3/mod/direct    5/rm32/EBP                                  4/r32/ESP                                     # copy ESP to EBP
+# 57
+  # factorial(5)
+  68/push                                                                                                                 5/imm32           # push 5
+# 5c
+  e8/call                                                                                                 factorial/disp32
+# 61
+  # discard arg
+  5a/pop                                                                                                                                    # pop into EDX
+# 62
+  # clean up after call
+  89/copy                         3/mod/direct    4/rm32/ESP                                  5/r32/EBP                                     # copy EBP to ESP
+# 64
+  5d/pop                                                                                                                                    # pop to EBP
+
+  # exit(EAX)
+# 65
+  89/copy                         3/mod/direct    3/rm32/EBX                                  0/r32/EAX                                     # copy EAX to EBX
+# 67
+  b8/copy                                                                                                                 1/imm32           # copy 1 to EAX
+# 6c
+  cd/syscall                                                                                                              0x80/imm8         # int 80h
+
+# factorial(n)
+# 6e
+factorial:
+  # initialize n
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp   4/index/none     2/r32/edx   4/disp8                           # copy *(ESP+4) to EDX
+# 72
+  # initialize EAX to 1 (base case)
+  b8/copy                                                                                                                 1/imm32           # copy 1 to EAX
+# 77
+  # if (n <= 1) jump exit
+  81          7/subop/compare     3/mod/direct    2/rm32/EDX                                                              1/imm32           # compare EDX with 1
+# 7d
+  7e/jump-if                                                                                              factorial:exit/disp8              # jump if <= to exit
+# 7f
+  # EBX: n-1
+  89/copy                         3/mod/direct    3/rm32/EBX                                  2/r32/EDX                                     # copy EDX to EBX
+# 81
+  81          5/subop/subtract    3/mod/direct    3/rm32/EBX                                                              1/imm32           # subtract 1 from EBX
+# 87
+  # prepare call
+  55/push                                                                                                                                   # push EBP
+# 88
+  89/copy                         3/mod/direct    5/rm32/EBP                                  4/r32/ESP                                     # copy ESP to EBP
+  # EAX: factorial(n-1)
+# 8a
+  53/push                                                                                                                                   # push EBX
+# 8b
+  e8/call                                                                                                 factorial/disp32
+# 90
+  # discard arg
+  5e/pop                                                                                                                                    # pop into ESI
+# 91
+  # clean up after call
+  89/copy                         3/mod/direct    4/rm32/ESP                                  5/r32/EBP                                     # copy EBP to ESP
+# 93
+  5d/pop                                                                                                                                    # pop to EBP
+# 94
+  # refresh n
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp   4/index/none     2/r32/edx   4/disp8                           # copy *(ESP+4) to EDX
+# 98
+  # return n * factorial(n-1)
+  0f af/multiply                  3/mod/direct    2/rm32/EDX                                  0/r32/EAX                                     # multiply EDX (n) into EAX (factorial(n-1))
+  # TODO: check for overflow
+# 9b
+factorial:exit:
+  c3/return
+
+# vim:ft=subx:nowrap:so=0