about summary refs log tree commit diff stats
path: root/subx/010---vm.cc
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-05-12 07:36:18 -0700
committerKartik Agaram <vc@akkartik.com>2019-05-12 07:41:34 -0700
commit8c1a69089bcb0be8ee869a3f83c3151a7083e27c (patch)
tree319e3b04bb5d94b0306e336dff573d6685e8d683 /subx/010---vm.cc
parentd5d43e044d16335a3a865a8c9f5aea5cbad73360 (diff)
downloadmu-8c1a69089bcb0be8ee869a3f83c3151a7083e27c.tar.gz
snapshot of carry flag implementation
Tests failing.

This approach seems wrong. I'm not sure even the tests are correct. Also,
some open questions:

1. Should setting the overflow flag always set the carry flag?
2. Should the carry flag only be set on add/subtract/compare, or by all
arithmetic ops?
3. Had to turn off the -ftrapv flag in `build`. Is there a way to detect
overflow without actually causing overflow?

Once we start setting CF correctly we have to implement jump above/below
instructions (8- and 32-bit displacement variants).

https://github.com/akkartik/mu/issues/30
Diffstat (limited to 'subx/010---vm.cc')
-rw-r--r--subx/010---vm.cc48
1 files changed, 31 insertions, 17 deletions
diff --git a/subx/010---vm.cc b/subx/010---vm.cc
index 31e5608f..00a2dee4 100644
--- a/subx/010---vm.cc
+++ b/subx/010---vm.cc
@@ -62,7 +62,10 @@ put_new(Help, "registers",
   "- 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 carry flag (CF): usually set if an arithmetic result overflows by just one bit.\n"
+  "  Useful for operating on unsigned numbers.\n"
+  "- the overflow flag (OF): usually set if an arithmetic result overflows by more than one bit.\n"
+  "  Useful for operating on signed numbers.\n"
   "The flag bits are read by conditional jumps.\n"
   "\n"
   "For complete details on how different instructions update the flags, consult the IA-32\n"
@@ -78,9 +81,10 @@ put_new(Help, "registers",
 // the subset of x86 flag registers we care about
 bool SF = false;  // sign flag
 bool ZF = false;  // zero flag
+bool CF = false;  // carry flag
 bool OF = false;  // overflow flag
 :(before "End Reset")
-SF = ZF = OF = false;
+SF = ZF = CF = OF = false;
 
 //: how the flag registers are updated after each instruction
 
@@ -88,25 +92,35 @@ SF = ZF = OF = false;
 // Combine 'arg1' and 'arg2' with arithmetic operation 'op' and store the
 // result in 'arg1', then update flags.
 // beware: no side-effects in args
-#define BINARY_ARITHMETIC_OP(op, arg1, arg2) { \
-  /* arg1 and arg2 must be signed */ \
-  int64_t tmp = arg1 op arg2; \
-  arg1 = arg1 op arg2; \
-  trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << arg1 << end(); \
-  SF = (arg1 < 0); \
-  ZF = (arg1 == 0); \
-  OF = (arg1 != tmp); \
+#define BINARY_ARITHMETIC_OP(op, signed_arg1, signed_arg2) { \
+  cerr << signed_arg1 << " vs " << signed_arg2 << '\n'; \
+  int64_t signed_full_result = signed_arg1 op signed_arg2; \
+  signed_arg1 = signed_arg1 op signed_arg2; \
+  trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << signed_arg1 << end(); \
+  SF = (signed_arg1 < 0); \
+  ZF = (signed_arg1 == 0); \
+  OF = (signed_arg1 != signed_full_result); \
+  /* CF is more complex */ \
+  uint32_t unsigned_arg1 = static_cast<uint32_t>(signed_arg1); \
+  uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2); \
+  cerr << unsigned_arg1 << " vs " << unsigned_arg2 << '\n'; \
+  uint32_t unsigned_result = unsigned_arg1 op unsigned_arg2; \
+  cerr << "result: " << unsigned_result << '\n'; \
+  uint64_t unsigned_full_result = unsigned_arg1 op unsigned_arg2; \
+  CF = (unsigned_result != unsigned_full_result); \
+  trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); \
 }
 
 // Combine 'arg1' and 'arg2' with bitwise operation 'op' and store the result
 // in 'arg1', then update flags.
-#define BINARY_BITWISE_OP(op, arg1, arg2) { \
-  /* arg1 and arg2 must be unsigned */ \
-  arg1 = arg1 op arg2; \
-  trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << arg1 << end(); \
-  SF = (arg1 >> 31); \
-  ZF = (arg1 == 0); \
+#define BINARY_BITWISE_OP(op, unsigned_arg1, unsigned_arg2) { \
+  unsigned_arg1 = unsigned_arg1 op unsigned_arg2; \
+  trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << unsigned_arg1 << end(); \
+  SF = (unsigned_arg1 >> 31); \
+  ZF = (unsigned_arg1 == 0); \
+  CF = false; \
   OF = false; \
+  trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); \
 }
 
 //:: simulated RAM
@@ -374,7 +388,7 @@ void dump_registers() {
     if (i > 0) out << "; ";
     out << "  " << i << ": " << std::hex << std::setw(8) << std::setfill('_') << Reg[i].u;
   }
-  out << " -- SF: " << SF << "; ZF: " << ZF << "; OF: " << OF;
+  out << " -- SF: " << SF << "; ZF: " << ZF << "; CF: " << CF << "; OF: " << OF;
   trace(Callstack_depth+1, "run") << out.str() << end();
 }