https://github.com/akkartik/mu/blob/master/subx/067print-int.subx
  1 # Print the (hex) textual representation of numbers.
  2 
  3 == code
  4 #   instruction                     effective address                                                   register    displacement    immediate
  5 # . op          subop               mod             rm32          base        index         scale       r32
  6 # . 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
  7 
  8 #? Entry:  # run a single test, while debugging
  9 #?     e8/call test-print-int32/disp32
 10 #?     # syscall(exit, Num-test-failures)
 11 #?     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 12 #?     b8/copy-to-EAX  1/imm32/exit
 13 #?     cd/syscall  0x80/imm8
 14 
 15 append-byte-hex:  # f : (address stream), n : int -> <void>
 16     # . prolog
 17     55/push-EBP
 18     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 19     # . save registers
 20     50/push-EAX
 21     # AL = convert upper nibble to hex
 22     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy *(EBP+12) to EAX
 23     c1/shift    5/subop/logic-right 3/mod/direct    0/rm32/EAX    .           .             .           .           .               4/imm8            # shift EAX right by 4 bits, while padding zeroes
 24     25/and-EAX  0xf/imm32
 25     # . AL = to-hex-char(AL)
 26     e8/call  to-hex-char/disp32
 27     # append-byte(f, AL)
 28     # . . push args
 29     50/push-EAX
 30     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
 31     # . . call
 32     e8/call  append-byte/disp32
 33     # . . discard args
 34     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 35     # AL = convert lower nibble to hex
 36     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy *(EBP+12) to EAX
 37     25/and-EAX  0xf/imm32
 38     # . AL = to-hex-char(AL)
 39     e8/call  to-hex-char/disp32
 40     # append-byte(f, AL)
 41     # . . push args
 42     50/push-EAX
 43     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
 44     # . . call
 45     e8/call  append-byte/disp32
 46     # . . discard args
 47     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 48 $append-byte-hex:end:
 49     # . restore registers
 50     58/pop-to-EAX
 51     # . epilog
 52     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 53     5d/pop-to-EBP
 54     c3/return
 55 
 56 test-append-byte-hex:
 57     # - check that append-byte-hex adds the hex textual representation
 58     # setup
 59     # . clear-stream(_test-stream)
 60     # . . push args
 61     68/push  _test-stream/imm32
 62     # . . call
 63     e8/call  clear-stream/disp32
 64     # . . discard args
 65     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 66     # append-byte-hex(_test-stream, 0xa)  # exercises digit, non-digit as well as leading zero
 67     # . . push args
 68     68/push  0xa/imm32
 69     68/push  _test-stream/imm32
 70     # . . call
 71     e8/call  append-byte-hex/disp32
 72     # . . discard args
 73     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 74     # check-stream-equal(_test-stream, "0a", msg)
 75     # . . push args
 76     68/push  "F - test-append-byte-hex"/imm32
 77     68/push  "0a"/imm32
 78     68/push  _test-stream/imm32
 79     # . . call
 80     e8/call  check-stream-equal/disp32
 81     # . . discard args
 82     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 83     # . end
 84     c3/return
 85 
 86 # print the hex representation for the lowest byte of a number
 87 print-byte-buffered:  # f : (address buffered-file), n : int -> <void>
 88     # . prolog
 89     55/push-EBP
 90     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 91     # . save registers
 92     50/push-EAX
 93     # AL = convert upper nibble to hex
 94     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy *(EBP+12) to EAX
 95     c1/shift    5/subop/logic-right 3/mod/direct    0/rm32/EAX    .           .             .           .           .               4/imm8            # shift EAX right by 4 bits, while padding zeroes
 96     25/and-EAX  0xf/imm32
 97     # . AL = to-hex-char(AL)
 98     e8/call  to-hex-char/disp32
 99     # write-byte-buffered(f, AL)
