https://github.com/akkartik/mu/blob/main/baremetal/309stream.subx
  1 # Some unsafe methods not intended to be used directly in SubX, only through
  2 # Mu after proper type-checking.
  3 
  4 == code
  5 
  6 stream-empty?:  # s: (addr stream _) -> result/eax: boolean
  7     # . prologue
  8     55/push-ebp
  9     89/<- %ebp 4/r32/esp
 10     # . save registers
 11     51/push-ecx
 12     56/push-esi
 13     # result = false
 14     b8/copy-to-eax 0/imm32/false
 15     # esi = s
 16     8b/-> *(ebp+8) 6/r32/esi
 17     # return s->read >= s->write
 18     8b/-> *esi 1/r32/ecx
 19     39/compare-with *(esi+4) 1/r32/ecx
 20     0f 9d/set-if->= %al
 21 $stream-empty?:end:
 22     # . restore registers
 23     5e/pop-to-esi
 24     59/pop-to-ecx
 25     # . epilogue
 26     89/<- %esp 5/r32/ebp
 27     5d/pop-to-ebp
 28     c3/return
 29 
 30 stream-full?:  # s: (addr stream _) -> result/eax: boolean
 31     # . prologue
 32     55/push-ebp
 33     89/<- %ebp 4/r32/esp
 34     # . save registers
 35     51/push-ecx
 36     56/push-esi
 37     # result = false
 38     b8/copy-to-eax 0/imm32/false
 39     # esi = s
 40     8b/-> *(ebp+8) 6/r32/esi
 41     # return s->write >= s->size
 42     8b/-> *(esi+8) 1/r32/ecx
 43     39/compare-with *esi 1/r32/ecx
 44     0f 9d/set-if->= %al
 45 $stream-full?:end:
 46     # . restore registers
 47     5e/pop-to-esi
 48     59/pop-to-ecx
 49     # . epilogue
 50     89/<- %esp 5/r32/ebp
 51     5d/pop-to-ebp
 52     c3/return
 53 
 54 write-to-stream:  # s: (addr stream _), in: (addr byte), n: int
 55     # . prologue
 56     55/push-ebp
 57     89/<- %ebp 4/r32/esp
 58     # . save registers
 59     50/push-eax
 60     51/push-ecx
 61     52/push-edx
 62     53/push-ebx
 63     57/push-edi
 64     # edi = s
 65     8b/-> *(ebp+8) 7/r32/edi
 66     # var swrite/edx: int = s->write
 67     8b/-> *edi 2/r32/edx
 68     # if (swrite + n > s->size) return
 69     8b/-> *(ebp+0x10) 1/r32/ecx
 70     01/add-to %ecx 2/r32/edx
 71     3b/compare 1/r32/ecx *(edi+8)
 72     0f 8f/jump-if-> $write-to-stream:end/disp32  # TODO: abort
 73     # var out/edx: (addr byte) = s->data + s->write
 74     8d/copy-address *(edi+edx+0xc) 2/r32/edx
 75     # var outend/ebx: (addr byte) = out + n
 76     8b/-> *(ebp+0x10) 3/r32/ebx
 77     8d/copy-address *(edx+ebx) 3/r32/ebx
 78     # eax = in
 79     8b/-> *(ebp+0xc) 0/r32/eax
 80     # var inend/ecx: (addr byte) = in + n
 81     8b/-> *(ebp+0x10) 1/r32/ecx
 82     8d/copy-address *(eax+ecx) 1/r32/ecx
 83     #
 84     (_append-4  %edx %ebx  %eax %ecx)  # => eax
 85     # s->write += n
 86     8b/-> *(ebp+0x10) 1/r32/ecx
 87     01/add-to *edi 1/r32/ecx
 88 $write-to-stream:end:
 89     # . restore registers
 90     5f/pop-to-edi
 91     5b/pop-to-ebx
 92     5a/pop-to-edx
 93     59/pop-to-ecx
 94     58/pop-to-eax
 95     # . epilogue
 96     89/<- %esp 5/r32/ebp
 97     5d/pop-to-ebp
 98     c3/return
 99 
