From ec73ed1230d75deb0f913a32617c9f1e0a5ca640 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 10 Jul 2020 23:44:10 -0700 Subject: 6631 --- html/115write-byte.subx.html | 469 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 469 insertions(+) create mode 100644 html/115write-byte.subx.html (limited to 'html/115write-byte.subx.html') diff --git a/html/115write-byte.subx.html b/html/115write-byte.subx.html new file mode 100644 index 00000000..b28af487 --- /dev/null +++ b/html/115write-byte.subx.html @@ -0,0 +1,469 @@ + + + + +Mu - 115write-byte.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/115write-byte.subx +
+  1 # write-byte-buffered: add a single byte to a buffered-file.
+  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 Stdout:  # buffered-file
+ 11     # file descriptor or (addr stream byte)
+ 12     1/imm32  # standard output
+ 13 $Stdout->buffer:
+ 14     # inlined fields for a stream
+ 15     #   current write index
+ 16     0/imm32
+ 17     #   current read index
+ 18     0/imm32
+ 19     #   size
+ 20     8/imm32
+ 21     #   data
+ 22     00 00 00 00 00 00 00 00  # 8 bytes
+ 23 
+ 24 # TODO: 8 bytes is too small. We'll need to grow the buffer for efficiency. But
+ 25 # I don't want to type in 1024 bytes here.
+ 26 
+ 27 == code
+ 28 #   instruction                     effective address                                                   register    displacement    immediate
+ 29 # . op          subop               mod             rm32          base        index         scale       r32
+ 30 # . 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
+ 31 
+ 32 # Write lower byte of 'n' to 'f'.
+ 33 write-byte-buffered:  # f: (addr buffered-file), n: int
+ 34     # . prologue
+ 35     55/push-ebp
+ 36     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 37     # . save registers
+ 38     51/push-ecx
+ 39     57/push-edi
+ 40     # edi = f
+ 41     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+ 42     # ecx = f->write
+ 43     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(edi+4) to ecx
+ 44     # if (f->write >= f->size) flush and clear f's stream
+ 45     3b/compare                      1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   0xc/disp8       .                 # compare ecx with *(edi+12)
+ 46     7c/jump-if-<  $write-byte-buffered:to-stream/disp8
+ 47     # . flush(f)
+ 48     # . . push args
+ 49     57/push-edi
+ 50     # . . call
+ 51     e8/call  flush/disp32
+ 52     # . . discard args
+ 53     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 54     # . clear-stream(stream = f+4)
+ 55     # . . push args
+ 56     8d/copy-address                 1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy edi+4 to eax
+ 57     50/push-eax
+ 58     # . . call
+ 59     e8/call  clear-stream/disp32
+ 60     # . . discard args
+ 61     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 62     # . f->write must now be 0; update its cache at ecx
+ 63     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
+ 64 $write-byte-buffered:to-stream:
+ 65     # write to stream
+ 66     # f->data[f->write] = LSB(n)
+ 67     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 68     8a/copy-byte                    1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ebp+12) to AL
+ 69     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           0/r32/AL    0x10/disp8      .                 # copy AL to *(edi+ecx+16)
+ 70     # ++f->write
+ 71     ff          0/subop/increment   1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         .                 # increment *(edi+4)
+ 72 $write-byte-buffered:end:
+ 73     # . restore registers
+ 74     5f/pop-to-edi
+ 75     59/pop-to-ecx
+ 76     # . epilogue
+ 77     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 78     5d/pop-to-ebp
+ 79     c3/return
+ 80 
+ 81 flush:  # f: (addr buffered-file)
+ 82     # . prologue
+ 83     55/push-ebp
+ 84     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 85     # . save registers
+ 86     50/push-eax
+ 87     51/push-ecx
+ 88     # eax = f
+ 89     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+ 90     # write-stream(f->fd, data = f+4)
+ 91       # . . push args
+ 92     8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy eax+4 to ecx
+ 93     51/push-ecx
+ 94     ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
+ 95       # . . call
+ 96     e8/call  write-stream/disp32
+ 97       # . . discard args
+ 98     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 99 $flush:end:
+100     # . restore registers
+101     59/pop-to-ecx
+102     58/pop-to-eax
+103     # . epilogue
+104     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+105     5d/pop-to-ebp
+106     c3/return
+107 
+108 test-write-byte-buffered-single:
+109     # - check that write-byte-buffered writes to first byte of 'file'
+110     # setup
+111     # . clear-stream(_test-stream)
+112     # . . push args
+113     68/push  _test-stream/imm32
+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     # . clear-stream($_test-buffered-file->buffer)
+119     # . . push args
+120     68/push  $_test-buffered-file->buffer/imm32
+121     # . . call
+122     e8/call  clear-stream/disp32
+123     # . . discard args
+124     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+125     # write-byte-buffered(_test-buffered-file, 'A')
+126     # . . push args
+127     68/push  0x41/imm32
+128     68/push  _test-buffered-file/imm32
+129     # . . call
+130     e8/call  write-byte-buffered/disp32
+131     # . . discard args
+132     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+133     # flush(_test-buffered-file)
+134     # . . push args
+135     68/push  _test-buffered-file/imm32
+136     # . . call
+137     e8/call  flush/disp32
+138     # . . discard args
+139     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+140     # check-stream-equal(_test-stream, "A", msg)
+141     # . . push args
+142     68/push  "F - test-write-byte-buffered-single"/imm32
+143     68/push  "A"/imm32
+144     68/push  _test-stream/imm32
+145     # . . call
+146     e8/call  check-stream-equal/disp32
+147     # . . discard args
+148     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+149     # . end
+150     c3/return
+151 
+152 test-write-byte-buffered-multiple-flushes:
+153     # - check that write-byte-buffered correctly flushes buffered data
+154     # setup
+155     # . clear-stream(_test-stream)
+156     # . . push args
+157     68/push  _test-stream/imm32
+158     # . . call
+159     e8/call  clear-stream/disp32
+160     # . . discard args
+161     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+162     # . clear-stream($_test-buffered-file->buffer)
+163     # . . push args
+164     68/push  $_test-buffered-file->buffer/imm32
+165     # . . call
+166     e8/call  clear-stream/disp32
+167     # . . discard args
+168     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+169     # fill up the buffer for _test-buffered-file
+170     # . write($_test-buffered-file->buffer, "abcdef")
+171     # . . push args
+172     68/push  "abcdef"/imm32
+173     68/push  $_test-buffered-file->buffer/imm32
+174     # . . call
+175     e8/call  write/disp32
+176     # . . discard args
+177     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+178     # write-byte-buffered(_test-buffered-file, 'g')
+179     # . . push args
+180     68/push  0x67/imm32
+181     68/push  _test-buffered-file/imm32
+182     # . . call
+183     e8/call  write-byte-buffered/disp32
+184     # . . discard args
+185     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+186     # flush(_test-buffered-file)
+187     # . . push args
+188     68/push  _test-buffered-file/imm32
+189     # . . call
+190     e8/call  flush/disp32
+191     # . . discard args
+192     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+193     # check-stream-equal(_test-stream, "abcdefg", msg)
+194     # . . push args
+195     68/push  "F - test-write-byte-buffered-multiple-flushes"/imm32
+196     68/push  "abcdefg"/imm32
+197     68/push  _test-stream/imm32
+198     # . . call
+199     e8/call  check-stream-equal/disp32
+200     # . . discard args
+201     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+202     # . end
+203     c3/return
+204 
+205 # - variant without buffering
+206 
+207 # Write lower byte of 'n' to 'f'.
+208 append-byte:  # f: (addr stream byte), n: int
+209     # . prologue
+210     55/push-ebp
+211     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+212     # . save registers
+213     51/push-ecx
+214     57/push-edi
+215     # edi = f
+216     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+217     # ecx = f->write
+218     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
+219     # if (f->write >= f->size) abort
+220     3b/compare                      1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   8/disp8         .                 # compare ecx with *(edi+8)
+221     7d/jump-if->=  $append-byte:abort/disp8
+222 $append-byte:to-stream:
+223     # write to stream
+224     # f->data[f->write] = LSB(n)
+225     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+226     8a/copy-byte                    1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ebp+12) to AL
+227     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           0/r32/AL    0xc/disp8       .                 # copy AL to *(edi+ecx+12)
+228     # ++f->write
+229     ff          0/subop/increment   0/mod/indirect  7/rm32/edi    .           .             .           .           .               .                 # increment *edi
+230 $append-byte:end:
+231     # . restore registers
+232     5f/pop-to-edi
+233     59/pop-to-ecx
+234     # . epilogue
+235     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+236     5d/pop-to-ebp
+237     c3/return
+238 
+239 $append-byte:abort:
+240     # . _write(2/stderr, error)
+241     # . . push args
+242     68/push  "append-byte: out of space\n"/imm32
+243     68/push  2/imm32/stderr
+244     # . . call
+245     e8/call  _write/disp32
+246     # . . discard args
+247     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+248     # . syscall(exit, 1)
+249     bb/copy-to-ebx  1/imm32
+250     e8/call  syscall_exit/disp32
+251     # never gets here
+252 
+253 test-append-byte-single:
+254     # - check that append-byte writes to first byte of 'file'
+255     # setup
+256     # . clear-stream(_test-stream)
+257     # . . push args
+258     68/push  _test-stream/imm32
+259     # . . call
+260     e8/call  clear-stream/disp32
+261     # . . discard args
+262     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+263     # append-byte(_test-stream, 'A')
+264     # . . push args
+265     68/push  0x41/imm32
+266     68/push  _test-stream/imm32
+267     # . . call
+268     e8/call  append-byte/disp32
+269     # . . discard args
+270     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+271     # check-stream-equal(_test-stream, "A", msg)
+272     # . . push args
+273     68/push  "F - test-append-byte-single"/imm32
+274     68/push  "A"/imm32
+275     68/push  _test-stream/imm32
+276     # . . call
+277     e8/call  check-stream-equal/disp32
+278     # . . discard args
+279     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+280     # . end
+281     c3/return
+282 
+283 == data
+284 
+285 _test-output-stream:  # (stream byte)
+286     # current write index
+287     0/imm32
+288     # current read index
+289     0/imm32
+290     # size
+291     0x400/imm32  # 1024 bytes
+292     # data (64 lines x 16 bytes/line)
+293     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+294     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+295     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+296     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+297     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+298     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+299     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+300     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+301     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+302     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+303     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+304     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+305     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+306     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+307     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+308     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+309     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+310     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+311     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+312     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+313     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+314     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+315     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+316     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+317     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+318     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+319     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+320     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+321     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+322     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+323     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+324     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+325     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+326     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+327     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+328     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+329     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+330     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+331     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+332     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+333     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+334     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+335     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+336     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+337     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+338     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+339     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+340     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+341     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+342     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+343     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+344     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+345     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+346     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+347     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+348     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+349     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+350     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+351     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+352     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+353     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+354     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+355     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+356     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+357 
+358 # a test buffered file for _test-output-stream
+359 _test-output-buffered-file:  # buffered-file
+360     # file descriptor or (addr stream byte)
+361     _test-output-stream/imm32
+362 $_test-output-buffered-file->buffer:
+363     # current write index
+364     0/imm32
+365     # current read index
+366     0/imm32
+367     # size
+368     6/imm32
+369     # data
+370     00 00 00 00 00 00  # 6 bytes
+371 
+372 _test-error-stream:  # (stream byte)
+373     # current write index
+374     0/imm32
+375     # current read index
+376     0/imm32
+377     # line
+378     0x80/imm32  # 128 bytes
+379     # data (8 lines x 16 bytes/line)
+380     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+381     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+382     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+383     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+384     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+385     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+386     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+387     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+388 
+389 # a test buffered file for _test-error-stream
+390 _test-error-buffered-file:  # buffered-file
+391     # file descriptor or (addr stream byte)
+392     _test-error-stream/imm32
+393 $_test-error-buffered-file->buffer:
+394     # current write index
+395     0/imm32
+396     # current read index
+397     0/imm32
+398     # size
+399     6/imm32
+400     # data
+401     00 00 00 00 00 00  # 6 bytes
+402 
+403 # . . vim:nowrap:textwidth=0
+
+ + + -- cgit 1.4.1-2-gfad0