about summary refs log tree commit diff stats
path: root/subx/apps
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-12-09 21:18:05 -0800
committerKartik Agaram <vc@akkartik.com>2018-12-09 21:18:05 -0800
commit42a933078c90f5cd7f5c8fcbee511e4f801f701a (patch)
tree1c2e5afad9f050ee40f2236138342cfd05b56972 /subx/apps
parentc91d67a29bdd5f6dbc012cfa9561bf6347996773 (diff)
downloadmu-42a933078c90f5cd7f5c8fcbee511e4f801f701a.tar.gz
4860 - stage 1 of SubX compiler in SubX is done!
I'm imagining 3 core stages total:
  1. convert text hex bytes -> binary (✓)
  2. pack and reorder operands
  3. compute label addresses

(Not including extras like error-checking.)
Diffstat (limited to 'subx/apps')
-rwxr-xr-xsubx/apps/hexbin11142 -> 11237 bytes
-rw-r--r--subx/apps/hex.subx75
2 files changed, 66 insertions, 9 deletions
diff --git a/subx/apps/hex b/subx/apps/hex
index aaca7324..4f594d95 100755
--- a/subx/apps/hex
+++ b/subx/apps/hex
Binary files differdiff --git a/subx/apps/hex.subx b/subx/apps/hex.subx
index d615a33d..c002864a 100644
--- a/subx/apps/hex.subx
+++ b/subx/apps/hex.subx
@@ -61,8 +61,8 @@ $run-main:
     # return convert(Stdin, 1/stdout, 2/stderr, ed)
     # . . push args
     50/push-EAX/ed
-    68/push  2/imm32/stderr
-    68/push  1/imm32/stdout
+    68/push  Stderr/imm32
+    68/push  Stdout/imm32
     68/push  Stdin/imm32
     # . . call
     e8/call  convert/disp32
@@ -76,12 +76,52 @@ $main:end:
 
 # the main entry point
 convert:  # in : (address buffered-file), out : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> <void>
+    # pseudocode:
+    #   repeatedly
+    #     EAX = convert-next-hex-byte(in, err, ed)
+    #     if EAX == 0xffffffff break  # eof
+    #     write-byte(out, AL)
+    #   flush(out)
+    #
     # . prolog
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # . save registers
+    50/push-EAX
+$convert:loop:
+    # EAX = convert-next-hex-byte(in, err, ed)
+    # . . push args
+    ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x14/disp8      .                 # push *(EBP+20)
+    ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x10/disp8      .                 # push *(EBP+16)
+    ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           8/disp8         .                 # push *(EBP+8)
+    # . . call
+    e8/call  convert-next-hex-byte/disp32
+    # . . discard first 2 args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # if EAX == 0xffffffff break
+    81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xffffffff/imm32  # compare EAX
+    74/jump-if-equal  $convert:loop-end/disp8
+    # write-byte(out, AL)
+    # . . push args
+    50/push-EAX
+    ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+    # . . call
+    e8/call  write-byte/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # loop
+    eb/jump  $convert:loop/disp8
+$convert:loop-end:
+    # flush(out)
+    # . . push args
+    ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+    # . . call
+    e8/call  flush/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 $convert:end:
     # . restore registers
+    58/pop-to-EAX
     # . epilog
     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
     5d/pop-to-EBP
@@ -97,10 +137,11 @@ convert-next-hex-byte:  # in : (address buffered-file), err : (address buffered-
     # pseudocode:
     #   EAX = scan-next-byte(in, err, ed)
     #   if (EAX == 0xffffffff) return
-    #   ECX = EAX
+    #   ECX = parse-hex-digit(EAX)
     #   EAX = scan-next-byte(in, err, ed)
     #   if (EAX == 0xffffffff) error("partial byte found.")
-    #   ECX = (ECX << 8) | EAX
+    #   EAX = parse-hex-digit(EAX)
+    #   EAX = (ECX << 4) | EAX
     #   return
     #
     # . prolog
@@ -120,6 +161,8 @@ convert-next-hex-byte:  # in : (address buffered-file), err : (address buffered-
     # if (EAX == 0xffffffff) return
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xffffffff/imm32  # compare EAX
     74/jump-if-equal  $convert-next-hex-byte:end/disp8
+    # EAX = parse-hex-digit(EAX)
+    e8/call parse-hex-digit/disp32
     # ECX = EAX
     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy EAX to ECX
     # EAX = scan-next-byte(in, err, ed)
@@ -143,9 +186,11 @@ convert-next-hex-byte:  # in : (address buffered-file), err : (address buffered-
     # . . call
     e8/call  error-byte/disp32  # never returns
 $convert-next-hex-byte:convert:
-    # EAX = (EAX << 8) | ECX
-    # . EAX <<= 8
-    c1/shift    4/subop/left        3/mod/direct    0/rm32/EAX    .           .             .           .           .               8/imm8            # shift EAX left by 8 bits
+    # EAX = parse-hex-digit(EAX)
+    e8/call parse-hex-digit/disp32
+    # EAX = (ECX << 4) | EAX
+    # . ECX <<= 4
+    c1/shift    4/subop/left        3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm8            # shift ECX left by 4 bits
     # . EAX |= ECX
     09/or                           3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # EAX = bitwise OR with ECX
 $convert-next-hex-byte:end:
@@ -242,10 +287,10 @@ test-convert-next-hex-byte:
     # return if abort
     81          7/subop/compare     1/mod/*+disp8   1/rm32/ECX    .           .             .           .           4/disp8         0/imm32           # compare *(ECX+4)
     75/jump-if-not-equal  $test-convert-next-hex-byte:end/disp8
-    # check-ints-equal(EAX, 0x61/a 0x62/b, msg)
+    # check-ints-equal(EAX, 0xab, msg)
     # . . push args
     68/push  "F - test-convert-next-hex-byte"/imm32
-    68/push  0x6261/imm32/ab
+    68/push  0xab/imm32/ab
     50/push-EAX
     # . . call
     e8/call  check-ints-equal/disp32
@@ -1528,6 +1573,18 @@ test-hex-above-f:
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
     c3/return
 
+parse-hex-digit:  # in/EAX : byte -> out/EAX : num
+    # no error checking; accepts argument in EAX
+    # if EAX <= '9' return EAX - '0'
+    3d/compare-EAX  0x39/imm32/9
+    7f/jump-if-greater  $parse-hex-digit:else/disp8
+    2d/subtract-from-EAX  0x30/imm32/0
+    c3/return
+$parse-hex-digit:else:
+    # otherwise return EAX - 'a' + 10
+    2d/subtract-from-EAX  0x57/imm32/a-10
+    c3/return
+
 skip-until-newline:  # in : (address buffered-file) -> <void>
     # pseudocode:
     #   push EAX