100 read-from-stream:  # s: (addr stream _), out: (addr byte), n: int
101     # . prologue
102     55/push-ebp
103     89/<- %ebp 4/r32/esp
104     # . save registers
105     50/push-eax
106     51/push-ecx
107     52/push-edx
108     53/push-ebx
109     56/push-esi
110     # esi = s
111     8b/-> *(ebp+8) 6/r32/esi
112     # var sread/edx: int = s->read
113     8b/-> *(esi+4) 2/r32/edx
114     # if (sread + n > s->write) return
115     8b/-> *(ebp+0x10) 1/r32/ecx
116     01/add-to %ecx 2/r32/edx
117     3b/compare 1/r32/ecx *esi
118     0f 8f/jump-if-> $read-from-stream:end/disp32  # TODO: abort
119     # var in/edx: (addr byte) = s->data + s->read
120     8d/copy-address *(esi+edx+0xc) 2/r32/edx
121     # var inend/ebx: (addr byte) = in + n
122     8b/-> *(ebp+0x10) 3/r32/ebx
123     8d/copy-address *(edx+ebx) 3/r32/ebx
124     # eax = out
125     8b/-> *(ebp+0xc) 0/r32/eax
126     # var outend/ecx: (addr byte) = out + n
127     8b/-> *(ebp+0x10) 1/r32/ecx
128     8d/copy-address *(eax+ecx) 1/r32/ecx
129     #
130     (_append-4  %eax %ecx  %edx %ebx)  # => eax
131     # s->read += n
132     8b/-> *(ebp+0x10) 1/r32/ecx
133     01/add-to *(esi+4) 1/r32/ecx
134 $read-from-stream:end:
135     # . restore registers
136     5e/pop-to-esi
137     5b/pop-to-ebx
138     5a/pop-to-edx
139     59/pop-to-ecx
140     58/pop-to-eax
141     # . epilogue
142     89/<- %esp 5/r32/ebp
143     5d/pop-to-ebp
144     c3/return
145 
146 stream-first:  # s: (addr stream byte) -> result/eax: byte
147     # . prologue
148     55/push-ebp
149     89/<- %ebp 4/r32/esp
150     # . save registers
151     51/push-ecx
152     56/push-esi
153     # result = false
154     b8/copy-to-eax 0/imm32
155     # esi = s
156     8b/-> *(ebp+8) 6/r32/esi
157     # var idx/ecx: int = s->read
158     8b/-> *(esi+4) 1/r32/ecx
159     # if idx >= s->write return 0
160     3b/compare-with 1/r32/ecx *esi
161     7d/jump-if->= $stream-first:end/disp8
162     # result = s->data[idx]
163     8a/byte-> *(esi+ecx+0xc) 0/r32/AL
164 $stream-first:end:
165     # . restore registers
166     5e/pop-to-esi
167     59/pop-to-ecx
168     # . epilogue
169     89/<- %esp 5/r32/ebp
170     5d/pop-to-ebp
171     c3/return
172 
173 stream-final:  # s: (addr stream byte) -> result/eax: byte
174     # . prologue
175     55/push-ebp
176     89/<- %ebp 4/r32/esp
177     # . save registers
178     51/push-ecx
179     56/push-esi
180     # result = false
181     b8/copy-to-eax 0/imm32
182     # esi = s
183     8b/-> *(ebp+8) 6/r32/esi
184     # var max/ecx: int = s->write
185     8b/-> *esi 1/r32/ecx
186     # if s->read >= max return 0
187     39/compare-with *(esi+4) 1/r32/ecx
188     7d/jump-if->= $stream-final:end/disp8
189     # var idx/ecx: int = max - 1
190     49/decrement-ecx
191     # result = s->data[idx]
192     8a/byte-> *(esi+ecx+0xc) 0/r32/AL
193 $stream-final:end:
194     # . restore registers
195     5e/pop-to-esi
196     59/pop-to-ecx
197     # . epilogue
198     89/<- %esp 5/r32/ebp
199     5d/pop-to-ebp
200     c3/return