about summary refs log tree commit diff stats
path: root/subx
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-09-23 11:17:11 -0700
committerKartik Agaram <vc@akkartik.com>2018-09-23 11:17:11 -0700
commitd48cfd0f36e21f6515285157b785a302932ed675 (patch)
treed965b4a82c18f1c8d70c42594d1639ebaf5e6a4f /subx
parentaa00959024643a33f766ef3f060a934006fe7725 (diff)
downloadmu-d48cfd0f36e21f6515285157b785a302932ed675.tar.gz
4505
Extract a helper from the factorial unit test: check_ints_equal.

Start of a vocabulary for unit tests.

I *could* also start thinking of supporting multi-file programs, but I'm
going to resist the temptation for now. Copy helpers as necessary, and
allow them to mutate and diverge for a while before we pummel them into
a Procrustean "standard library". Extracting a body of shared code immediately
starts to discourage innovation in the shared code.
Diffstat (limited to 'subx')
-rw-r--r--subx/035labels.cc10
-rwxr-xr-xsubx/apps/factorialbin410 -> 455 bytes
-rw-r--r--subx/apps/factorial.subx35
3 files changed, 37 insertions, 8 deletions
diff --git a/subx/035labels.cc b/subx/035labels.cc
index fc2ccd8c..207b09b1 100644
--- a/subx/035labels.cc
+++ b/subx/035labels.cc
@@ -89,6 +89,8 @@ void compute_byte_indices_for_labels(const segment& code, map<string, int32_t>&
           raise << "'" << to_string(inst) << "': label definition (':') not allowed in operand\n" << end();
         if (j > 0)
           raise << "'" << to_string(inst) << "': labels can only be the first word in a line.\n" << end();
+        if (Dump_map)
+          cerr << "0x" << HEXWORD << (code.start + current_byte) << ' ' << label << '\n';
         put(byte_index, label, current_byte);
         trace(99, "transform") << "label '" << label << "' is at address " << (current_byte+code.start) << end();
         // no modifying current_byte; label definitions won't be in the final binary
@@ -97,6 +99,14 @@ void compute_byte_indices_for_labels(const segment& code, map<string, int32_t>&
   }
 }
 
+:(before "End Globals")
+bool Dump_map = false;  // currently used only by 'subx translate'
+:(before "End Commandline Options")
+else if (is_equal(*arg, "--map")) {
+  Dump_map = true;
+}
+
+:(code)
 void drop_labels(segment& code) {
   for (int i = 0;  i < SIZE(code.lines);  ++i) {
     line& inst = code.lines.at(i);
diff --git a/subx/apps/factorial b/subx/apps/factorial
index 07c92714..1d61ad03 100755
--- a/subx/apps/factorial
+++ b/subx/apps/factorial
Binary files differdiff --git a/subx/apps/factorial.subx b/subx/apps/factorial.subx
index 9aef6634..36bc90f8 100644
--- a/subx/apps/factorial.subx
+++ b/subx/apps/factorial.subx
@@ -89,9 +89,28 @@ test_factorial:
   e8/call  factorial/disp32
     # discard arg
   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
-  # if EAX == 120
-  3d/compare                      .               .             .           .             .           .           .               0x78/imm32/120    # compare EAX with 120
-  75/jump-if-unequal              .               .             .           .             .           .           $test_factorial:else/disp8
+  # check_ints_equal(EAX, 120, failure message)
+    # push args
+  50/push-EAX
+  68/push  0x78/imm32/expected-120
+  68/push  "F - test_factorial"/imm32
+    # call
+  e8/call  check_ints_equal/disp32
+    # discard args
+  81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add 12 to ESP
+  # end
+  c3/return
+
+## helpers
+
+# print msg to stderr if a != b, otherwise print "."
+check_ints_equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
+  # load args into EAX, EBX and ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   0xc/disp8       .                 # copy *(ESP+12) to EAX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           3/r32/EBX   0x8/disp8       .                 # copy *(ESP+8) to EBX
+  # if EAX == b/EBX
+  39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
+  75/jump-if-unequal  $check_ints_equal:else/disp8
     # print('.')
       # push args
   68/push  "."/imm32
@@ -102,10 +121,12 @@ test_factorial:
     # return
   c3/return
   # else:
-$test_factorial:else:
-    # print('F')
+$check_ints_equal:else:
+  # copy msg into ECX
+  8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
+    # print(ECX)
       # push args
-  68/push  "F"/imm32
+  51/push-ECX
       # call
   e8/call  write_stderr/disp32
       # discard arg
@@ -113,8 +134,6 @@ $test_factorial:else:
   # end
   c3/return
 
-## helpers
-
 # compare two null-terminated ascii strings
 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
 argv_equal:  # (s1, s2) : null-terminated ascii strings -> EAX : boolean