100     # . . push args
101     50/push-EAX
102     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
103     # . . call
104     e8/call  write-byte-buffered/disp32
105     # . . discard args
106     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
107     # AL = convert lower nibble to hex
108     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy *(EBP+12) to EAX
109     25/and-EAX  0xf/imm32
110     # . AL = to-hex-char(AL)
111     e8/call  to-hex-char/disp32
112     # write-byte-buffered(f, AL)
113     # . . push args
114     50/push-EAX
115     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
116     # . . call
117     e8/call  write-byte-buffered/disp32
118     # . . discard args
119     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
120 $print-byte-buffered:end:
121     # . restore registers
122     58/pop-to-EAX
123     # . epilog
124     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
125     5d/pop-to-EBP
126     c3/return
127 
128 test-print-byte-buffered:
129     # - check that print-byte-buffered prints the hex textual representation
130     # setup
131     # . clear-stream(_test-stream)
132     # . . push args
133     68/push  _test-stream/imm32
134     # . . call
135     e8/call  clear-stream/disp32
136     # . . discard args
137     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
138     # . clear-stream(_test-buffered-file+4)
139     # . . push args
140     b8/copy-to-EAX  _test-buffered-file/imm32
141     05/add-to-EAX  4/imm32
142     50/push-EAX
143     # . . call
144     e8/call  clear-stream/disp32
145     # . . discard args
146     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
147     # print-byte-buffered(_test-buffered-file, 0xa)  # exercises digit, non-digit as well as leading zero
148     # . . push args
149     68/push  0xa/imm32
150     68/push  _test-buffered-file/imm32
151     # . . call
152     e8/call  print-byte-buffered/disp32
153     # . . discard args
154     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
155     # flush(_test-buffered-file)
156     # . . push args
157     68/push  _test-buffered-file/imm32
158     # . . call
159     e8/call  flush/disp32
160     # . . discard args
161     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
162     # check-stream-equal(_test-stream, "0a", msg)
163     # . . push args
164     68/push  "F - test-print-byte-buffered"/imm32
165     68/push  "0a"/imm32
166     68/push  _test-stream/imm32
167     # . . call
168     e8/call  check-stream-equal/disp32
169     # . . discard args
170     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
171     # . end
172     c3/return
173 
174 print-int32:  # f : (address stream), n : int -> <void>
175     # pseudocode:
176     #  write(f, "0x")
177     #  ECX = 28
178     #  while true
179     #    if (ECX < 0) break
180     #    EAX = n >> ECX
181     #    EAX = EAX & 0xf
182     #    append-byte(f, AL)
183     #    ECX -= 4
184     #
185     # . prolog
186     55/push-EBP
187     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
188     # . save registers
189     50/push-EAX
190     51/push-ECX
191     # ECX = 28
192     b9/copy-to-ECX  0x1c/imm32
193 $print-int32:print-hex-prefix:
194     # write(f, "0x")
195     # . . push args
196     68/push  "0x"/imm32
197     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
198     # . . call
199     e8/call  write/disp32
200     # . . discard args
201     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
202 $print-int32:loop:
203     # if (ECX < 0) break
204     81          7/subop/compare     3/mod/direct    1/rm32/ECX    .           .             .           .           .               0/imm32           # compare ECX
205     7c/jump-if-lesser  $print-int32:end/disp8
206     # EAX = n >> ECX
207     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy *(EBP+12) to EAX
208     d3/>>ECX    5/subop/pad-zeroes  3/mod/direct    0/rm32/EAX    .           .             .           .           .               .                 # shift EAX right by ECX bits, padding zeroes
209     # EAX = to-hex-char(AL)
210     25/and-EAX  0xf/imm32
211     e8/call  to-hex-char/disp32
212     # append-byte(f, AL)
213     # . . push args
214     50/push-EAX
215     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
216     # . . call
217     e8/call  append-byte/disp32
218     # . . discard args
219     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
220     # ECX -= 4
221     81          5/subop/subtract    3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # subtract from ECX
222     eb/jump  $print-int32:loop/disp8
223 $print-int32:end:
224     # . restore registers
225     59/pop-to-ECX
226     58/pop-to-EAX
227     # . epilog
228     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
229     5d/pop-to-EBP
230     c3/return
231 
232 test-print-int32:
233     # - check that print-int32 prints the hex textual representation
234     # setup
235     # . clear-stream(_test-stream)
236     # . . push args
237     68/push  _test-stream/imm32
238     # . . call
239     e8/call  clear-stream/disp32
240     # . . discard args
241     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
242     # print-int32(_test-stream, 0x8899aa)
243     # . . push args
244     68/push  0x8899aa/imm32
245     68/push  _test-stream/imm32
246     # . . call
247     e8/call  print-int32/disp32
248     # . . discard args
249     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
250     # check-stream-equal(_test-stream, "0x008899aa", msg)
251     # . . push args
252     68/push  "F - test-print-int32"/imm32
253     68/push  "0x008899aa"/imm32
254     68/push  _test-stream/imm32
255     # . . call
256     e8/call  check-stream-equal/disp32
257     # . . discard args
258     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
259     # . end
260     c3/return
261 
262 print-int32-buffered:  # f : (address buffered-file), n : int -> <void>
263     # pseudocode:
264     #  write-buffered(f, "0x")
265     #  ECX = 28
266     #  while true
267     #    if (ECX < 0) break
268     #    EAX = n >> ECX
269     #    EAX = EAX & 0xf
270     #    write-byte-buffered(f, AL)
271     #    ECX -= 4
272     #
273     # . prolog
274     55/push-EBP
275     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
276     # . save registers
277     50/push-EAX
278     51/push-ECX
279     # ECX = 28
280     b9/copy-to-ECX  0x1c/imm32
281 $print-int32-buffered:print-hex-prefix:
282     # write-buffered(f, "0x")
283     # . . push args
284     68/push  "0x"/imm32
285     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
286     # . . call
287     e8/call  write-buffered/disp32
288     # . . discard args
289     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
290 $print-int32-buffered:loop:
291     # if (ECX < 0) break
292     81          7/subop/compare     3/mod/direct    1/rm32/ECX    .           .             .           .           .               0/imm32           # compare ECX
293     7c/jump-if-lesser  $print-int32-buffered:end/disp8
294     # EAX = n >> ECX
295     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy *(EBP+12) to EAX
296     d3/>>ECX    5/subop/pad-zeroes  3/mod/direct    0/rm32/EAX    .           .             .           .           .               .                 # shift EAX right by ECX bits, padding zeroes
297     # EAX = to-hex-char(AL)
298     25/and-EAX  0xf/imm32
299     e8/call  to-hex-char/disp32
300     # write-byte-buffered(f, AL)
301     # . . push args
302     50/push-EAX
303     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
304     # . . call
305     e8/call  write-byte-buffered/disp32
306     # . . discard args
307     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
308     # ECX -= 4
309     81          5/subop/subtract    3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # subtract from ECX
310     eb/jump  $print-int32-buffered:loop/disp8
311 $print-int32-buffered:end:
312     # . restore registers
313     59/pop-to-ECX
314     58/pop-to-EAX
315     # . epilog
316     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
317     5d/pop-to-EBP
318     c3/return
319 
320 test-print-int32-buffered:
321     # - check that print-int32-buffered prints the hex textual representation
322     # setup
323     # . clear-stream(_test-stream)
324     # . . push args
325     68/push  _test-stream/imm32
326     # . . call
327     e8/call  clear-stream/disp32
328     # . . discard args
329     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
330     # . clear-stream(_test-buffered-file+4)
331     # . . push args
332     b8/copy-to-EAX  _test-buffered-file/imm32
333     05/add-to-EAX  4/imm32
334     50/push-EAX
335     # . . call
336     e8/call  clear-stream/disp32
337     # . . discard args
338     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
339     # print-int32-buffered(_test-buffered-file, 0x8899aa)
340     # . . push args
341     68/push  0x8899aa/imm32
342     68/push  _test-buffered-file/imm32
343     # . . call
344     e8/call  print-int32-buffered/disp32
345     # . . discard args
346     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
347     # flush(_test-buffered-file)
348     # . . push args
349     68/push  _test-buffered-file/imm32
350     # . . call
351     e8/call  flush/disp32
352     # . . discard args
353     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
354 +-- 18 lines: #?     # dump line -----------------------------------------------------------------------------------------------------------------------------
372     # check-stream-equal(_test-stream, "0x008899aa", msg)
373     # . . push args
374     68/push  "F - test-print-int32-buffered"/imm32
375     68/push  "0x008899aa"/imm32
376     68/push  _test-stream/imm32
377     # . . call
378     e8/call  check-stream-equal/disp32
379     # . . discard args
380     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
381     # . end
382     c3/return
383 
384 # . . vim:nowrap:textwidth=0