https://github.com/akkartik/mu/blob/main/112read-byte.subx
  1 # Read a single byte from a stream.
  2 #
  3 # We need to do this in machine code because streams need to be opaque types,
  4 # and we don't yet support opaque types in Mu.
  5 
  6 == code
  7 #   instruction                     effective address                                                   register    displacement    immediate
  8 # . op          subop               mod             rm32          base        index         scale       r32
  9 # . 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
 10 
 11 # Return next byte value in eax, with top 3 bytes cleared.
 12 # Abort on reaching end of stream.
 13 read-byte:  # s: (addr stream byte) -> result/eax: byte
 14     # . prologue
 15     55/push-ebp
 16     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 17     # . save registers
 18     51/push-ecx
 19     56/push-esi
 20     # esi = s
 21     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
 22     # ecx = s->read
 23     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
 24     # if (f->read >= f->write) abort
 25     3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare ecx with *esi
 26     0f 8d/jump-if->=  $read-byte:abort/disp32
 27     # result = f->data[f->read]
 28     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
 29     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(esi+ecx+12) to AL
 30     # ++f->read
 31     ff          0/subop/increment   1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # increment *(esi+4)
 32 $read-byte:end:
 33     # . restore registers
 34     5e/pop-to-esi
 35     59/pop-to-ecx
 36     # . epilogue
 37     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 38     5d/pop-to-ebp
 39     c3/return
 40 
 41 $read-byte:abort:
 42     (abort "read-byte: empty stream")
 43     # never gets here
 44 
 45 # Return next byte value in eax, with top 3 bytes cleared.
 46 # Abort on reaching end of stream.
 47 peek-byte:  # s: (addr stream byte) -> result/eax: byte
 48     # . prologue
 49     55/push-ebp
 50     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 51     # . save registers
 52     51/push-ecx
 53     56/push-esi
 54     # esi = s
 55     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
 56     # ecx = s->read
 57     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
 58     # if (f->read >= f->write) abort
 59     3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare ecx with *esi
 60     0f 8d/jump-if->=  $peek-byte:abort/disp32
 61     # result = f->data[f->read]
 62     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
 63     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(esi+ecx+12) to AL
 64 $peek-byte:end:
 65     # . restore registers
 66     5e/pop-to-esi
 67     59/pop-to-ecx
 68     # . epilogue
 69     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 70     5d/pop-to-ebp
 71     c3/return
 72 
 73 $peek-byte:abort:
 74     (abort "peek-byte: empty stream")
 75     # never gets here
 76 
 77 == data
 78 
 79 _test-input-stream:  # (stream byte)
 80     # current write index
 81     0/imm32
 82 $_test-input-stream->read:
 83     # current read index
 84     0/imm32
 85     # size
 86     0x400/imm32  # 1024 bytes
 87     # data (64 lines x 16 bytes/line)
 88     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 89     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 90     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 91     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 92     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 93     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 94     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 95     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 96     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 97     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 98     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 99     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
100     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
101     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
102     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
103     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
104     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
105     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
106     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
107     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
108     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
109     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
110     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
111     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
112     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
113     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
114     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
115     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
116     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
117     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
118     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
119     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
120     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
121     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
122     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
123     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
124     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
125     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
126     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
127     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
128     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
129     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
130     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
132     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
133     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
134     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
135     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
136     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
137     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
138     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
139     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
140     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
141     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
142     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
143     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
144     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
145     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
146     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
147     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
148     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
149     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
150     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
151     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
152 
153 # . . vim:nowrap:textwidth=0