diff --git a/html/subx/059read-byte.subx.html b/html/subx/059read-byte.subx.html index e23ec5a7..a3ebe17f 100644 --- a/html/subx/059read-byte.subx.html +++ b/html/subx/059read-byte.subx.html @@ -119,201 +119,200 @@ if ('onhashchange' in window) { 53 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI 54 # ECX = f->read 55 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # copy *(ESI+8) to ECX - 56 # if (f->read < f->write) read byte from stream + 56 # if (f->read >= f->write) populate stream from file 57 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # compare ECX with *(ESI+4) 58 7c/jump-if-lesser $read-byte:from-stream/disp8 - 59 # otherwise first populate stream from file - 60 # . clear-stream(stream = f+4) - 61 # . . push args - 62 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX - 63 50/push-EAX - 64 # . . call - 65 e8/call clear-stream/disp32 - 66 # . . discard args - 67 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 68 # . EAX = read(f->fd, stream = f+4) - 69 # . . push args - 70 50/push-EAX - 71 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI - 72 # . . call - 73 e8/call read/disp32 - 74 # . . discard args - 75 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 76 # if EAX = 0 return 0xffffffff - 77 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX - 78 75/jump-if-not-equal $read-byte:from-stream/disp8 - 79 b8/copy-to-EAX 0xffffffff/imm32 - 80 eb/jump $read-byte:end/disp8 - 81 $read-byte:from-stream: - 82 # reading from stream - 83 # AL = f->data[f->read] - 84 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 85 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0x10/disp8 . # copy *(ESI+ECX+16) to AL - 86 # ++f->read - 87 ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # increment *(ESI+8) - 88 $read-byte:end: - 89 # . restore registers - 90 5e/pop-to-ESI - 91 59/pop-to-ECX - 92 # . epilog - 93 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 94 5d/pop-to-EBP - 95 c3/return - 96 - 97 # - tests - 98 - 99 test-read-byte-single: -100 # - check that read-byte returns first byte of 'file' -101 # setup -102 # . clear-stream(_test-stream) -103 # . . push args -104 68/push _test-stream/imm32 -105 # . . call -106 e8/call clear-stream/disp32 -107 # . . discard args -108 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -109 # . clear-stream(_test-buffered-file+4) -110 # . . push args -111 b8/copy-to-EAX _test-buffered-file/imm32 -112 05/add-to-EAX 4/imm32 -113 50/push-EAX -114 # . . call -115 e8/call clear-stream/disp32 -116 # . . discard args -117 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -118 # . write(_test-stream, "Ab") -119 # . . push args -120 68/push "Ab"/imm32 -121 68/push _test-stream/imm32 -122 # . . call -123 e8/call write/disp32 -124 # . . discard args -125 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -126 # read-byte(_test-buffered-file) -127 # . . push args -128 68/push _test-buffered-file/imm32 -129 # . . call -130 e8/call read-byte/disp32 -131 # . . discard args -132 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -133 # check-ints-equal(EAX, 'A', msg) -134 # . . push args -135 68/push "F - test-read-byte-single"/imm32 -136 68/push 0x41/imm32 -137 50/push-EAX -138 # . . call -139 e8/call check-ints-equal/disp32 -140 # . . discard args -141 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -142 # . end -143 c3/return -144 -145 test-read-byte-multiple: -146 # - call read-byte twice, check that second call returns second byte -147 # setup -148 # . clear-stream(_test-stream) -149 # . . push args -150 68/push _test-stream/imm32 -151 # . . call -152 e8/call clear-stream/disp32 -153 # . . discard args -154 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -155 # . clear-stream(_test-buffered-file+4) -156 # . . push args -157 b8/copy-to-EAX _test-buffered-file/imm32 -158 05/add-to-EAX 4/imm32 -159 50/push-EAX -160 # . . call -161 e8/call clear-stream/disp32 -162 # . . discard args -163 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -164 # . write(_test-stream, "Ab") -165 # . . push args -166 68/push "Ab"/imm32 -167 68/push _test-stream/imm32 -168 # . . call -169 e8/call write/disp32 -170 # . . discard args -171 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -172 # read-byte(_test-buffered-file) -173 # . . push args -174 68/push _test-buffered-file/imm32 -175 # . . call -176 e8/call read-byte/disp32 -177 # . . discard args -178 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -179 # read-byte(_test-buffered-file) -180 # . . push args -181 68/push _test-buffered-file/imm32 -182 # . . call -183 e8/call read-byte/disp32 -184 # . . discard args -185 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -186 # check-ints-equal(EAX, 'b', msg) -187 # . . push args -188 68/push "F - test-read-byte-multiple"/imm32 -189 68/push 0x62/imm32 -190 50/push-EAX -191 # . . call -192 e8/call check-ints-equal/disp32 -193 # . . discard args -194 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -195 # . end -196 c3/return -197 -198 test-read-byte-end-of-file: -199 # - call read-byte on an empty 'file', check that it returns -1 -200 # setup -201 # . clear-stream(_test-stream) -202 # . . push args -203 68/push _test-stream/imm32 -204 # . . call -205 e8/call clear-stream/disp32 -206 # . . discard args -207 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -208 # . clear-stream(_test-buffered-file+4) -209 # . . push args -210 b8/copy-to-EAX _test-buffered-file/imm32 -211 05/add-to-EAX 4/imm32 -212 50/push-EAX -213 # . . call -214 e8/call clear-stream/disp32 -215 # . . discard args -216 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -217 # read-byte(_test-buffered-file) -218 # . . push args -219 68/push _test-buffered-file/imm32 -220 # . . call -221 e8/call read-byte/disp32 -222 # . . discard args -223 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -224 # check-ints-equal(EAX, -1, msg) -225 # . . push args -226 68/push "F - test-read-byte-end-of-file"/imm32 -227 68/push -1/imm32 -228 50/push-EAX -229 # . . call -230 e8/call check-ints-equal/disp32 -231 # . . discard args -232 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -233 # . end -234 c3/return -235 -236 == data -237 -238 _test-buffered-file: -239 # file descriptor or (address stream) -240 _test-stream/imm32 -241 # current write index -242 00 00 00 00 -243 # current read index -244 00 00 00 00 -245 # length (8) -246 08 00 00 00 -247 # data -248 00 00 00 00 00 00 00 00 # 8 bytes -249 -250 # . . vim:nowrap:textwidth=0 + 59 # . clear-stream(stream = f+4) + 60 # . . push args + 61 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX + 62 50/push-EAX + 63 # . . call + 64 e8/call clear-stream/disp32 + 65 # . . discard args + 66 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 67 # . EAX = read(f->fd, stream = f+4) + 68 # . . push args + 69 50/push-EAX + 70 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI + 71 # . . call + 72 e8/call read/disp32 + 73 # . . discard args + 74 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 75 # if EAX = 0 return 0xffffffff + 76 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX + 77 75/jump-if-not-equal $read-byte:from-stream/disp8 + 78 b8/copy-to-EAX 0xffffffff/imm32 + 79 eb/jump $read-byte:end/disp8 + 80 $read-byte:from-stream: + 81 # read byte from stream + 82 # AL = f->data[f->read] + 83 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX + 84 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0x10/disp8 . # copy *(ESI+ECX+16) to AL + 85 # ++f->read + 86 ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # increment *(ESI+8) + 87 $read-byte:end: + 88 # . restore registers + 89 5e/pop-to-ESI + 90 59/pop-to-ECX + 91 # . epilog + 92 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 93 5d/pop-to-EBP + 94 c3/return + 95 + 96 # - tests + 97 + 98 test-read-byte-single: + 99 # - check that read-byte returns first byte of 'file' +100 # setup +101 # . clear-stream(_test-stream) +102 # . . push args +103 68/push _test-stream/imm32 +104 # . . call +105 e8/call clear-stream/disp32 +106 # . . discard args +107 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +108 # . clear-stream(_test-buffered-file+4) +109 # . . push args +110 b8/copy-to-EAX _test-buffered-file/imm32 +111 05/add-to-EAX 4/imm32 +112 50/push-EAX +113 # . . call +114 e8/call clear-stream/disp32 +115 # . . discard args +116 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +117 # . write(_test-stream, "Ab") +118 # . . push args +119 68/push "Ab"/imm32 +120 68/push _test-stream/imm32 +121 # . . call +122 e8/call write/disp32 +123 # . . discard args +124 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +125 # read-byte(_test-buffered-file) +126 # . . push args +127 68/push _test-buffered-file/imm32 +128 # . . call +129 e8/call read-byte/disp32 +130 # . . discard args +131 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +132 # check-ints-equal(EAX, 'A', msg) +133 # . . push args +134 68/push "F - test-read-byte-single"/imm32 +135 68/push 0x41/imm32 +136 50/push-EAX +137 # . . call +138 e8/call check-ints-equal/disp32 +139 # . . discard args +140 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +141 # . end +142 c3/return +143 +144 test-read-byte-multiple: +145 # - call read-byte twice, check that second call returns second byte +146 # setup +147 # . clear-stream(_test-stream) +148 # . . push args +149 68/push _test-stream/imm32 +150 # . . call +151 e8/call clear-stream/disp32 +152 # . . discard args +153 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +154 # . clear-stream(_test-buffered-file+4) +155 # . . push args +156 b8/copy-to-EAX _test-buffered-file/imm32 +157 05/add-to-EAX 4/imm32 +158 50/push-EAX +159 # . . call +160 e8/call clear-stream/disp32 +161 # . . discard args +162 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +163 # . write(_test-stream, "Ab") +164 # . . push args +165 68/push "Ab"/imm32 +166 68/push _test-stream/imm32 +167 # . . call +168 e8/call write/disp32 +169 # . . discard args +170 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +171 # read-byte(_test-buffered-file) +172 # . . push args +173 68/push _test-buffered-file/imm32 +174 # . . call +175 e8/call read-byte/disp32 +176 # . . discard args +177 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +178 # read-byte(_test-buffered-file) +179 # . . push args +180 68/push _test-buffered-file/imm32 +181 # . . call +182 e8/call read-byte/disp32 +183 # . . discard args +184 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +185 # check-ints-equal(EAX, 'b', msg) +186 # . . push args +187 68/push "F - test-read-byte-multiple"/imm32 +188 68/push 0x62/imm32 +189 50/push-EAX +190 # . . call +191 e8/call check-ints-equal/disp32 +192 # . . discard args +193 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +194 # . end +195 c3/return +196 +197 test-read-byte-end-of-file: +198 # - call read-byte on an empty 'file', check that it returns -1 +199 # setup +200 # . clear-stream(_test-stream) +201 # . . push args +202 68/push _test-stream/imm32 +203 # . . call +204 e8/call clear-stream/disp32 +205 # . . discard args +206 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +207 # . clear-stream(_test-buffered-file+4) +208 # . . push args +209 b8/copy-to-EAX _test-buffered-file/imm32 +210 05/add-to-EAX 4/imm32 +211 50/push-EAX +212 # . . call +213 e8/call clear-stream/disp32 +214 # . . discard args +215 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +216 # read-byte(_test-buffered-file) +217 # . . push args +218 68/push _test-buffered-file/imm32 +219 # . . call +220 e8/call read-byte/disp32 +221 # . . discard args +222 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +223 # check-ints-equal(EAX, -1, msg) +224 # . . push args +225 68/push "F - test-read-byte-end-of-file"/imm32 +226 68/push -1/imm32 +227 50/push-EAX +228 # . . call +229 e8/call check-ints-equal/disp32 +230 # . . discard args +231 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +232 # . end +233 c3/return +234 +235 == data +236 +237 _test-buffered-file: +238 # file descriptor or (address stream) +239 _test-stream/imm32 +240 # current write index +241 00 00 00 00 +242 # current read index +243 00 00 00 00 +244 # length (8) +245 08 00 00 00 +246 # data +247 00 00 00 00 00 00 00 00 # 8 bytes +248 +249 # . . vim:nowrap:textwidth=0 diff --git a/html/subx/062write-byte.subx.html b/html/subx/062write-byte.subx.html new file mode 100644 index 00000000..d6a65565 --- /dev/null +++ b/html/subx/062write-byte.subx.html @@ -0,0 +1,229 @@ + + + + +Mu - subx/062write-byte.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/subx/062write-byte.subx +
+  1 # write-byte: write a single byte to a buffered-file. The write may be buffered.
+  2 # flush: write out any buffered writes to disk.
+  3 #
+  4 # TODO: Come up with a way to signal failure to write to disk. This is hard
+  5 # since the failure may impact previous calls that were buffered.
+  6 
+  7 == data
+  8 
+  9 # The buffered file for standard output.
+ 10 
+ 11 Stdout:
+ 12     # file descriptor or (address stream)
+ 13     01 00 00 00  # 1 = standard output
+ 14     # current write index
+ 15     00 00 00 00
+ 16     # current read index
+ 17     00 00 00 00
+ 18     # length (8)
+ 19     08 00 00 00
+ 20     # data
+ 21     00 00 00 00 00 00 00 00  # 8 bytes
+ 22 
+ 23 # TODO: 8 bytes is too small. We'll need to grow the buffer for efficiency. But
+ 24 # I don't want to type 1024 bytes here.
+ 25 
+ 26 == code
+ 27 #   instruction                     effective address                                                   register    displacement    immediate
+ 28 # . op          subop               mod             rm32          base        index         scale       r32
+ 29 # . 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
+ 30 
+ 31 # main:
+ 32     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
+ 33     # syscall(exit, Num-test-failures)
+ 34     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
+ 35     b8/copy-to-EAX  1/imm32
+ 36     cd/syscall  0x80/imm8
+ 37 
+ 38 # Write lower byte of 'n' to 'f'.
+ 39 write-byte:  # f : (address buffered-file), n : num -> <void>
+ 40     # . prolog
+ 41     55/push-EBP
+ 42     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 43     # . save registers
+ 44     51/push-ECX
+ 45     56/push-ESI
+ 46     # ESI = f
+ 47     8b/copy                         1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+ 48     # ECX = f->write
+ 49     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+ 50     # if (f->write >= f->length) flush and clear stream
+ 51     3b/compare                      1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   0xc/disp8       .                 # compare ECX with *(ESI+12)
+ 52     7c/jump-if-lesser  $write-byte:to-stream/disp8
+ 53     # . flush-buffered-file(f)
+ 54     # . . push args
+ 55     56/push-ESI
+ 56     # . . call
+ 57     e8/call  flush/disp32
+ 58     # . . discard args
+ 59     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 60     # . clear-stream(stream = f+4)
+ 61     # . . push args
+ 62     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   4/disp8         .                 # copy ESI+4 to EAX
+ 63     50/push-EAX
+ 64     # . . call
+ 65     e8/call  clear-stream/disp32
+ 66     # . . discard args
+ 67     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 68 $write-byte:to-stream:
+ 69     # write to stream
+ 70     # f->data[f->read] = LSB(n)
+ 71     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 72     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           0/r32/AL    0xc/disp8       .                 # copy byte at *(EBP+12) to AL
+ 73     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0x10/disp8      .                 # copy AL to *(ESI+ECX+16)
+ 74     # ++f->read
+ 75     ff          0/subop/increment   1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # increment *(ESI+4)
+ 76     # . restore registers
+ 77     5e/pop-to-ESI
+ 78     59/pop-to-ECX
+ 79     # . epilog
+ 80     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 81     5d/pop-to-EBP
+ 82     c3/return
+ 83 
+ 84 flush:  # f : (address buffered-file) -> <void>
+ 85     # . prolog
+ 86     55/push-EBP
+ 87     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 88     # . save registers
+ 89     50/push-EAX
+ 90     51/push-ECX
+ 91     # EAX = f
+ 92     8b/copy                         1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
+ 93     # write-stream(f->fd, data = f+4)
+ 94       # . . push args
+ 95     8d/copy-address                 1/mod/*+disp8   0/rm32/EAX    .           .             .           1/r32/ECX   4/disp8         .                 # copy EAX+4 to ECX
+ 96     51/push-ECX
+ 97     ff          6/subop/push        0/mod/indirect  0/rm32/EAX    .           .             .           .           .               .                 # push *EAX
+ 98       # . . call
+ 99     e8/call  write-stream/disp32
+100       # . . discard args
+101     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+102     # . restore registers
+103     59/pop-to-ECX
+104     58/pop-to-EAX
+105     # . epilog
+106     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+107     5d/pop-to-EBP
+108     c3/return
+109 
+110 # - tests
+111 
+112 test-write-byte-single:
+113     # - check that read-byte returns first byte of 'file'
+114     # setup
+115     # . clear-stream(_test-stream)
+116     # . . push args
+117     68/push  _test-stream/imm32
+118     # . . call
+119     e8/call  clear-stream/disp32
+120     # . . discard args
+121     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+122     # . clear-stream(_test-buffered-file+4)
+123     # . . push args
+124     b8/copy-to-EAX  _test-buffered-file/imm32
+125     05/add-to-EAX  4/imm32
+126     50/push-EAX
+127     # . . call
+128     e8/call  clear-stream/disp32
+129     # . . discard args
+130     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+131     # write-byte(_test-buffered-file, 'A')
+132     # . . push args
+133     68/push  0x41/imm32
+134     68/push  _test-buffered-file/imm32
+135     # . . call
+136     e8/call  write-byte/disp32
+137     # . . discard args
+138     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+139     # flush(_test-buffered-file)
+140     # . . push args
+141     68/push  _test-buffered-file/imm32
+142     # . . call
+143     e8/call  flush/disp32
+144     # . . discard args
+145     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+146     # check-ints-equal(*_test-stream->data, 'A', msg)
+147     # . . push args
+148     68/push  "F - test-write-byte-single"/imm32
+149     68/push  0x41/imm32
+150     # . . push *_test-stream->data
+151     b8/copy-to-EAX  _test-stream/imm32
+152     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           0xc/disp8       .                 # push *(EAX+12)
+153     # . . call
+154     e8/call  check-ints-equal/disp32
+155     # . . discard args
+156     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+157     # . end
+158     c3/return
+159 
+160 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/subx/059read-byte.subx b/subx/059read-byte.subx index 07958a63..305bcbb8 100644 --- a/subx/059read-byte.subx +++ b/subx/059read-byte.subx @@ -53,10 +53,9 @@ read-byte: # f : (address buffered-file) -> byte-or-eof/EAX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI # ECX = f->read 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # copy *(ESI+8) to ECX - # if (f->read < f->write) read byte from stream + # if (f->read >= f->write) populate stream from file 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # compare ECX with *(ESI+4) 7c/jump-if-lesser $read-byte:from-stream/disp8 - # otherwise first populate stream from file # . clear-stream(stream = f+4) # . . push args 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX @@ -79,7 +78,7 @@ read-byte: # f : (address buffered-file) -> byte-or-eof/EAX b8/copy-to-EAX 0xffffffff/imm32 eb/jump $read-byte:end/disp8 $read-byte:from-stream: - # reading from stream + # read byte from stream # AL = f->data[f->read] 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0x10/disp8 . # copy *(ESI+ECX+16) to AL diff --git a/subx/062write-byte.subx b/subx/062write-byte.subx new file mode 100644 index 00000000..fedde5d9 --- /dev/null +++ b/subx/062write-byte.subx @@ -0,0 +1,160 @@ +# write-byte: write a single byte to a buffered-file. The write may be buffered. +# flush: write out any buffered writes to disk. +# +# TODO: Come up with a way to signal failure to write to disk. This is hard +# since the failure may impact previous calls that were buffered. + +== data + +# The buffered file for standard output. + +Stdout: + # file descriptor or (address stream) + 01 00 00 00 # 1 = standard output + # current write index + 00 00 00 00 + # current read index + 00 00 00 00 + # length (8) + 08 00 00 00 + # data + 00 00 00 00 00 00 00 00 # 8 bytes + +# TODO: 8 bytes is too small. We'll need to grow the buffer for efficiency. But +# I don't want to type 1024 bytes here. + +== code +# instruction effective address register 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: + e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. + # syscall(exit, Num-test-failures) + 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + b8/copy-to-EAX 1/imm32 + cd/syscall 0x80/imm8 + +# Write lower byte of 'n' to 'f'. +write-byte: # f : (address buffered-file), n : num -> + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # . save registers + 51/push-ECX + 56/push-ESI + # ESI = f + 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI + # ECX = f->write + 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX + # if (f->write >= f->length) flush and clear stream + 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # compare ECX with *(ESI+12) + 7c/jump-if-lesser $write-byte:to-stream/disp8 + # . flush-buffered-file(f) + # . . push args + 56/push-ESI + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # . clear-stream(stream = f+4) + # . . push args + 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX + 50/push-EAX + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +$write-byte:to-stream: + # write to stream + # f->data[f->read] = LSB(n) + 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX + 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/AL 0xc/disp8 . # copy byte at *(EBP+12) to AL + 88/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0x10/disp8 . # copy AL to *(ESI+ECX+16) + # ++f->read + ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # increment *(ESI+4) + # . restore registers + 5e/pop-to-ESI + 59/pop-to-ECX + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +flush: # f : (address buffered-file) -> + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # . save registers + 50/push-EAX + 51/push-ECX + # EAX = f + 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX + # write-stream(f->fd, data = f+4) + # . . push args + 8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy EAX+4 to ECX + 51/push-ECX + ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX + # . . call + e8/call write-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # . restore registers + 59/pop-to-ECX + 58/pop-to-EAX + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +# - tests + +test-write-byte-single: + # - check that read-byte returns first byte of 'file' + # setup + # . clear-stream(_test-stream) + # . . push args + 68/push _test-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # . clear-stream(_test-buffered-file+4) + # . . push args + b8/copy-to-EAX _test-buffered-file/imm32 + 05/add-to-EAX 4/imm32 + 50/push-EAX + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # write-byte(_test-buffered-file, 'A') + # . . push args + 68/push 0x41/imm32 + 68/push _test-buffered-file/imm32 + # . . call + e8/call write-byte/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # flush(_test-buffered-file) + # . . push args + 68/push _test-buffered-file/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # check-ints-equal(*_test-stream->data, 'A', msg) + # . . push args + 68/push "F - test-write-byte-single"/imm32 + 68/push 0x41/imm32 + # . . push *_test-stream->data + b8/copy-to-EAX _test-stream/imm32 + ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # . end + c3/return + +# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1 index 10003ae7..a9c23773 100755 Binary files a/subx/apps/crenshaw2-1 and b/subx/apps/crenshaw2-1 differ diff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b index 20eaafe0..982a1f59 100755 Binary files a/subx/apps/crenshaw2-1b and b/subx/apps/crenshaw2-1b differ diff --git a/subx/apps/factorial b/subx/apps/factorial index 7d867940..77ac0adb 100755 Binary files a/subx/apps/factorial and b/subx/apps/factorial differ