diff options
Diffstat (limited to 'baremetal')
73 files changed, 0 insertions, 17933 deletions
diff --git a/baremetal/101screen.subx b/baremetal/101screen.subx deleted file mode 100644 index 46cee777..00000000 --- a/baremetal/101screen.subx +++ /dev/null @@ -1,42 +0,0 @@ -# Primitives for screen control. -# -# We need to do this in machine code because Mu doesn't have global variables -# yet (for the start of video memory). - -== code - -pixel-on-real-screen: # x: int, y: int, color: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - # bounds checks - 8b/-> *(ebp+8) 0/r32/eax - 3d/compare-eax-and 0/imm32 - 7c/jump-if-< $pixel-on-real-screen:end/disp8 - 3d/compare-eax-and 0x400/imm32/screen-width=1024 - 7d/jump-if->= $pixel-on-real-screen:end/disp8 - 8b/-> *(ebp+0xc) 0/r32/eax - 3d/compare-eax-and 0/imm32 - 7c/jump-if-< $pixel-on-real-screen:end/disp8 - 3d/compare-eax-and 0x300/imm32/screen-height=768 - 7d/jump-if->= $pixel-on-real-screen:end/disp8 - # eax = y*1024 + x - 8b/-> *(ebp+0xc) 0/r32/eax - c1/shift 4/subop/left %eax 0xa/imm8 - 03/add-> *(ebp+8) 0/r32/eax - # eax += location of frame buffer - 03/add-> *0x8128 0/r32/eax # unsafe - # *eax = color - 8b/-> *(ebp+0x10) 1/r32/ecx - 88/byte<- *eax 1/r32/CL -$pixel-on-real-screen:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/102keyboard.subx b/baremetal/102keyboard.subx deleted file mode 100644 index df74c8e7..00000000 --- a/baremetal/102keyboard.subx +++ /dev/null @@ -1,48 +0,0 @@ -# check keyboard for a key -# return 0 on no keypress or unrecognized key -# -# We need to do this in machine code because Mu doesn't have global variables -# yet (for the keyboard buffer). - -== code - -read-key: # kbd: (addr keyboard) -> result/eax: byte - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - # result = 0 - b8/copy-to-eax 0/imm32 - # ecx = keyboard - 8b/-> *(ebp+8) 1/r32/ecx - 81 7/subop/compare %ecx 0/imm32 - { - 75/jump-if-!= break/disp8 - # var read/ecx: byte = keyboard buffer's read index - 8b/-> *0x802c 1/r32/CL # keyboard-buffer-read - # var next-key/eax: byte = *(keyboard buffer + ecx) - 8a/byte-> *(ecx+0x8030) 0/r32/AL # keyboard-buffer-data - # if (next-key != 0) lock and remove from keyboard buffer - 81 7/subop/compare %eax 0/imm32 - { - 74/jump-if-= break/disp8 - # TODO: add some instructions in this block to SubX if we ever want to - # use bootstrap on baremetal programs - fa/disable-interrupts - c6 0/subop/copy-byte *(ecx+0x8030) 0/imm8 # keyboard-buffer-data - ff 0/subop/increment *0x802c # keyboard-buffer-read - 81 4/subop/and *0x802c 0xf/imm32 # keyboard-buffer-read - fb/enable-interrupts - } - # return - eb $read-key:end/disp8 - } - # TODO: fake keyboard -$read-key:end: - # . restore registers - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/103grapheme.subx b/baremetal/103grapheme.subx deleted file mode 100644 index d26a0b58..00000000 --- a/baremetal/103grapheme.subx +++ /dev/null @@ -1,173 +0,0 @@ -# Use the built-in font to draw a grapheme to real screen. -# -# We need to do this in machine code because Mu doesn't have global variables -# yet (for the start of video memory). -# -# There are uncomfortable assumptions baked in here about english/latin -# script. We convert the grid of pixels into a fixed-width grid of graphemes, -# which may not work well with other language families. - -== code - -# The Mu computer's screen is 1024px wide and 768px tall. -# The Mu computer's font is 8px wide and 16px tall. -# Therefore 'x' here is in [0, 128), and 'y' is in [0, 48) -# Doesn't update the cursor; where the cursor should go after printing the -# current grapheme is a higher-level concern. -draw-grapheme-on-real-screen: # g: grapheme, x: int, y: int, color: int, background-color: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - # var letter-bitmap/esi = font[g] - 8b/-> *(ebp+8) 6/r32/esi - c1 4/subop/shift-left %esi 4/imm8 - 8d/copy-address *(esi+0x8c00) 6/r32/esi # font-start - # if (letter-bitmap >= 0x9400) return # characters beyond ASCII currently not supported - 81 7/subop/compare %esi 0x9400/imm32 - 7d/jump-if->= $draw-grapheme-on-real-screen:end/disp8 - # var ycurr/edx: int = y*16 - 8b/-> *(ebp+0x10) 2/r32/edx - c1 4/subop/shift-left %edx 4/imm8 - # var ymax/ebx: int = ycurr + 16 - 8b/-> *(ebp+0x10) 3/r32/ebx - c1 4/subop/shift-left %ebx 4/imm8 - 81 0/subop/add %ebx 0x10/imm32 - { - # if (ycurr >= ymax) break - 39/compare %edx 3/r32/ebx - 7d/jump-if->= break/disp8 - # var xcurr/eax: int = x*8 + 7 - 8b/-> *(ebp+0xc) 0/r32/eax # font-width - 1 - c1 4/subop/shift-left %eax 3/imm8 - 81 0/subop/add %eax 7/imm32 - # var xmin/ecx: int = x*8 - 8b/-> *(ebp+0xc) 1/r32/ecx - c1 4/subop/shift-left %ecx 3/imm8 - # var row-bitmap/ebx: int = *letter-bitmap - 53/push-ebx - 8b/-> *esi 3/r32/ebx - { - # if (xcurr < xmin) break - 39/compare %eax 1/r32/ecx - 7c/jump-if-< break/disp8 - # shift LSB from row-bitmap into carry flag (CF) - c1 5/subop/shift-right-logical %ebx 1/imm8 - # if LSB, draw a pixel in the given color - { - 73/jump-if-not-CF break/disp8 - (pixel-on-real-screen %eax %edx *(ebp+0x14)) - eb/jump $draw-grapheme-on-real-screen:continue/disp8 - } - # otherwise use the background color - (pixel-on-real-screen %eax %edx *(ebp+0x18)) -$draw-grapheme-on-real-screen:continue: - # --x - 48/decrement-eax - # - eb/jump loop/disp8 - } - # reclaim row-bitmap - 5b/pop-to-ebx - # ++y - 42/increment-edx - # next bitmap row - 46/increment-esi - # - eb/jump loop/disp8 - } -$draw-grapheme-on-real-screen:end: - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -cursor-position-on-real-screen: # -> _/eax: int, _/ecx: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # TODO: support fake screen; we currently assume 'screen' is always 0 (real) - 8b/-> *Real-screen-cursor-x 0/r32/eax - 8b/-> *Real-screen-cursor-y 1/r32/ecx -$cursor-position-on-real-screen:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -set-cursor-position-on-real-screen: # x: int, y: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - # - 8b/-> *(ebp+8) 0/r32/eax - 89/<- *Real-screen-cursor-x 0/r32/eax - 8b/-> *(ebp+0xc) 0/r32/eax - 89/<- *Real-screen-cursor-y 0/r32/eax -$set-cursor-position-on-real-screen:end: - # . restore registers - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -# Draw cursor at current location. But this is rickety: -# - does not clear previous location cursor was shown at. -# - does not preserve what was at the cursor. Caller is responsible for -# tracking what was on the screen at this position before and passing it -# in again. -# - does not stop showing the cursor at this location when the cursor moves -show-cursor-on-real-screen: # g: grapheme - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - # - (cursor-position-on-real-screen) # => eax, ecx - (draw-grapheme-on-real-screen *(ebp+8) %eax %ecx 0 7) -$show-cursor-on-real-screen:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -== data - -# The cursor is where certain Mu functions (usually of the form -# 'draw*cursor*') print to by default. -# -# We don't bother displaying the cursor when drawing. It only becomes visible -# on show-cursor, which is quite rickety (see above) -# -# It's up to applications to manage cursor display: -# - clean up where it used to be -# - display the cursor before waiting for a key -# - ensure its location appropriately suggests the effect keystrokes will have -# - ensure its contents (and colors) appropriately reflect the state of the -# screen -# -# There's no blinking, etc. We aren't using any hardware-supported text mode -# here. -Real-screen-cursor-x: - 0/imm32 -Real-screen-cursor-y: - 0/imm32 diff --git a/baremetal/104test.subx b/baremetal/104test.subx deleted file mode 100644 index 5b14049e..00000000 --- a/baremetal/104test.subx +++ /dev/null @@ -1,32 +0,0 @@ -# Some helpers needed only because Mu doesn't support globals at the moment. - -== code - -count-test-failure: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - ff 0/subop/increment *Num-test-failures -$count-test-failure:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -num-test-failures: # -> _/eax: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - 8b/-> *Num-test-failures 0/r32/eax -$num-test-failures:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -== data - -Num-test-failures: - 0/imm32 diff --git a/baremetal/105string-equal.subx b/baremetal/105string-equal.subx deleted file mode 100644 index 2289e514..00000000 --- a/baremetal/105string-equal.subx +++ /dev/null @@ -1,256 +0,0 @@ -# Comparing 'regular' size-prefixed strings. - -== 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 - -string-equal?: # s: (addr array byte), benchmark: (addr array byte) -> result/eax: boolean - # pseudocode: - # if (s->size != benchmark->size) return false - # return string-starts-with?(s, benchmark) - # - # . prologue - 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 - 57/push-edi - # esi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # edi = benchmark - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi - # ecx = s->size - 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx -$string-equal?:sizes: - # if (ecx != benchmark->size) return false - 39/compare 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # compare *edi and ecx - b8/copy-to-eax 0/imm32/false - 75/jump-if-!= $string-equal?:end/disp8 -$string-equal?:contents: - # string-starts-with?(s, benchmark) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call string-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -$string-equal?:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -string-starts-with?: # s: (addr array byte), benchmark: (addr array byte) -> result/eax: boolean - # pseudocode: - # if (s->size < benchmark->size) return false - # currs = s->data - # currb = benchmark->data - # maxb = &benchmark->data[benchmark->size] - # while currb < maxb - # c1 = *currs - # c2 = *currb - # if (c1 != c2) return false - # ++currs, ++currb - # return true - # - # registers: - # currs: esi - # maxs: ecx - # currb: edi - # c1: eax - # c2: ebx - # - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 56/push-esi - 57/push-edi - # esi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # edi = benchmark - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi - # var bsize/ecx: int = benchmark->size - 8b/copy 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # copy *edi to ecx -$string-starts-with?:sizes: - # if (s->size < bsize) return false - 39/compare 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # compare *esi with ecx - 7c/jump-if-< $string-starts-with?:false/disp8 - # var currs/esi: (addr byte) = s->data - 81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 4/imm32 # add to esi - # var currb/edi: (addr byte) = benchmark->data - 81 0/subop/add 3/mod/direct 7/rm32/edi . . . . . 4/imm32 # add to edi - # var maxb/ecx: (addr byte) = &benchmark->data[benchmark->size] - 01/add 3/mod/direct 1/rm32/ecx . . . 7/r32/edi . . # add edi to ecx - # var c1/eax: byte = 0 - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - # var c2/edx: byte = 0 - 31/xor 3/mod/direct 2/rm32/edx . . . 2/r32/edx . . # clear edx -$string-starts-with?:loop: - # if (currs >= maxs) return true - 39/compare 3/mod/direct 7/rm32/edi . . . 1/r32/ecx . . # compare edi with ecx - 73/jump-if-addr>= $string-starts-with?:true/disp8 - # c1 = *currs - 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 0/r32/AL . . # copy byte at *esi to AL - # c2 = *currb - 8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 2/r32/DL . . # copy byte at *edi to DL - # if (c1 != c2) return false - 39/compare 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # compare eax and edx - 75/jump-if-!= $string-starts-with?:false/disp8 - # ++currs - 46/increment-esi - # ++currb - 47/increment-edi - eb/jump $string-starts-with?:loop/disp8 -$string-starts-with?:true: - b8/copy-to-eax 1/imm32 - eb/jump $string-starts-with?:end/disp8 -$string-starts-with?:false: - b8/copy-to-eax 0/imm32 -$string-starts-with?:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# - tests - -test-compare-empty-with-empty-string: - # eax = string-equal?("", "") - # . . push args - 68/push ""/imm32 - 68/push ""/imm32 - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-compare-empty-with-empty-string"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-empty-with-non-empty-string: # also checks size-mismatch code path - # eax = string-equal?("", "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push ""/imm32 - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-compare-empty-with-non-empty-string"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-equal-strings: - # eax = string-equal?("Abc", "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push "Abc"/imm32 - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-compare-equal-strings"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-compare-inequal-strings-equal-sizes: - # eax = string-equal?("Abc", "Adc") - # . . push args - 68/push "Adc"/imm32 - 68/push "Abc"/imm32 - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-compare-inequal-strings-equal-sizes"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -# helper for later tests -check-strings-equal: # s: (addr array byte), expected: (addr array byte), msg: (addr array byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - # var eax: boolean = string-equal?(s, expected) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -$check-strings-equal:end: - # . restore registers - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# test the helper -test-check-strings-equal: - # check-strings-equal("Abc", "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push "Abc"/imm32 - # . . call - e8/call check-strings-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/106stream.subx b/baremetal/106stream.subx deleted file mode 100644 index 9949ee7d..00000000 --- a/baremetal/106stream.subx +++ /dev/null @@ -1,77 +0,0 @@ -# streams: data structure for operating on arrays in a stateful manner -# -# A stream looks like this: -# write: int # index at which writes go -# read: int # index that we've read until -# data: (array byte) # prefixed by size as usual -# -# some primitives for operating on streams: -# - clear-stream (clears everything but the data size) -# - rewind-stream (resets read pointer) -# -# We need to do this in machine code because streams need to be opaque types, -# and we don't yet support opaque types in Mu. - -== 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 - -clear-stream: # f: (addr stream byte) - # . prologue - 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 5/rm32/ebp . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - # var count/ecx: int = f->size - 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 8/disp8 . # copy *(eax+8) to ecx - # var max/ecx: (addr byte) = &f->data[f->size] - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 0xc/disp8 . # copy eax+ecx+12 to ecx - # f->write = 0 - c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0/imm32 # copy to *eax - # f->read = 0 - c7 0/subop/copy 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 0/imm32 # copy to *(eax+4) - # - clear all stream data - # - this isn't strictly necessary, and it can slow things down *a lot*, but better safe than sorry. - # var curr/eax: (addr byte) = f->data - 81 0/subop/add 3/mod/direct 0/rm32/eax . . . . . 0xc/imm32 # add to eax -$clear-stream:loop: - # if (curr >= max) break - 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx - 73/jump-if-addr>= $clear-stream:end/disp8 - # *curr = 0 - c6 0/subop/copy-byte 0/mod/direct 0/rm32/eax . . . . . 0/imm8 # copy byte to *eax - # ++curr - 40/increment-eax - eb/jump $clear-stream:loop/disp8 -$clear-stream:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -rewind-stream: # f: (addr stream byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - # eax = f - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - # f->read = 0 - c7 0/subop/copy 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 0/imm32 # copy to *(eax+4) -$rewind-stream:end: - # . restore registers - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/108write.subx b/baremetal/108write.subx deleted file mode 100644 index 43e9bf9b..00000000 --- a/baremetal/108write.subx +++ /dev/null @@ -1,220 +0,0 @@ -# write: write to in-memory streams -# -# We need to do this in machine code because streams need to be opaque types, -# and we don't yet support opaque types in Mu. - -== 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 - -write: # f: (addr stream byte), s: (addr array byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # if (s == 0) return - 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 0/imm32 # compare *(ebp+12) - 74/jump-if-= $write:end/disp8 - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 53/push-ebx - # ecx = f - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # edx = f->write - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy *ecx to edx - # ebx = f->size - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 3/r32/ebx 8/disp8 . # copy *(ecx+8) to ebx - # eax = _append-3(&f->data[f->write], &f->data[f->size], s) - # . . push s - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - # . . push &f->data[f->size] - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 3/index/ebx . 3/r32/ebx 0xc/disp8 . # copy ecx+ebx+12 to ebx - 53/push-ebx - # . . push &f->data[f->write] - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 3/r32/ebx 0xc/disp8 . # copy ecx+edx+12 to ebx - 53/push-ebx - # . . call - e8/call _append-3/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # f->write += eax - 01/add 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # add eax to *ecx - # . restore registers - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax -$write:end: - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-write-single: - # 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 - # write(_test-stream, "Ab") - # . . push args - 68/push "Ab"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(*_test-stream->data, 41/A 62/b 00 00, msg) - # . . push args - 68/push "F - test-write-single"/imm32 - 68/push 0x006241/imm32/Ab - # . . 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 - -test-write-appends: - # 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 - # write(_test-stream, "C") - # . . push args - 68/push "C"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # write(_test-stream, "D") - # . . push args - 68/push "D"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(*_test-stream->data, 43/C 44/D 00 00, msg) - # . . push args - 68/push "F - test-write-appends"/imm32 - 68/push 0x00004443/imm32/C-D - # . . 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 - -== data - -_test-stream: # (stream byte) - # current write index - 0/imm32 - # current read index - 0/imm32 - # size - 0x10/imm32 - # data (2 lines x 8 bytes/line) - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - -== code - -# 3-argument variant of _append -_append-3: # out: (addr byte), outend: (addr byte), s: (addr array byte) -> num_bytes_appended/eax - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - # eax = _append-4(out, outend, &s->data[0], &s->data[s->size]) - # . . push &s->data[s->size] - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 51/push-ecx - # . . push &s->data[0] - 8d/copy-address 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy eax+4 to ecx - 51/push-ecx - # . . push outend - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - # . . push out - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call _append-4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp -$_append-3:end: - # . restore registers - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# 4-argument variant of _append -_append-4: # out: (addr byte), outend: (addr byte), in: (addr byte), inend: (addr byte) -> num_bytes_appended/eax: int - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # num_bytes_appended = 0 - b8/copy-to-eax 0/imm32 - # edi = out - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi - # edx = outend - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx - # esi = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0x10/disp8 . # copy *(ebp+16) to esi - # ecx = inend - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x14/disp8 . # copy *(ebp+20) to ecx -$_append-4:loop: - # if (in >= inend) break - 39/compare 3/mod/direct 6/rm32/esi . . . 1/r32/ecx . . # compare esi with ecx - 73/jump-if-addr>= $_append-4:end/disp8 - # if (out >= outend) abort # just to catch test failures fast - 39/compare 3/mod/direct 7/rm32/edi . . . 2/r32/edx . . # compare edi with edx - 73/jump-if-addr>= $_append-4:end/disp8 # TODO: abort - # *out = *in - 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 3/r32/BL . . # copy byte at *esi to BL - 88/copy-byte 0/mod/indirect 7/rm32/edi . . . 3/r32/BL . . # copy byte at BL to *edi - # ++num_bytes_appended - 40/increment-eax - # ++in - 46/increment-esi - # ++out - 47/increment-edi - eb/jump $_append-4:loop/disp8 -$_append-4:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/109stream-equal.subx b/baremetal/109stream-equal.subx deleted file mode 100644 index 8f6cf1bf..00000000 --- a/baremetal/109stream-equal.subx +++ /dev/null @@ -1,595 +0,0 @@ -# some primitives for checking stream contents - -== 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 - -# compare all the data in a stream (ignoring the read pointer) -stream-data-equal?: # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 56/push-esi - 57/push-edi - # esi = f - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # eax = f->write - 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax - # var maxf/edx: (addr byte) = &f->data[f->write] - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 0/index/eax . 2/r32/edx 0xc/disp8 . # copy esi+eax+12 to edx - # var currf/esi: (addr byte) = f->data - 81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0xc/imm32 # add to esi - # edi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi -$stream-data-equal?:compare-sizes: - # if (f->write != s->size) return false - 39/compare 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # compare *edi and eax - 75/jump-if-!= $stream-data-equal?:false/disp8 - # var currs/edi: (addr byte) = s->data - 81 0/subop/add 3/mod/direct 7/rm32/edi . . . . . 4/imm32 # add to edi - # var eax: byte = 0 - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - # var ecx: byte = 0 - 31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx -$stream-data-equal?:loop: - # if (currf >= maxf) return true - 39/compare 3/mod/direct 6/rm32/esi . . . 2/r32/edx . . # compare esi with edx - 73/jump-if-addr>= $stream-data-equal?:true/disp8 - # AL = *currs - 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 0/r32/AL . . # copy byte at *esi to AL - # CL = *curr - 8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 1/r32/CL . . # copy byte at *edi to CL - # if (eax != ecx) return false - 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax and ecx - 75/jump-if-!= $stream-data-equal?:false/disp8 - # ++f - 46/increment-esi - # ++curr - 47/increment-edi - eb/jump $stream-data-equal?:loop/disp8 -$stream-data-equal?:false: - b8/copy-to-eax 0/imm32 - eb/jump $stream-data-equal?:end/disp8 -$stream-data-equal?:true: - b8/copy-to-eax 1/imm32 -$stream-data-equal?:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-stream-data-equal: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # write(_test-stream, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # eax = stream-data-equal?(_test-stream, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call stream-data-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-stream-data-equal"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-stream-data-equal-2: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # write(_test-stream, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # eax = stream-data-equal?(_test-stream, "Abd") - # . . push args - 68/push "Abd"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call stream-data-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-stream-data-equal-2"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-stream-data-equal-size-check: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # write(_test-stream, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # eax = stream-data-equal?(_test-stream, "Abcd") - # . . push args - 68/push "Abcd"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call stream-data-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-stream-data-equal-size-check"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# helper for later tests -check-stream-equal: # f: (addr stream byte), s: (addr array byte), msg: (addr array byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - # eax = stream-data-equal?(f, s) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call stream-data-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -$check-stream-equal:end: - # . restore registers - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# scan the next line until newline starting from f->read and compare it with -# 's' (ignoring the trailing newline) -# on success, set f->read to after the next newline -# on failure, leave f->read unmodified -# this function is usually used only in tests, so we repeatedly write f->read -next-stream-line-equal?: # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean - # pseudocode: - # currf = f->read # bound: f->write - # currs = 0 # bound: s->size - # while true - # if currf >= f->write - # return currs >= s->size - # if f[currf] == '\n' - # ++currf - # return currs >= s->size - # if (currs >= s->size) return false # the current line of f still has data to match - # if (f[currf] != s[currs]) return false - # ++currf - # ++currs - # - # collapsing the two branches that can return true: - # currf = f->read # bound: f->write - # currs = 0 # bound: s->size - # while true - # if (currf >= f->write) break - # if (f[currf] == '\n') break - # if (currs >= s->size) return false # the current line of f still has data to match - # if (f[currf] != s[currs]) return false - # ++currf - # ++currs - # ++currf # skip '\n' - # return currs >= s->size - # Here the final `++currf` is sometimes unnecessary (if we're already at the end of the stream) - # - # registers: - # f: esi - # s: edi - # currf: ecx - # currs: edx - # f[currf]: eax - # s[currs]: ebx - # - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 56/push-esi - 57/push-edi - # esi = f - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # var currf/ecx: int = f->read - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - # edi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi - # var currs/edx: int = 0 - 31/xor 3/mod/direct 2/rm32/edx . . . 2/r32/edx . . # clear edx - # var c1/eax: byte = 0 - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - # var c2/ebx: byte = 0 - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx -$next-stream-line-equal?:loop: - # if (currf >= f->write) break - 3b/compare 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # compare ecx with *esi - 7d/jump-if->= $next-stream-line-equal?:break/disp8 - # c1 = f->data[f->read] - 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 - # if (c1 == '\n') break - 3d/compare-eax-and 0xa/imm32/newline - 74/jump-if-= $next-stream-line-equal?:break/disp8 - # if (currs >= s->size) return false - 3b/compare 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # compare edx with *edi - 7d/jump-if->= $next-stream-line-equal?:false/disp8 - # c2 = s->data[currs] - 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/edi 2/index/edx . 3/r32/BL 4/disp8 . # copy byte at *(edi+edx+4) to BL - # if (c1 != c2) return false - 39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx - 75/jump-if-!= $next-stream-line-equal?:false/disp8 - # ++currf - 41/increment-ecx - # ++currs - 42/increment-edx - eb/jump $next-stream-line-equal?:loop/disp8 -$next-stream-line-equal?:break: - # ++currf - 41/increment-ecx - # if (currs >= s->size) return true - 3b/compare 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # compare edx with *edi - 7c/jump-if-< $next-stream-line-equal?:false/disp8 -$next-stream-line-equal?:true: - b8/copy-to-eax 1/imm32 - # persist f->read on success - 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4) - eb/jump $next-stream-line-equal?:end/disp8 -$next-stream-line-equal?:false: - b8/copy-to-eax 0/imm32 -$next-stream-line-equal?:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-stream-line-equal-stops-at-newline: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # write(_test-stream, "Abc\ndef") - # . . push args - 68/push "Abc\ndef"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # eax = next-stream-line-equal?(_test-stream, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-next-stream-line-equal-stops-at-newline"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-stream-line-equal-stops-at-newline-2: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # write(_test-stream, "Abc\ndef") - # . . push args - 68/push "Abc\ndef"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # eax = next-stream-line-equal?(_test-stream, "def") - # . . push args - 68/push "def"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-next-stream-line-equal-stops-at-newline-2"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-stream-line-equal-skips-newline: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # write(_test-stream, "Abc\ndef\n") - # . . push args - 68/push "Abc\ndef\n"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # next-stream-line-equal?(_test-stream, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # eax = next-stream-line-equal?(_test-stream, "def") - # . . push args - 68/push "def"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-next-stream-line-equal-skips-newline"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-stream-line-equal-handles-final-line: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # write(_test-stream, "Abc\ndef") - # . . push args - 68/push "Abc\ndef"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # next-stream-line-equal?(_test-stream, "Abc") - # . . push args - 68/push "Abc"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # eax = next-stream-line-equal?(_test-stream, "def") - # . . push args - 68/push "def"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-next-stream-line-equal-skips-newline"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-stream-line-equal-always-fails-after-Eof: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # write nothing - # eax = next-stream-line-equal?(_test-stream, "") - # . . push args - 68/push ""/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-next-stream-line-equal-always-fails-after-Eof"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = next-stream-line-equal?(_test-stream, "") - # . . push args - 68/push ""/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-next-stream-line-equal-always-fails-after-Eof/2"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# helper for later tests -check-next-stream-line-equal: # f: (addr stream byte), s: (addr array byte), msg: (addr array byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - # eax = next-stream-line-equal?(f, s) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call next-stream-line-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . restore registers - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/112read-byte.subx b/baremetal/112read-byte.subx deleted file mode 100644 index 0c9af75b..00000000 --- a/baremetal/112read-byte.subx +++ /dev/null @@ -1,123 +0,0 @@ -# Read a single byte from a stream. -# -# We need to do this in machine code because streams need to be opaque types, -# and we don't yet support opaque types in Mu. - -== 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 - -# Return next byte value in eax, with top 3 bytes cleared. -# Abort on reaching end of stream. -read-byte: # s: (addr stream byte) -> result/eax: byte - # . prologue - 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 = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # ecx = s->read - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - # if (f->read >= f->write) abort - 3b/compare 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # compare ecx with *esi - 0f 8d/jump-if->= $read-byte:abort/disp32 - # result = 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 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL - # ++f->read - ff 0/subop/increment 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # increment *(esi+4) -$read-byte:end: - # . restore registers - 5e/pop-to-esi - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$read-byte:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "read-byte: empty stream" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -== data - -_test-input-stream: # (stream byte) - # current write index - 0/imm32 - # current read index - 0/imm32 - # size - 0x400/imm32 # 1024 bytes - # data (64 lines x 16 bytes/line) - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/113write-stream.subx b/baremetal/113write-stream.subx deleted file mode 100644 index 7dd93fba..00000000 --- a/baremetal/113write-stream.subx +++ /dev/null @@ -1,173 +0,0 @@ -# write-stream: like write, but write streams rather than strings - -== 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 - -write-stream: # f: (addr stream byte), s: (addr stream byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - 56/push-esi - 57/push-edi - # edi = f - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi - # esi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi - # eax = _append-4(&f->data[f->write], &f->data[f->size], &s->data[s->read], &s->data[s->write]) - # . . push &s->data[s->write] - 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 0/index/eax . 0/r32/eax 0xc/disp8 . # copy esi+eax+12 to eax - 50/push-eax - # . . push &s->data[s->read] - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy *(esi+4) to eax - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 0/index/eax . 0/r32/eax 0xc/disp8 . # copy esi+eax+12 to eax - 50/push-eax - # . . push &f->data[f->size] - 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 8/disp8 . # copy *(edi+8) to eax - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 0/index/eax . 0/r32/eax 0xc/disp8 . # copy edi+eax+12 to eax - 50/push-eax - # . . push &f->data[f->write] - 8b/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy *edi to eax - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 0/index/eax . 0/r32/eax 0xc/disp8 . # copy edi+eax+12 to eax - 50/push-eax - # . . call - e8/call _append-4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # f->write += eax - 01/add 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # add eax to *edi - # s->read += eax - 01/add 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # add eax to *(esi+4) -$write-stream:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-write-stream-single: - # 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-stream2) - # . . push args - 68/push _test-stream2/imm32 - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # . write(_test-stream2, "Ab") - # . . push args - 68/push "Ab"/imm32 - 68/push _test-stream2/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # write-stream(_test-stream, _test-stream2) - # . . push args - 68/push _test-stream2/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "Ab", msg) - # . . push args - 68/push "F - test-write-stream-single"/imm32 - 68/push "Ab"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . end - c3/return - -test-write-stream-appends: - # 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-stream2) - # . . push args - 68/push _test-stream2/imm32 - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # . write(_test-stream2, "C") - # . . push args - 68/push "C"/imm32 - 68/push _test-stream2/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # first write - # . write-stream(_test-stream, _test-stream2) - # . . push args - 68/push _test-stream2/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # second write - # . write(_test-stream2, "D") - # . . push args - 68/push "D"/imm32 - 68/push _test-stream2/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # . write-stream(_test-stream, _test-stream2) - # . . push args - 68/push _test-stream2/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "CD", msg) - # . . push args - 68/push "F - test-write-stream-appends"/imm32 - 68/push "CD"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . end - c3/return - -== data - -_test-stream2: # (stream byte) - # current write index - 4/imm32 - # current read index - 1/imm32 - # size - 8/imm32 - # data - 41/A 42/B 43/C 44/D 00 00 00 00 # 8 bytes - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/115write-byte.subx b/baremetal/115write-byte.subx deleted file mode 100644 index 6935d65b..00000000 --- a/baremetal/115write-byte.subx +++ /dev/null @@ -1,82 +0,0 @@ -# Write a single byte to a stream. -# -# We need to do this in machine code because streams need to be opaque types, -# and we don't yet support opaque types in Mu. - -== 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 - -# Write lower byte of 'n' to 'f'. -append-byte: # f: (addr stream byte), n: int - # . prologue - 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 - 57/push-edi - # edi = f - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi - # ecx = f->write - 8b/copy 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # copy *edi to ecx - # if (f->write >= f->size) abort - 3b/compare 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 8/disp8 . # compare ecx with *(edi+8) - 7d/jump-if->= $append-byte:abort/disp8 -$append-byte:to-stream: - # write to stream - # f->data[f->write] = LSB(n) - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - 8a/copy-byte 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/AL 0xc/disp8 . # copy byte at *(ebp+12) to AL - 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) - # ++f->write - ff 0/subop/increment 0/mod/indirect 7/rm32/edi . . . . . . # increment *edi -$append-byte:end: - # . restore registers - 5f/pop-to-edi - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$append-byte:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "append-byte: out of space\n" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -test-append-byte-single: - # - check that append-byte writes to 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 - # append-byte(_test-stream, 'A') - # . . push args - 68/push 0x41/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call append-byte/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "A", msg) - # . . push args - 68/push "F - test-append-byte-single"/imm32 - 68/push "A"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-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/baremetal/117write-int-hex.subx b/baremetal/117write-int-hex.subx deleted file mode 100644 index 091bd874..00000000 --- a/baremetal/117write-int-hex.subx +++ /dev/null @@ -1,202 +0,0 @@ -# Write out the (hex) textual representation of numbers. - -== 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 - -# convert the lowest nibble of eax to ascii and return it in the lowest byte of eax -to-hex-char: # in/eax: int -> out/eax: int - # no error checking; accepts argument in eax - # if (eax <= 9) return eax + '0' - 3d/compare-eax-with 0x9/imm32/9 - 7f/jump-if-> $to-hex-char:else/disp8 - 05/add-to-eax 0x30/imm32/0 - c3/return -$to-hex-char:else: - # otherwise return eax + 'a' - 10 - 05/add-to-eax 0x57/imm32/a-10 - c3/return - -append-byte-hex: # f: (addr stream byte), n: int - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - # AL = convert upper nibble to hex - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax - c1/shift 5/subop/logic-right 3/mod/direct 0/rm32/eax . . . . . 4/imm8 # shift eax right by 4 bits, while padding zeroes - 25/and-eax 0xf/imm32 - # . AL = to-hex-char(AL) - e8/call to-hex-char/disp32 - # append-byte(f, AL) - # . . push args - 50/push-eax - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call append-byte/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # AL = convert lower nibble to hex - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax - 25/and-eax 0xf/imm32 - # . AL = to-hex-char(AL) - e8/call to-hex-char/disp32 - # append-byte(f, AL) - # . . push args - 50/push-eax - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call append-byte/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -$append-byte-hex:end: - # . restore registers - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-append-byte-hex: - # - check that append-byte-hex adds the hex textual representation - # 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 - # append-byte-hex(_test-stream, 0xa) # exercises digit, non-digit as well as leading zero - # . . push args - 68/push 0xa/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call append-byte-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "0a", msg) - # . . push args - 68/push "F - test-append-byte-hex"/imm32 - 68/push "0a"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . end - c3/return - -write-int32-hex: # f: (addr stream byte), n: int - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp -$write-int32-hex:hex-prefix: - # write(f, "0x") - # . . push args - 68/push "0x"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -$write-int32-hex:rest: - # write-int32-hex-bits(f, n, 32) - # . . push args - 68/push 0x20/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call write-int32-hex-bits/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -$write-int32-hex:end: - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# print rightmost 'bits' of 'n' -# bits must be multiple of 4 -write-int32-hex-bits: # f: (addr stream byte), n: int, bits: int - # pseudocode: - # bits -= 4 - # while true - # if (bits < 0) break - # eax = n >> bits - # eax = eax & 0xf - # append-byte(f, AL) - # bits -= 4 - # - # . prologue - 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 - # ecx = bits-4 - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # copy *(ebp+16) to ecx - 81 5/subop/subtract 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # subtract from ecx -$write-int32-hex-bits:loop: - # if (bits < 0) break - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0/imm32 # compare ecx - 7c/jump-if-< $write-int32-hex-bits:end/disp8 - # eax = n >> bits - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax - d3/>>ecx 5/subop/pad-zeroes 3/mod/direct 0/rm32/eax . . . . . . # shift eax right by ecx bits, padding zeroes - # eax = to-hex-char(AL) - 25/and-eax 0xf/imm32 - e8/call to-hex-char/disp32 - # append-byte(f, AL) - # . . push args - 50/push-eax - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call append-byte/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # bits -= 4 - 81 5/subop/subtract 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # subtract from ecx - eb/jump $write-int32-hex-bits:loop/disp8 -$write-int32-hex-bits:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-write-int32-hex: - # - check that write-int32-hex prints the hex textual representation - # 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 - # write-int32-hex(_test-stream, 0x8899aa) - # . . push args - 68/push 0x8899aa/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-int32-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "0x008899aa", msg) - # . . push args - 68/push "F - test-write-int32-hex"/imm32 - 68/push "0x008899aa"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-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/baremetal/118parse-hex-int.subx b/baremetal/118parse-hex-int.subx deleted file mode 100644 index 153def3c..00000000 --- a/baremetal/118parse-hex-int.subx +++ /dev/null @@ -1,897 +0,0 @@ -# some utilities for converting numbers from hex -# lowercase letters only for now - -== 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 - -is-hex-int?: # in: (addr slice) -> result/eax: boolean - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - # ecx = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # edx = s->end - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx - # var curr/ecx: (addr byte) = s->start - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx - # if s is empty return false - b8/copy-to-eax 0/imm32/false - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 73/jump-if-addr>= $is-hex-int?:end/disp8 - # skip past leading '-' - # . if (*curr == '-') ++curr - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x2d/imm32/- # compare ebx - 75/jump-if-!= $is-hex-int?:initial-0/disp8 - # . ++curr - 41/increment-ecx - # skip past leading '0x' -$is-hex-int?:initial-0: - # . if (*curr != '0') jump to loop - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x30/imm32/0 # compare ebx - 75/jump-if-!= $is-hex-int?:loop/disp8 - # . ++curr - 41/increment-ecx -$is-hex-int?:initial-0x: - # . if (curr >= in->end) return true - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 73/jump-if-addr>= $is-hex-int?:true/disp8 - # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x78/imm32/x # compare ebx - 75/jump-if-!= $is-hex-int?:loop/disp8 - # . ++curr - 41/increment-ecx -$is-hex-int?:loop: - # if (curr >= in->end) return true - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 73/jump-if-addr>= $is-hex-int?:true/disp8 - # var eax: boolean = is-hex-digit?(*curr) - # . . push args - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL - 50/push-eax - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # if (eax == false) return false - 3d/compare-eax-and 0/imm32/false - 74/jump-if-= $is-hex-int?:end/disp8 - # ++curr - 41/increment-ecx - # loop - eb/jump $is-hex-int?:loop/disp8 -$is-hex-int?:true: - # return true - b8/copy-to-eax 1/imm32/true -$is-hex-int?:end: - # . restore registers - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-hex-int: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "34" - b8/copy-to-eax "34"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = is-hex-int?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call is-hex-int?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-is-hex-int"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-hex-int-handles-letters: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "34a" - b8/copy-to-eax "34a"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = is-hex-int?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call is-hex-int?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-is-hex-int-handles-letters"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-hex-int-with-trailing-char: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "34q" - b8/copy-to-eax "34q"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = is-hex-int?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call is-hex-int?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-is-hex-int-with-trailing-char"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-hex-int-with-leading-char: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "q34" - b8/copy-to-eax "q34"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = is-hex-int?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call is-hex-int?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-is-hex-int-with-leading-char"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-hex-int-empty: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var slice/ecx: slice = "" - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = is-hex-int?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call is-hex-int?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-is-hex-int-empty"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-hex-int-handles-0x-prefix: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "0x3a" - b8/copy-to-eax "0x3a"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = is-hex-int?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call is-hex-int?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-is-hex-int-handles-0x-prefix"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-hex-int-handles-negative: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "-34a" - b8/copy-to-eax "-34a"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = is-hex-int?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call is-hex-int?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-is-hex-int-handles-negative"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-hex-int-handles-negative-0x-prefix: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "-0x3a" - b8/copy-to-eax "-0x3a"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = is-hex-int?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call is-hex-int?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-is-hex-int-handles-negative-0x-prefix"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -parse-hex-int: # in: (addr array byte) -> result/eax: int - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - # eax = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - # var curr/ecx: (addr byte) = &in->data - 8d/copy-address 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy eax+4 to ecx - # var max/edx: (addr byte) = &in->data[in->size] - # . edx = in->size - 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx - # . edx = in->data + in->size - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx - # return parse-hex-int-helper(curr, max) - # . . push args - 52/push-edx - 51/push-ecx - # . . call - e8/call parse-hex-int-helper/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -$parse-hex-int:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -parse-hex-int-from-slice: # in: (addr slice) -> result/eax: int - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - # ecx = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # var max/edx: (addr byte) = in->end - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx - # var curr/ecx: (addr byte) = in->start - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx - # return parse-hex-int-helper(curr, max) - # . . push args - 52/push-edx - 51/push-ecx - # . . call - e8/call parse-hex-int-helper/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -$parse-hex-int-from-slice:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -parse-hex-int-helper: # start: (addr byte), end: (addr byte) -> result/eax: int - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - # var curr/ecx: (addr byte) = start - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # edx = max - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx - # var result/ebx: int = 0 - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx - # var negate?/esi: boolean = false - 31/xor 3/mod/direct 6/rm32/esi . . . 6/r32/esi . . # clear esi -$parse-hex-int-helper:negative: - # if (*curr == '-') ++curr, negate = true - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL - 3d/compare-eax-and 0x2d/imm32/- - 75/jump-if-!= $parse-hex-int-helper:initial-0/disp8 - # . ++curr - 41/increment-ecx - # . negate = true - be/copy-to-esi 1/imm32/true -$parse-hex-int-helper:initial-0: - # skip past leading '0x' - # . if (*curr != '0') jump to loop - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL - 3d/compare-eax-and 0x30/imm32/0 - 75/jump-if-!= $parse-hex-int-helper:loop/disp8 - # . ++curr - 41/increment-ecx -$parse-hex-int-helper:initial-0x: - # . if (curr >= in->end) return result - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 73/jump-if-addr>= $parse-hex-int-helper:end/disp8 - # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL - 3d/compare-eax-and 0x78/imm32/x - 75/jump-if-!= $parse-hex-int-helper:loop/disp8 - # . ++curr - 41/increment-ecx -$parse-hex-int-helper:loop: - # if (curr >= in->end) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 73/jump-if-addr>= $parse-hex-int-helper:negate/disp8 - # var eax: int = from-hex-char(*curr) - # . . copy arg to eax - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL - # . . call - e8/call from-hex-char/disp32 - # result = result * 16 + eax - c1/shift 4/subop/left 3/mod/direct 3/rm32/ebx . . . . . 4/imm8 # shift ebx left by 4 bits - 01/add 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # add eax to ebx - # ++curr - 41/increment-ecx - # loop - eb/jump $parse-hex-int-helper:loop/disp8 -$parse-hex-int-helper:negate: - # if (negate?) result = -result - 81 7/subop/compare 3/mod/direct 6/rm32/esi . . . . . 0/imm32/false # compare esi - 74/jump-if-= $parse-hex-int-helper:end/disp8 - f7 3/subop/negate 3/mod/direct 3/rm32/ebx . . . . . . # negate ebx -$parse-hex-int-helper:end: - # return result - 89/copy 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # copy ebx to eax - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-parse-hex-int-from-slice-single-digit: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "a" - b8/copy-to-eax "a"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = parse-hex-int-from-slice(slice) - # . . push args - 51/push-ecx - # . . call - e8/call parse-hex-int-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0xa, msg) - # . . push args - 68/push "F - test-parse-hex-int-from-slice-single-digit"/imm32 - 68/push 0xa/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-parse-hex-int-from-slice-multi-digit: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "34a" - b8/copy-to-eax "34a"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = parse-hex-int-from-slice(slice) - # . . push args - 51/push-ecx - # . . call - e8/call parse-hex-int-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0x34a, msg) - # . . push args - 68/push "F - test-parse-hex-int-from-slice-multi-digit"/imm32 - 68/push 0x34a/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-parse-hex-int-from-slice-0x-prefix: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "0x34" - b8/copy-to-eax "0x34"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = parse-hex-int-from-slice(slice) - # . . push args - 51/push-ecx - # . . call - e8/call parse-hex-int-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0x34, msg) - # . . push args - 68/push "F - test-parse-hex-int-from-slice-0x-prefix"/imm32 - 68/push 0x34/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-parse-hex-int-from-slice-zero: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "0" - b8/copy-to-eax "0"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = parse-hex-int-from-slice(slice) - # . . push args - 51/push-ecx - # . . call - e8/call parse-hex-int-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-parse-hex-int-from-slice-zero"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-parse-hex-int-from-slice-0-prefix: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "03" - b8/copy-to-eax "03"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = parse-hex-int-from-slice(slice) - # . . push args - 51/push-ecx - # . . call - e8/call parse-hex-int-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0x3, msg) - # . . push args - 68/push "F - test-parse-hex-int-from-slice-0-prefix"/imm32 - 68/push 0x3/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-parse-hex-int-from-slice-negative: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "-03" - b8/copy-to-eax "-03"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = parse-hex-int-from-slice(slice) - # . . push args - 51/push-ecx - # . . call - e8/call parse-hex-int-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, -3, msg) - # . . push args - 68/push "F - test-parse-hex-int-from-slice-negative"/imm32 - 68/push -3/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -is-hex-digit?: # c: byte -> result/eax: boolean - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - # ecx = c - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # return false if c < '0' - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x30/imm32 # compare ecx - 7c/jump-if-< $is-hex-digit?:false/disp8 - # return true if c <= '9' - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x39/imm32 # compare ecx - 7e/jump-if-<= $is-hex-digit?:true/disp8 - # drop case - 25/and-eax-with 0x5f/imm32 - # return false if c > 'f' - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x66/imm32 # compare ecx - 7f/jump-if-> $is-hex-digit?:false/disp8 - # return true if c >= 'a' - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x61/imm32 # compare ecx - 7d/jump-if->= $is-hex-digit?:true/disp8 - # otherwise return false -$is-hex-digit?:false: - b8/copy-to-eax 0/imm32/false - eb/jump $is-hex-digit?:end/disp8 -$is-hex-digit?:true: - b8/copy-to-eax 1/imm32/true -$is-hex-digit?:end: - # . restore registers - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-hex-below-0: - # eax = is-hex-digit?(0x2f) - # . . push args - 68/push 0x2f/imm32 - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-hex-below-0"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-hex-0-to-9: - # eax = is-hex-digit?(0x30) - # . . push args - 68/push 0x30/imm32 - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-hex-at-0"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = is-hex-digit?(0x39) - # . . push args - 68/push 0x39/imm32 - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-hex-at-9"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-hex-above-9-to-a: - # eax = is-hex-digit?(0x3a) - # . . push args - 68/push 0x3a/imm32 - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-hex-above-9-to-a"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-hex-a-to-f: - # eax = is-hex-digit?(0x61) - # . . push args - 68/push 0x61/imm32 - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-hex-at-a"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = is-hex-digit?(0x66) - # . . push args - 68/push 0x66/imm32 - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-hex-at-f"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-hex-above-f: - # eax = is-hex-digit?(0x67) - # . . push args - 68/push 0x67/imm32 - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-hex-above-f"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -from-hex-char: # in/eax: byte -> out/eax: nibble -$from-hex-char:check0: - # if (eax < '0') goto abort - 3d/compare-eax-with 0x30/imm32/0 - 7c/jump-if-< $from-hex-char:abort/disp8 -$from-hex-char:check1: - # if (eax > 'f') goto abort - 3d/compare-eax-with 0x66/imm32/f - 7f/jump-if-> $from-hex-char:abort/disp8 -$from-hex-char:check2: - # if (eax > '9') goto next check - 3d/compare-eax-with 0x39/imm32/9 - 7f/jump-if-> $from-hex-char:check3/disp8 -$from-hex-char:digit: - # return eax - '0' - 2d/subtract-from-eax 0x30/imm32/0 - c3/return -$from-hex-char:check3: - # if (eax < 'a') goto abort - 3d/compare-eax-with 0x61/imm32/a - 7c/jump-if-< $from-hex-char:abort/disp8 -$from-hex-char:letter: - # return eax - ('a'-10) - 2d/subtract-from-eax 0x57/imm32/a-10 - c3/return - -$from-hex-char:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "invalid hex char" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/120allocate.subx b/baremetal/120allocate.subx deleted file mode 100644 index 38c4110b..00000000 --- a/baremetal/120allocate.subx +++ /dev/null @@ -1,914 +0,0 @@ -# Helper to dynamically allocate memory on the heap. -# -# We'd like to be able to write tests for functions that allocate memory, -# making assertions on the precise addresses used. To achieve this we'll pass -# in an *allocation descriptor* to allocate from. -# -# Allocation descriptors are also useful outside of tests. Assembly and machine -# code are of necessity unsafe languages, and one of the most insidious kinds -# of bugs unsafe languages expose us to are dangling pointers to memory that -# has been freed and potentially even reused for something totally different. -# To reduce the odds of such "use after free" errors, SubX programs tend to not -# reclaim and reuse dynamically allocated memory. (Running out of memory is far -# easier to debug.) Long-running programs that want to reuse memory are mostly -# on their own to be careful. However, they do get one bit of help: they can -# carve out chunks of memory and then allocate from them manually using this -# very same 'allocate' helper. They just need a new allocation descriptor for -# their book-keeping. - -== data - -# Allocations are returned in a handle, which consists of an alloc-id and a payload. -# The alloc-id helps detect use-after-free errors. -Handle-size: # (addr int) - 8/imm32 - -# A default allocation descriptor for programs to use. -Heap: # allocation-descriptor - # curr - 0x01000000/imm32 # 16 MB - # limit - 0x02000000/imm32 # 32 MB - -Next-alloc-id: # int - 0x100/imm32 # save a few alloc ids for fake handles - -== 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 - -# Allocate and clear 'n' bytes of memory from an allocation-descriptor 'ad'. -# Abort if there isn't enough memory in 'ad'. -allocate: # ad: (addr allocation-descriptor), n: int, out: (addr handle _) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - # allocate-raw(ad, n, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call allocate-raw/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = out->payload + 4 - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax - 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax - 05/add-to-eax 4/imm32 - # zero-out(eax, n) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - 50/push-eax - # . . call - e8/call zero-out/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -$allocate:end: - # . restore registers - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# Claim the next 'n' bytes of memory starting at ad->curr and update ad->curr. -# Abort if there isn't enough memory in 'ad'. -allocate-raw: # ad: (addr allocation-descriptor), n: int, out: (addr handle _) - # . prologue - 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 - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # ecx = ad - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # edx = out - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx - # ebx = n - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 3/r32/ebx 0xc/disp8 . # copy *(ebp+12) to ebx - # out->alloc-id = Next-alloc-id - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/eax Next-alloc-id/disp32 # copy *Next-alloc-id to eax - 89/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . . # copy eax to *edx - # out->payload = ad->curr - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax -$allocate-raw:save-payload-in-eax: - 89/copy 1/mod/*+disp8 2/rm32/edx . . . 0/r32/eax 4/disp8 . # copy eax to *(edx+4) - # *out->payload = Next-alloc-id - 8b/copy 1/mod/*+disp8 2/rm32/edx . . . 7/r32/edi 4/disp8 . # copy *(edx+4) to edi - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 6/r32/esi Next-alloc-id/disp32 # copy *Next-alloc-id to esi - 89/copy 0/mod/indirect 7/rm32/edi . . . 6/r32/esi . . # copy esi to *edi -$allocate-raw:increment-next-alloc-id: - # increment *Next-alloc-id - ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # increment *Next-alloc-id - # check if there's enough space - # TODO: move this check up before any state updates when we support error recovery - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 3/index/ebx . 0/r32/eax 4/disp8 . # copy eax+ebx+4 to eax - 3b/compare 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # compare eax with *(ecx+4) - 73/jump-if->=-signed $allocate-raw:abort/disp8 -$allocate-raw:commit: - # ad->curr += n+4 - 89/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy eax to *ecx -$allocate-raw:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$allocate-raw:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "allocate: failed" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -test-allocate-raw-success: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var ad/ecx: allocation-descriptor containing 16 bytes - # . var end/ecx: (addr byte) - 89/<- %ecx 4/r32/esp - # . var start/edx: (addr byte) = end - 16 - 81 5/subop/subtract %esp 0x10/imm32 - 89/<- %edx 4/r32/esp - # . ad = {start, end} - 51/push-ecx - 52/push-edx - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # var expected-payload/ebx = ad->curr - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 3/r32/ebx . . # copy *ecx to ebx - # var h/edx: handle = {0, 0} - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx - # *Next-alloc-id = 0x34 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id - # allocate-raw(ad, 3, h) - # . . push args - 52/push-edx - 68/push 3/imm32 - 51/push-ecx - # . . call - e8/call allocate-raw/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->alloc-id, 0x34, msg) - # . . push args - 68/push "F - test-allocate-raw-success: sets alloc-id in handle"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->payload, expected-payload, msg) - # . . push args - 68/push "F - test-allocate-raw-success: sets payload in handle"/imm32 - 53/push-ebx - ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->payload->alloc-id, 0x34, msg) - # . . push args - 68/push "F - test-allocate-raw-success: sets alloc-id in payload"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(*Next-alloc-id, 0x35, msg) - # . . push args - 68/push "F - test-allocate-raw-success: increments Next-alloc-id"/imm32 - 68/push 0x35/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # push *Next-alloc-id - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(ad->curr - expected-payload, 3 + 4 for alloc-id, msg) - # . . push args - 68/push "F - test-allocate-raw-success: updates allocation descriptor"/imm32 - 68/push 7/imm32 - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax - 29/subtract 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # subtract ebx from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # clean up - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x100/imm32 # copy to *Next-alloc-id - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x20/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -lookup: # h: (handle _T) -> result/eax: (addr _T) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - # eax = 0 - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - # ecx = handle->alloc_id - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # if (ecx == 0) return 0 - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0/imm32 # compare ecx - 74/jump-if-= $lookup:end/disp8 - # eax = handle->address (payload) - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax - # if (ecx != *eax) abort - 39/compare 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # compare *eax and ecx - 75/jump-if-!= $lookup:abort/disp8 - # add 4 to eax - 05/add-to-eax 4/imm32 -$lookup:end: - # . restore registers - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$lookup:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "lookup: failed" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -test-lookup-success: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var ad/ebx: allocation-descriptor containing 16 bytes - # . var end/ecx: (addr byte) - 89/<- %ecx 4/r32/esp - # . var start/edx: (addr byte) = end - 16 - 81 5/subop/subtract %esp 0x10/imm32 - 89/<- %edx 4/r32/esp - # . ad = {start, end} - 51/push-ecx - 52/push-edx - 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx - # var handle/ecx: handle - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # var old-top/edx = ad->curr - 8b/copy 0/mod/indirect 3/rm32/ebx . . . 2/r32/edx . . # copy *ebx to edx - # allocate-raw(ad, 2, handle) - # . . push args - 51/push-ecx - 68/push 2/imm32/size - 53/push-ebx - # . . call - e8/call allocate-raw/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = lookup(handle) - # . . push args - ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) - ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx - # . . call - e8/call lookup/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # eax contains old top of heap, except skipping the alloc-id in the payload - # . check-ints-equal(eax, old-top+4, msg) - # . . push args - 68/push "F - test-lookup-success"/imm32 - 81 0/subop/add 3/mod/direct 2/rm32/edx . . . . . 4/imm32 # add to edx - 52/push-edx - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # clean up - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x100/imm32 # copy to *Next-alloc-id - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x20/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-lookup-null-returns-null: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var handle/ecx: handle - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = lookup(handle) - # . . push args - ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) - ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx - # . . call - e8/call lookup/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-lookup-null-returns-null"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -_pending-test-lookup-failure: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var ad/ecx: allocation-descriptor containing 16 bytes - # . var end/ecx: (addr byte) - 89/<- %ecx 4/r32/esp - # . var start/edx: (addr byte) = end - 16 - 81 5/subop/subtract %esp 0x10/imm32 - 89/<- %edx 4/r32/esp - # . ad = {start, end} - 51/push-ecx - 52/push-edx - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # var h1/ecx: handle - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # var old_top/ebx = ad->curr - 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx - # first allocation, to h1 - # . allocate(ad, 2, h1) - # . . push args - 51/push-ecx - 68/push 2/imm32/size - 56/push-esi - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # reset ad->curr to mimic reclamation - 89/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy ebx to *esi - # second allocation that returns the same address as the first - # var h2/edx: handle - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx - # . allocate(ad, 2, h2) - # . . push args - 52/push-edx - 68/push 2/imm32/size - 56/push-esi - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h1->address, h2->address, msg) - # . . push args - 68/push "F - test-lookup-failure"/imm32 - ff 6/subop/push 1/mod/*+disp8 2/rm32/ecx . . . . 4/disp8 . # push *(edx+4) - ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # lookup(h1) should crash - # . . push args - ff 6/subop/push 1/mod/*+disp8 1/rm32/ecx . . . . 4/disp8 . # push *(ecx+4) - ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx - # . . call - e8/call lookup/disp32 - # should never get past this point - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # clean up - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x100/imm32 # copy to *Next-alloc-id - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x20/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# when comparing handles, just treat them as pure values -handle-equal?: # a: (handle _T), b: (handle _T) -> result/eax: boolean - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - # eax = false - b8/copy-to-eax 0/imm32/false -$handle-equal?:compare-alloc-id: - # ecx = a->alloc_id - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # if (ecx != b->alloc_id) return false - 39/compare 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # compare ecx and *(ebp+16) - 75/jump-if-!= $handle-equal?:end/disp8 -$handle-equal?:compare-address: - # ecx = handle->address - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx - # if (ecx != b->address) return false - 39/compare 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x14/disp8 . # compare ecx and *(ebp+20) - 75/jump-if-!= $handle-equal?:end/disp8 -$handle-equal?:return-true: - # return true - b8/copy-to-eax 1/imm32/true -$handle-equal?:end: - # . restore registers - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -copy-handle: # src: (handle _T), dest: (addr handle _T) - # . prologue - 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 - # ecx = dest - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # copy *(ebp+16) to ecx - # *dest = src - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - 89/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy eax to *ecx - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax - 89/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy eax to *(ecx+4) -$copy-handle:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# helper: create a nested allocation descriptor (useful for tests) -allocate-region: # ad: (addr allocation-descriptor), n: int, out: (addr handle allocation-descriptor) - # . prologue - 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 - # allocate(ad, n, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = out->payload - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax - 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax - # skip payload->allocid - 05/add-to-eax 4/imm32 - # if (eax == 0) abort - 3d/compare-eax-and 0/imm32 - 74/jump-if-= $allocate-region:abort/disp8 - # earmark 8 bytes at the start for a new allocation descriptor - # . *eax = eax + 8 - 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx - 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 8/imm32 # add to ecx - 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax - # . *(eax+4) = eax + n - 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx - 03/add 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # add *(ebp+12) to ecx - 89/copy 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy ecx to *(eax+4) - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# We could create a more general '$abort' jump target, but then we'd need to do -# a conditional jump followed by loading the error message and an unconditional -# jump. Or we'd need to unconditionally load the error message before a -# conditional jump, even if it's unused the vast majority of the time. This way -# we bloat a potentially cold segment in RAM so we can abort with a single -# instruction. -$allocate-region:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "allocate-region: failed to allocate" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -# Claim the next 'n+4' bytes of memory and initialize the first 4 to n. -# Abort if there isn't enough memory in 'ad'. -allocate-array: # ad: (addr allocation-descriptor), n: int, out: (addr handle _) - # . prologue - 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 - 52/push-edx - # ecx = n - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx - # var size/edx: int = n+4 - 8d/copy-address 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy ecx+4 to edx - # allocate(ad, size, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - 52/push-edx - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # *out->payload = n - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax - 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax - # . skip payload->allocid - 05/add-to-eax 4/imm32 - # . - 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax -$allocate-array:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-allocate-array: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var ad/ecx: allocation-descriptor containing 16 bytes - # . var end/ecx: (addr byte) - 89/<- %ecx 4/r32/esp - # . var start/edx: (addr byte) = end - 16 - 81 5/subop/subtract %esp 0x10/imm32 - 89/<- %edx 4/r32/esp - # . ad = {start, end} - 51/push-ecx - 52/push-edx - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # var expected-payload/ebx = ad->curr - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 3/r32/ebx . . # copy *ecx to ebx - # var h/edx: handle = {0, 0} - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx - # *Next-alloc-id = 0x34 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id - # allocate-array(ad, 3, h) - # . . push args - 52/push-edx - 68/push 3/imm32 - 51/push-ecx - # . . call - e8/call allocate-array/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->alloc-id, 0x34, msg) - # . . push args - 68/push "F - test-allocate-array: sets alloc-id in handle"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->payload, expected-payload, msg) - # . . push args - 68/push "F - test-allocate-array: sets payload in handle"/imm32 - 53/push-ebx - ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->payload->alloc-id, 0x34, msg) - # . . push args - 68/push "F - test-allocate-array: sets alloc-id in payload"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->payload->size, 3, msg) - # . . push args - 68/push "F - test-allocate-array: sets array size in payload"/imm32 - 68/push 3/imm32 - ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(*Next-alloc-id, 0x35, msg) - # . . push args - 68/push "F - test-allocate-array: increments Next-alloc-id"/imm32 - 68/push 0x35/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # push *Next-alloc-id - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(ad->curr - expected-payload, 3 + 4 for alloc-id + 4 for array size, msg) - # . . push args - 68/push "F - test-allocate-array: updates allocation descriptor"/imm32 - 68/push 0xb/imm32 - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax - 29/subtract 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # subtract ebx from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # clean up - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x20/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -copy-array: # ad: (addr allocation-descriptor), src: (addr array _T), out: (addr handle array _T) - # . prologue - 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 - 52/push-edx - 56/push-esi - # esi = src - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi - # var size/ecx: int = src->size+4 - 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx - 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx - # allocate(ad, size, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - 51/push-ecx - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # var payload/eax: (addr byte) = out->payload - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax - 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax - # . skip payload->allocid - 05/add-to-eax 4/imm32 - # var max/ecx: (addr byte) = payload + size - 01/add 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # add eax to ecx - # _append-4(payload, max, src, &src->data[src->size]) - # . . push &src->data[src->size] - 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 2/index/edx . 2/r32/edx 4/disp8 . # copy esi+edx+4 to edx - 52/push-edx - # . . push src - 56/push-esi - # . . push max - 51/push-ecx - # . . push payload - 50/push-eax - # . . call - e8/call _append-4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp -$copy-array:end: - # . restore registers - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-copy-array: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var src/esi: (addr array int) = [3, 4, 5] - 68/push 5/imm32 - 68/push 4/imm32 - 68/push 3/imm32 - 68/push 0xc/imm32/size - 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi - # var ad/ecx: allocation-descriptor containing 32 bytes - # . var end/ecx: (addr byte) - 89/<- %ecx 4/r32/esp - # . var start/edx: (addr byte) = end - 32 - 81 5/subop/subtract %esp 0x20/imm32 - 89/<- %edx 4/r32/esp - # . ad = {start, end} - 51/push-ecx - 52/push-edx - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # var expected-payload/ebx = ad->curr - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 3/r32/ebx . . # copy *ecx to ebx - # var h/edx: handle = {0, 0} - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx - # *Next-alloc-id = 0x34 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id - # copy-array(ad, src, h) - # . . push args - 52/push-edx - 56/push-esi - 51/push-ecx - # . . call - e8/call copy-array/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->alloc-id, 0x34, msg) - # . . push args - 68/push "F - test-copy-array: sets alloc-id in handle"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->payload, expected-payload, msg) - # . . push args - 68/push "F - test-copy-array: sets payload in handle"/imm32 - 53/push-ebx - ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(h->payload->alloc-id, 0x34, msg) - # . . push args - 68/push "F - test-copy-array: sets alloc-id in payload"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # var payload/eax: (addr int) = lookup(h) - # . . push args - ff 6/subop/push 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # push *(edx+4) - ff 6/subop/push 0/mod/indirect 2/rm32/edx . . . . . . # push *edx - # . . call - e8/call lookup/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(payload->size, 0xc, msg) - # . . push args - 68/push "F - test-copy-array: sets array size in payload"/imm32 - 68/push 0xc/imm32 - ff 6/subop/push 0/mod/indirect 0/rm32/eax . . . . . . # push *eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(*Next-alloc-id, 0x35, msg) - # . . push args - 68/push "F - test-copy-array: increments Next-alloc-id"/imm32 - 68/push 0x35/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # push *Next-alloc-id - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(ad->curr - expected-payload, 12 + 4 for alloc-id + 4 for size, msg) - # . . push args - 68/push "F - test-copy-array: updates allocation descriptor"/imm32 - 68/push 0x14/imm32 - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax - 29/subtract 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # subtract ebx from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # clean up - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x40/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# Fill a region of memory with zeroes. -zero-out: # start: (addr byte), size: int - # pseudocode: - # curr/esi = start - # i/ecx = 0 - # while true - # if (i >= size) break - # *curr = 0 - # ++curr - # ++i - # - # . prologue - 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 - 52/push-edx - 56/push-esi - # curr/esi = start - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # var i/ecx: int = 0 - 31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx - # edx = size - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx -$zero-out:loop: - # if (i >= size) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 7d/jump-if->= $zero-out:end/disp8 - # *curr = 0 - c6 0/subop/copy-byte 0/mod/direct 6/rm32/esi . . . . . 0/imm8 # copy byte to *esi - # ++curr - 46/increment-esi - # ++i - 41/increment-ecx - eb/jump $zero-out:loop/disp8 -$zero-out:end: - # . restore registers - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-zero-out: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # region/ecx = 34, 35, 36, 37 - 68/push 0x37363534/imm32 - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # zero-out(ecx, 3) - # . . push args - 68/push 3/imm32/size - 51/push-ecx - # . . call - e8/call zero-out/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # first 3 bytes cleared, fourth left alone - # . check-ints-equal(*ecx, 0x37000000, msg) - # . . push args - 68/push "F - test-zero-out"/imm32 - 68/push 0x37000000/imm32 - ff 6/subop/push 0/mod/indirect 1/rm32/ecx . . . . . . # push *ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/121new-stream.subx b/baremetal/121new-stream.subx deleted file mode 100644 index 241f162e..00000000 --- a/baremetal/121new-stream.subx +++ /dev/null @@ -1,127 +0,0 @@ -# Helper to allocate a stream on the heap. - -== 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 - -new-stream: # ad: (addr allocation-descriptor), length: int, elemsize: int, out: (addr handle stream _) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 50/push-eax - 52/push-edx - # var size/edx: int = elemsize*length (clobbering eax) - # . eax = elemsize - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax - # . eax *= length - 31/xor 3/mod/direct 2/rm32/edx . . . 2/r32/edx . . # clear edx - f7 4/subop/multiply 1/mod/*+disp8 5/rm32/ebp . . 0xc/disp8 . # multiply *(ebp+12) into edx:eax - # . if overflow abort - 81 7/subop/compare 3/mod/direct 2/rm32/edx . . . . . 0/imm32 # compare edx - 75/jump-if-!= $new-stream:abort/disp8 - # . edx = elemsize*length - 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx - # var n/eax: int = size + 12 (for read, write and size) - 05/add-to-eax 0xc/imm32 - # allocate(ad, n, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20) - 50/push-eax - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = out->payload - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x14/disp8 . # copy *(ebp+20) to eax - 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax - # skip payload->allocid - 05/add-to-eax 4/imm32 - # eax->size = size - 89/copy 1/mod/*+disp8 0/rm32/eax . . . 2/r32/edx 8/disp8 . # copy edx to *(eax+8) - # clear-stream(eax) - # . . push args - 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 -$new-stream:end: - # . restore registers - 5a/pop-to-edx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$new-stream:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "new-stream: size too large" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -test-new-stream: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var ad/ecx: allocation-descriptor containing 16 bytes - # . var end/ecx: (addr byte) - 89/<- %ecx 4/r32/esp - # . var start/edx: (addr byte) = end - 32 - 81 5/subop/subtract %esp 0x20/imm32 - 89/<- %edx 4/r32/esp - # . ad = {start, end} - 51/push-ecx - 52/push-edx - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # var start/edx = ad->curr - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 2/r32/edx . . # copy *ecx to edx - # var h/ebx: (handle stream byte) - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx - # new-stream(ad, 3, 2, h) - # . . push args - 53/push-ebx - 68/push 2/imm32 - 68/push 3/imm32 - 51/push-ecx - # . . call - e8/call new-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # eax = out->payload - 8b/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy *(ebx+4) to eax - # check-ints-equal(eax, edx, msg) - # . . push args - 68/push "F - test-new-stream: returns current pointer of allocation descriptor"/imm32 - 52/push-edx - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # skip payload->allocid - 05/add-to-eax 4/imm32 - # check-ints-equal(eax->size, 6, msg) - # . . push args - 68/push "F - test-new-stream: sets size correctly"/imm32 - 68/push 6/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . . 8/disp8 # push *(eax+8) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # the rest is delegated to clear-stream() so we won't bother checking it - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x30/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/123slice.subx b/baremetal/123slice.subx deleted file mode 100644 index 01c29290..00000000 --- a/baremetal/123slice.subx +++ /dev/null @@ -1,1069 +0,0 @@ -# new data structure: a slice is an open interval of addresses [start, end) -# that includes 'start' but not 'end' - -== 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 - -slice-empty?: # s: (addr slice) -> result/eax: boolean - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - # ecx = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # if (s->start >= s->end) return true - # . eax = s->start - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax - # . if (eax >= s->end) return true - 3b/compare 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # compare eax with *(ecx+4) - b8/copy-to-eax 1/imm32/true - 73/jump-if-addr>= $slice-empty?:end/disp8 - b8/copy-to-eax 0/imm32/false -$slice-empty?:end: - # . restore registers - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-empty-true: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var slice/ecx: slice = {34, 34} - 68/push 34/imm32/end - 68/push 34/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # slice-empty?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-empty-true"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-empty-false: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var slice/ecx: slice = {32, 34} - 68/push 34/imm32/end - 68/push 32/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # slice-empty?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-empty-false"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-empty-if-start-greater-than-end: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var slice/ecx: slice = {34, 32} - 68/push 32/imm32/end - 68/push 34/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # slice-empty?(slice) - # . . push args - 51/push-ecx - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-empty-if-start-greater-than-end"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -slice-equal?: # s: (addr slice), p: (addr array byte) -> result/eax: boolean - # pseudocode: - # if (p == 0) return (s == 0) - # currs = s->start - # maxs = s->end - # if (maxs - currs != p->size) return false - # currp = p->data - # while currs < maxs - # if (*currs != *currp) return false - # ++currs - # ++currp - # return true - # - # registers: - # currs: edx - # maxs: esi - # currp: ebx - # *currs: eax - # *currp: ecx - # - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - # esi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # var currs/edx: (addr byte) = s->start - 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx - # var maxs/esi: (addr byte) = s->end - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 4/disp8 . # copy *(esi+4) to esi - # var ssize/eax: int = maxs - currs - 89/copy 3/mod/direct 0/rm32/eax . . . 6/r32/esi . . # copy esi to eax - 29/subtract 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # subtract edx from eax - # ebx = p - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 3/r32/ebx 0xc/disp8 . # copy *(ebp+12) to ebx - # if (p != 0) goto next check - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0/imm32 # compare ebx - 75/jump-if-!= $slice-equal?:nonnull-string/disp8 -$slice-equal?:null-string: - # return s->start == s->end - 3d/compare-eax-and 0/imm32 - 74/jump-if-= $slice-equal?:true/disp8 - eb/jump $slice-equal?:false/disp8 -$slice-equal?:nonnull-string: - # if (ssize != p->size) return false - 39/compare 0/mod/indirect 3/rm32/ebx . . . 0/r32/eax . . # compare *ebx and eax - 75/jump-if-!= $slice-equal?:false/disp8 - # var currp/ebx: (addr byte) = p->data - 81 0/subop/add 3/mod/direct 3/rm32/ebx . . . . . 4/imm32 # add to ebx - # var c1/eax: byte = 0 - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - # var c2/ecx: byte = 0 - 31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx -$slice-equal?:loop: - # if (currs >= maxs) return true - 39/compare 3/mod/direct 2/rm32/edx . . . 6/r32/esi . . # compare edx with esi - 73/jump-if-addr>= $slice-equal?:true/disp8 - # c1 = *currp - 8a/copy-byte 0/mod/indirect 3/rm32/ebx . . . 0/r32/AL . . # copy byte at *ebx to AL - # c2 = *currs - 8a/copy-byte 0/mod/indirect 2/rm32/edx . . . 1/r32/CL . . # copy byte at *edx to CL - # if (c1 != c2) return false - 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax and ecx - 75/jump-if-!= $slice-equal?:false/disp8 - # ++currp - 43/increment-ebx - # ++currs - 42/increment-edx - eb/jump $slice-equal?:loop/disp8 -$slice-equal?:false: - b8/copy-to-eax 0/imm32 - eb/jump $slice-equal?:end/disp8 -$slice-equal?:true: - b8/copy-to-eax 1/imm32 -$slice-equal?:end: - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-equal: - # - slice-equal?(slice("Abc"), "Abc") == 1 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-equal?(ecx, "Abc") - # . . push args - 68/push "Abc"/imm32 - 51/push-ecx - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-equal"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-equal-false: - # - slice-equal?(slice("bcd"), "Abc") == 0 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "bcd" - b8/copy-to-eax "bcd"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-equal?(ecx, "Abc") - # . . push args - 68/push "Abc"/imm32 - 51/push-ecx - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-equal-false"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-equal-too-long: - # - slice-equal?(slice("Abcd"), "Abc") == 0 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Abcd" - b8/copy-to-eax "Abcd"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-equal?(ecx, "Abc") - # . . push args - 68/push "Abc"/imm32 - 51/push-ecx - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-equal-too-long"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-equal-too-short: - # - slice-equal?(slice("A"), "Abc") == 0 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "A" - b8/copy-to-eax "A"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-equal?(ecx, "Abc") - # . . push args - 68/push "Abc"/imm32 - 51/push-ecx - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-equal-too-short"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-equal-empty: - # - slice-equal?(slice(""), "Abc") == 0 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var slice/ecx: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-equal?(ecx, "Abc") - # . . push args - 68/push "Abc"/imm32 - 51/push-ecx - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-equal-empty"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-equal-with-empty: - # - slice-equal?(slice("Ab"), "") == 0 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Ab" - b8/copy-to-eax "Ab"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-equal?(ecx, "") - # . . push args - 68/push ""/imm32 - 51/push-ecx - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-equal-with-empty"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-equal-empty-with-empty: - # - slice-equal?(slice(""), "") == 1 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var slice/ecx: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-equal?(ecx, "") - # . . push args - 68/push ""/imm32 - 51/push-ecx - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-equal-empty-with-empty"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-equal-with-null: - # - slice-equal?(slice("Ab"), null) == 0 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Ab" - b8/copy-to-eax "Ab"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-equal?(ecx, 0) - # . . push args - 68/push 0/imm32 - 51/push-ecx - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-equal-with-null"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -slice-starts-with?: # s: (addr slice), head: (addr array byte) -> result/eax: boolean - # pseudocode - # hsize = head->size - # if (hsize > s->end - s->start) return false - # i = 0 - # currs = s->start - # currp = head->data - # while i < hsize - # if (*currs != *currh) return false - # ++i - # ++currs - # ++currh - # return true - # - # registers: - # currs: esi - # currh: edi - # *currs: eax - # *currh: ebx - # i: ecx - # hsize: edx - # - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # esi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # var lens/ecx: int = s->end - s->start - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - 2b/subtract 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # subtract *esi from ecx - # edi = head - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi - # var hsize/edx: int = head->size - 8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx - # if (hsize > lens) return false - 39/compare 3/mod/direct 2/rm32/edx . . . 1/r32/ecx . . # compare edx with ecx - 7f/jump-if-> $slice-starts-with?:false/disp8 - # var currs/esi: (addr byte) = s->start - 8b/subtract 0/mod/indirect 6/rm32/esi . . . 6/r32/esi . . # copy *esi to esi - # var currh/edi: (addr byte) = head->data - 81 0/subop/add 3/mod/direct 7/rm32/edi . . . . . 4/imm32 # add to edi - # var i/ecx: int = 0 - 31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx - # var c1/eax: byte = 0 - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - # var c2/ebx: byte = 0 - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx -$slice-starts-with?:loop: - # if (i >= hsize) return true - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 7d/jump-if->= $slice-starts-with?:true/disp8 - # c1 = *currs - 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 0/r32/AL . . # copy byte at *esi to AL - # c2 = *currh - 8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 3/r32/BL . . # copy byte at *edi to BL - # if (c1 != c2) return false - 39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx - 75/jump-if-!= $slice-starts-with?:false/disp8 - # ++i - 41/increment-ecx - # ++currs - 46/increment-esi - # ++currh - 47/increment-edi - eb/jump $slice-starts-with?:loop/disp8 -$slice-starts-with?:true: - b8/copy-to-eax 1/imm32 - eb/jump $slice-starts-with?:end/disp8 -$slice-starts-with?:false: - b8/copy-to-eax 0/imm32 -$slice-starts-with?:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-starts-with-single-character: - # - slice-starts-with?(slice("Abc"), "A") == 1 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-starts-with?(ecx, "A") - # . . push args - 68/push "A"/imm32 - 51/push-ecx - # . . call - e8/call slice-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-starts-with-single-character"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-starts-with-empty-string: - # - slice-starts-with?(slice("Abc"), "") == 1 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-starts-with?(ecx, "") - # . . push args - 68/push ""/imm32 - 51/push-ecx - # . . call - e8/call slice-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-starts-with-empty-string"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-starts-with-multiple-characters: - # - slice-starts-with?(slice("Abc"), "Ab") == 1 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-starts-with?(ecx, "Ab") - # . . push args - 68/push "Ab"/imm32 - 51/push-ecx - # . . call - e8/call slice-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-starts-with-multiple-characters"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-starts-with-entire-string: - # - slice-starts-with?(slice("Abc"), "Abc") == 1 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-starts-with?(ecx, "Abc") - # . . push args - 68/push "Abc"/imm32 - 51/push-ecx - # . . call - e8/call slice-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-starts-with-entire-string"/imm32 - 68/push 1/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-starts-with-fails: - # - slice-starts-with?(slice("Abc"), "Abd") == 1 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-starts-with?(ecx, "Abd") - # . . push args - 68/push "Abd"/imm32 - 51/push-ecx - # . . call - e8/call slice-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-starts-with-fails"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-slice-starts-with-fails-2: - # - slice-starts-with?(slice("Abc"), "Ac") == 1 - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # eax = slice-starts-with?(ecx, "Ac") - # . . push args - 68/push "Ac"/imm32 - 51/push-ecx - # . . call - e8/call slice-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-slice-starts-with-fails-2"/imm32 - 68/push 0/imm32 - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# write a slice to a stream -# abort if the stream doesn't have enough space -write-slice: # out: (addr stream byte), s: (addr slice) - # . prologue - 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 - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # esi = s - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi - # var curr/ecx: (addr byte) = s->start - 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx - # var max/esi: (addr byte) = s->end - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 4/disp8 . # copy *(esi+4) to esi - # edi = out - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi - # edx = out->size - 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 . # copy *(edi+8) to edx - # ebx = out->write - 8b/copy 0/mod/indirect 7/rm32/edi . . . 3/r32/ebx . . # copy *edi to ebx -$write-slice:loop: - # if (curr >= max) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 6/r32/esi . . # compare ecx with esi - 73/jump-if-addr>= $write-slice:loop-end/disp8 - # if (out->write >= out->size) abort - 39/compare 3/mod/direct 3/rm32/ebx . . . 2/r32/edx . . # compare ebx with edx - 7d/jump-if->= $write-slice:abort/disp8 - # out->data[out->write] = *in - # . AL = *in - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL - # . out->data[out->write] = AL - 88/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/edi 3/index/ebx . 0/r32/AL 0xc/disp8 . # copy AL to *(edi+ebx+12) - # ++out->write - 43/increment-ebx - # ++in - 41/increment-ecx - eb/jump $write-slice:loop/disp8 -$write-slice:loop-end: - # persist out->write - 89/copy 0/mod/indirect 7/rm32/edi . . . 3/r32/ebx . . # copy ebx to *edi -$write-slice:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$write-slice:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "write-slice: out of space" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -test-write-slice: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # write-slice(_test-stream, slice) - # . . push args - 51/push-ecx - 68/push _test-stream/imm32 - # . . call - e8/call write-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "Abc", msg) - # . . push args - 68/push "F - test-write-slice"/imm32 - 68/push "Abc"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# copy a slice into a new (dynamically allocated) string -slice-to-string: # ad: (addr allocation-descriptor), in: (addr slice), out: (addr handle array byte) - # . prologue - 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 - 52/push-edx - 53/push-ebx - 56/push-esi - # esi = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi - # var curr/edx: (addr byte) = in->start - 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx - # var max/ebx: (addr byte) = in->end - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 3/r32/ebx 4/disp8 . # copy *(esi+4) to ebx - # var size/ecx: int = max - curr + 4 # total size of output string (including the initial 'size' field) - 89/copy 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # copy ebx to ecx - 29/subtract 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # subtract edx from ecx - 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx - # allocate(ad, size, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - 51/push-ecx - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = out->payload - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax - 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax - # skip payload->allocid - 05/add-to-eax 4/imm32 - # if (eax == 0) abort - 3d/compare-eax-and 0/imm32 - 74/jump-if-= $slice-to-string:abort/disp8 - # out->size = size-4 - 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax - 81 5/subop/subtract 0/mod/indirect 0/rm32/eax . . . . . 4/imm32 # subtract 4 from *eax - # save out - 50/push-eax -$slice-to-string:initialize: - # eax = _append-4(eax+4, eax+size, curr, max) # clobbering ecx - # . . push args - 53/push-ebx - 52/push-edx - # . . push eax+size (clobbering ecx) - 01/add 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # add eax to ecx - 51/push-ecx - # . . push eax+4 (clobbering eax) - 81 0/subop/add 3/mod/direct 0/rm32/eax . . . . . 4/imm32 # add to eax - 50/push-eax - # . . call - e8/call _append-4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # restore out (assumes _append-4 can't error) - 58/pop-to-eax -$slice-to-string:end: - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$slice-to-string:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "slice-to-string: out of space\n" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -test-slice-to-string: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var ad/edx: allocation-descriptor containing 16 bytes - # . var end/ecx: (addr byte) - 89/<- %ecx 4/r32/esp - 81 5/subop/subtract %esp 0x10/imm32 - # . var start/edx: (addr byte) = end - 0x10 - 89/<- %edx 4/r32/esp - # . ad = {start, end} - 51/push-ecx - 52/push-edx - 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx - # (eax..ecx) = "Abc" - b8/copy-to-eax "Abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # var h/ebx: (handle array byte) - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx - # slice-to-string(ad, slice, h) - # . . push args - 53/push-ebx - 51/push-ecx - 52/push-edx - # . . call - e8/call slice-to-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = h->payload - 8b/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy *(ebx+4) to eax - # skip payload->allocid - 05/add-to-eax 4/imm32 -#? # dump eax {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -#? # . write(2/stderr, eax) -#? # . . push args -#? 50/push-eax -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -#? # }}} - # eax = string-equal?(eax, "Abc") - # . . push args - 68/push "Abc"/imm32 - 50/push-eax - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-slice-to-string"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/124next-token.subx b/baremetal/124next-token.subx deleted file mode 100644 index 6ad00907..00000000 --- a/baremetal/124next-token.subx +++ /dev/null @@ -1,1772 +0,0 @@ -# Some tokenization primitives. - -== 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 - -# extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary) -# on reaching end of file, return an empty interval -next-token-from-slice: # start: (addr byte), end: (addr byte), delimiter: byte, out: (addr slice) - # . prologue - 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 - 52/push-edx - 57/push-edi - # ecx = end - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx - # edx = delimiter - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx - # edi = out - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0x14/disp8 . # copy *(ebp+20) to edi - # eax = skip-chars-matching-in-slice(start, end, delimiter) - # . . push args - 52/push-edx - 51/push-ecx - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call skip-chars-matching-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # out->start = eax - 89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi - # eax = skip-chars-not-matching-in-slice(eax, end, delimiter) - # . . push args - 52/push-edx - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-chars-not-matching-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # out->end = eax - 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4) - # . restore registers - 5f/pop-to-edi - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-token-from-slice: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = " ab" - b8/copy-to-eax " ab"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var out/edi: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi - # next-token-from-slice(eax, ecx, 0x20/space, out) - # . . push args - 57/push-edi - 68/push 0x20/imm32 - 51/push-ecx - 50/push-eax - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # out->start should be at the 'a' - # . check-ints-equal(out->start - in->start, 2, msg) - # . . push args - 68/push "F - test-next-token-from-slice: start"/imm32 - 68/push 2/imm32 - # . . push out->start - in->start - 8b/copy 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # copy *edi to ecx - 2b/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # out->end should be after the 'b' - # check-ints-equal(out->end - in->start, 4, msg) - # . . push args - 68/push "F - test-next-token-from-slice: end"/imm32 - 68/push 4/imm32 - # . . push out->end - in->start - 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx - 2b/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-token-from-slice-Eof: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # var out/edi: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi - # next-token-from-slice(0, 0, 0x20/space, out) - # . . push args - 57/push-edi - 68/push 0x20/imm32 - 68/push 0/imm32 - 68/push 0/imm32 - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # out should be empty - # . check-ints-equal(out->end - out->start, 0, msg) - # . . push args - 68/push "F - test-next-token-from-slice-Eof"/imm32 - 68/push 0/imm32 - # . . push out->start - in->start - 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx - 2b/subtract 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # subtract *edi from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-token-from-slice-nothing: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # (eax..ecx) = " " - b8/copy-to-eax " "/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # var out/edi: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi - # next-token-from-slice(in, 0x20/space, out) - # . . push args - 57/push-edi - 68/push 0x20/imm32 - 51/push-ecx - 50/push-eax - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # out should be empty - # . check-ints-equal(out->end - out->start, 0, msg) - # . . push args - 68/push "F - test-next-token-from-slice-Eof"/imm32 - 68/push 0/imm32 - # . . push out->start - in->start - 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx - 2b/subtract 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # subtract *edi from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -skip-chars-matching: # in: (addr stream byte), delimiter: byte - # . prologue - 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 - 52/push-edx - 53/push-ebx - 56/push-esi - # esi = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # ecx = in->read - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - # ebx = in->write - 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx - # edx = delimiter - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx -$skip-chars-matching:loop: - # if (in->read >= in->write) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx - 7d/jump-if->= $skip-chars-matching:end/disp8 - # eax = in->data[in->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 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL - # if (eax != delimiter) break - 39/compare 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # compare eax and edx - 75/jump-if-!= $skip-chars-matching:end/disp8 - # ++in->read - 41/increment-ecx - eb/jump $skip-chars-matching:loop/disp8 -$skip-chars-matching:end: - # persist in->read - 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4) - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-chars-matching: - # 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 - # write(_test-stream, " ab") - # . . push args - 68/push " ab"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # skip-chars-matching(_test-stream, 0x20/space) - # . . push args - 68/push 0x20/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call skip-chars-matching/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(_test-stream->read, 2, msg) - # . . push args - 68/push "F - test-skip-chars-matching"/imm32 - 68/push 2/imm32 - # . . push *_test-stream->read - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . 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 - -test-skip-chars-matching-none: - # 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 - # write(_test-stream, "ab") - # . . push args - 68/push "ab"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # skip-chars-matching(_test-stream, 0x20/space) - # . . push args - 68/push 0x20/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call skip-chars-matching/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(_test-stream->read, 0, msg) - # . . push args - 68/push "F - test-skip-chars-matching-none"/imm32 - 68/push 0/imm32 - # . . push *_test-stream->read - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . 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 - -skip-chars-matching-whitespace: # in: (addr stream byte) - # . prologue - 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 - 53/push-ebx - 56/push-esi - # esi = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # ecx = in->read - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - # ebx = in->write - 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx -$skip-chars-matching-whitespace:loop: - # if (in->read >= in->write) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx - 7d/jump-if->= $skip-chars-matching-whitespace:end/disp8 - # eax = in->data[in->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 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL - # if (eax == ' ') goto body - 3d/compare-eax-and 0x20/imm32/space - 74/jump-if-= $skip-chars-matching-whitespace:body/disp8 - # if (eax == '\n') goto body - 3d/compare-eax-and 0x0a/imm32/newline - 74/jump-if-= $skip-chars-matching-whitespace:body/disp8 - # if (eax == '\t') goto body - 3d/compare-eax-and 0x09/imm32/tab - 74/jump-if-= $skip-chars-matching-whitespace:body/disp8 - # if (eax != '\r') break - 3d/compare-eax-and 0x0d/imm32/cr - 75/jump-if-!= $skip-chars-matching-whitespace:end/disp8 -$skip-chars-matching-whitespace:body: - # ++in->read - 41/increment-ecx - eb/jump $skip-chars-matching-whitespace:loop/disp8 -$skip-chars-matching-whitespace:end: - # persist in->read - 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4) - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-chars-matching-whitespace: - # 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 - # write(_test-stream, " \nab") - # . . push args - 68/push " \nab"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # skip-chars-matching-whitespace(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-chars-matching-whitespace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(_test-stream->read, 2, msg) - # . . push args - 68/push "F - test-skip-chars-matching-whitespace"/imm32 - 68/push 2/imm32 - # . . push *_test-stream->read - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . 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 - -# minor fork of 'skip-chars-matching' -skip-chars-not-matching: # in: (addr stream byte), delimiter: byte - # . prologue - 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 - 52/push-edx - 53/push-ebx - 56/push-esi - # esi = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # ecx = in->read - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - # ebx = in->write - 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx - # edx = delimiter - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx -$skip-chars-not-matching:loop: - # if (in->read >= in->write) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx - 7d/jump-if->= $skip-chars-not-matching:end/disp8 - # eax = in->data[in->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 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL - # if (eax == delimiter) break - 39/compare 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # compare eax and edx - 74/jump-if-= $skip-chars-not-matching:end/disp8 - # ++in->read - 41/increment-ecx - eb/jump $skip-chars-not-matching:loop/disp8 -$skip-chars-not-matching:end: - # persist in->read - 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4) - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-chars-not-matching: - # 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 - # write(_test-stream, "ab ") - # . . push args - 68/push "ab "/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # skip-chars-not-matching(_test-stream, 0x20/space) - # . . push args - 68/push 0x20/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call skip-chars-not-matching/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(_test-stream->read, 2, msg) - # . . push args - 68/push "F - test-skip-chars-not-matching"/imm32 - 68/push 2/imm32 - # . . push *_test-stream->read - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . 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 - -test-skip-chars-not-matching-none: - # 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 - # write(_test-stream, " ab") - # . . push args - 68/push " ab"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # skip-chars-not-matching(_test-stream, 0x20/space) - # . . push args - 68/push 0x20/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call skip-chars-not-matching/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(_test-stream->read, 0, msg) - # . . push args - 68/push "F - test-skip-chars-not-matching-none"/imm32 - 68/push 0/imm32 - # . . push *_test-stream->read - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . 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 - -test-skip-chars-not-matching-all: - # 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 - # write(_test-stream, "ab") - # . . push args - 68/push "ab"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # skip-chars-not-matching(_test-stream, 0x20/space) - # . . push args - 68/push 0x20/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call skip-chars-not-matching/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(_test-stream->read, 2, msg) - # . . push args - 68/push "F - test-skip-chars-not-matching-all"/imm32 - 68/push 2/imm32 - # . . push *_test-stream->read - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . 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 - -skip-chars-not-matching-whitespace: # in: (addr stream byte) - # . prologue - 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 - 53/push-ebx - 56/push-esi - # esi = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # ecx = in->read - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - # ebx = in->write - 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx -$skip-chars-not-matching-whitespace:loop: - # if (in->read >= in->write) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx - 7d/jump-if->= $skip-chars-not-matching-whitespace:end/disp8 - # eax = in->data[in->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 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL - # if (eax == ' ') break - 3d/compare-eax-and 0x20/imm32/space - 74/jump-if-= $skip-chars-not-matching-whitespace:end/disp8 - # if (eax == '\n') break - 3d/compare-eax-and 0x0a/imm32/newline - 74/jump-if-= $skip-chars-not-matching-whitespace:end/disp8 - # if (eax == '\t') break - 3d/compare-eax-and 0x09/imm32/tab - 74/jump-if-= $skip-chars-not-matching-whitespace:end/disp8 - # if (eax == '\r') break - 3d/compare-eax-and 0x0d/imm32/cr - 74/jump-if-= $skip-chars-not-matching-whitespace:end/disp8 - # ++in->read - 41/increment-ecx - eb/jump $skip-chars-not-matching-whitespace:loop/disp8 -$skip-chars-not-matching-whitespace:end: - # persist in->read - 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4) - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-chars-not-matching-whitespace: - # 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 - # write(_test-stream, "ab\n") - # . . push args - 68/push "ab\n"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # skip-chars-not-matching-whitespace(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-chars-not-matching-whitespace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(_test-stream->read, 2, msg) - # . . push args - 68/push "F - test-skip-chars-not-matching-whitespace"/imm32 - 68/push 2/imm32 - # . . push *_test-stream->read - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . 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 - -skip-chars-matching-in-slice: # curr: (addr byte), end: (addr byte), delimiter: byte -> curr/eax: (addr byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - # eax = curr - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - # ecx = end - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx - # edx = delimiter - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx - # var c/ebx: byte = 0 - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx -$skip-chars-matching-in-slice:loop: - # if (curr >= end) break - 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx - 73/jump-if-addr>= $skip-chars-matching-in-slice:end/disp8 - # c = *curr - 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 3/r32/BL . . # copy byte at *eax to BL - # if (c != delimiter) break - 39/compare 3/mod/direct 3/rm32/ebx . . . 2/r32/edx . . # compare ebx and edx - 75/jump-if-!= $skip-chars-matching-in-slice:end/disp8 - # ++curr - 40/increment-eax - eb/jump $skip-chars-matching-in-slice:loop/disp8 -$skip-chars-matching-in-slice:end: - # . restore registers - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-chars-matching-in-slice: - # (eax..ecx) = " ab" - b8/copy-to-eax " ab"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-chars-matching-in-slice(eax, ecx, 0x20/space) - # . . push args - 68/push 0x20/imm32/space - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-chars-matching-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(ecx-eax, 2, msg) - # . . push args - 68/push "F - test-skip-chars-matching-in-slice"/imm32 - 68/push 2/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . 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 - -test-skip-chars-matching-in-slice-none: - # (eax..ecx) = "ab" - b8/copy-to-eax "ab"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-chars-matching-in-slice(eax, ecx, 0x20/space) - # . . push args - 68/push 0x20/imm32/space - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-chars-matching-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(ecx-eax, 2, msg) - # . . push args - 68/push "F - test-skip-chars-matching-in-slice-none"/imm32 - 68/push 2/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . 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 - -skip-chars-matching-whitespace-in-slice: # curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 53/push-ebx - # eax = curr - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - # ecx = end - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx - # var c/ebx: byte = 0 - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx -$skip-chars-matching-whitespace-in-slice:loop: - # if (curr >= end) break - 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx - 0f 83/jump-if-addr>= $skip-chars-matching-in-slice:end/disp32 - # c = *curr - 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 3/r32/BL . . # copy byte at *eax to BL - # if (c == ' ') goto body - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x20/imm32/space # compare ebx - 74/jump-if-= $skip-chars-matching-whitespace-in-slice:body/disp8 - # if (c == '\n') goto body - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x0a/imm32/newline # compare ebx - 74/jump-if-= $skip-chars-matching-whitespace-in-slice:body/disp8 - # if (c == '\t') goto body - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x09/imm32/tab # compare ebx - 74/jump-if-= $skip-chars-matching-whitespace-in-slice:body/disp8 - # if (c != '\r') break - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x0d/imm32/cr # compare ebx - 75/jump-if-!= $skip-chars-matching-whitespace-in-slice:end/disp8 -$skip-chars-matching-whitespace-in-slice:body: - # ++curr - 40/increment-eax - eb/jump $skip-chars-matching-whitespace-in-slice:loop/disp8 -$skip-chars-matching-whitespace-in-slice:end: - # . restore registers - 5b/pop-to-ebx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-chars-matching-whitespace-in-slice: - # (eax..ecx) = " \nab" - b8/copy-to-eax " \nab"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-chars-matching-whitespace-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-chars-matching-whitespace-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 2, msg) - # . . push args - 68/push "F - test-skip-chars-matching-whitespace-in-slice"/imm32 - 68/push 2/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . 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 - -# minor fork of 'skip-chars-matching-in-slice' -skip-chars-not-matching-in-slice: # curr: (addr byte), end: (addr byte), delimiter: byte -> curr/eax: (addr byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - # eax = curr - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - # ecx = end - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx - # edx = delimiter - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx - # var c/ebx: byte = 0 - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx -$skip-chars-not-matching-in-slice:loop: - # if (curr >= end) break - 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx - 73/jump-if-addr>= $skip-chars-not-matching-in-slice:end/disp8 - # c = *curr - 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 3/r32/BL . . # copy byte at *eax to BL - # if (c == delimiter) break - 39/compare 3/mod/direct 3/rm32/ebx . . . 2/r32/edx . . # compare ebx and edx - 74/jump-if-= $skip-chars-not-matching-in-slice:end/disp8 - # ++curr - 40/increment-eax - eb/jump $skip-chars-not-matching-in-slice:loop/disp8 -$skip-chars-not-matching-in-slice:end: - # . restore registers - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-chars-not-matching-in-slice: - # (eax..ecx) = "ab " - b8/copy-to-eax "ab "/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space) - # . . push args - 68/push 0x20/imm32/space - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-chars-not-matching-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(ecx-eax, 1, msg) - # . . push args - 68/push "F - test-skip-chars-not-matching-in-slice"/imm32 - 68/push 1/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . 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 - -test-skip-chars-not-matching-in-slice-none: - # (eax..ecx) = " ab" - b8/copy-to-eax " ab"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space) - # . . push args - 68/push 0x20/imm32/space - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-chars-not-matching-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(ecx-eax, 3, msg) - # . . push args - 68/push "F - test-skip-chars-not-matching-in-slice-none"/imm32 - 68/push 3/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . 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 - -test-skip-chars-not-matching-in-slice-all: - # (eax..ecx) = "ab" - b8/copy-to-eax "ab"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space) - # . . push args - 68/push 0x20/imm32/space - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-chars-not-matching-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(ecx-eax, 0, msg) - # . . push args - 68/push "F - test-skip-chars-not-matching-in-slice-all"/imm32 - 68/push 0/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . 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 - -skip-chars-not-matching-whitespace-in-slice: # curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 53/push-ebx - # eax = curr - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax - # ecx = end - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx - # var c/ebx: byte = 0 - 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx -$skip-chars-not-matching-whitespace-in-slice:loop: - # if (curr >= end) break - 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx - 0f 83/jump-if-addr>= $skip-chars-not-matching-in-slice:end/disp32 - # c = *curr - 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 3/r32/BL . . # copy byte at *eax to BL - # if (c == ' ') break - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x20/imm32/space # compare ebx - 74/jump-if-= $skip-chars-not-matching-whitespace-in-slice:end/disp8 - # if (c == '\n') break - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x0a/imm32/newline # compare ebx - 74/jump-if-= $skip-chars-not-matching-whitespace-in-slice:end/disp8 - # if (c == '\t') break - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x09/imm32/tab # compare ebx - 74/jump-if-= $skip-chars-not-matching-whitespace-in-slice:end/disp8 - # if (c == '\r') break - 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x0d/imm32/cr # compare ebx - 74/jump-if-= $skip-chars-not-matching-whitespace-in-slice:end/disp8 - # ++curr - 40/increment-eax - eb/jump $skip-chars-not-matching-whitespace-in-slice:loop/disp8 -$skip-chars-not-matching-whitespace-in-slice:end: - # . restore registers - 5b/pop-to-ebx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-chars-not-matching-whitespace-in-slice: - # (eax..ecx) = "ab\n" - b8/copy-to-eax "ab\n"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-chars-not-matching-whitespace-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-chars-not-matching-whitespace-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 1, msg) - # . . push args - 68/push "F - test-skip-chars-not-matching-whitespace-in-slice"/imm32 - 68/push 1/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . 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 - -# update line->read to end of string literal surrounded by double quotes -# line->read must start out at a double-quote -skip-string: # line: (addr stream byte) - # . prologue - 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 - 52/push-edx - # ecx = line - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # eax = skip-string-in-slice(&line->data[line->read], &line->data[line->write]) - # . . push &line->data[line->write] - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . 2/r32/edx 8/disp8 . # copy *(ecx+8) to edx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx 0xc/disp8 . # copy ecx+edx+12 to edx - 52/push-edx - # . . push &line->data[line->read] - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx 0xc/disp8 . # copy ecx+edx+12 to edx - 52/push-edx - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # line->read = eax - line->data - 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax - 2d/subtract-from-eax 0xc/imm32 - 89/copy 1/mod/*+disp8 1/rm32/ecx . . 0/r32/eax 4/disp8 . # copy eax to *(ecx+4) -$skip-string:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-string: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # . write(_test-stream, "\"abc\" def") - # . indices: 0123 45 - # . . push args - 68/push "\"abc\" def"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # precondition: line->read == 0 - # . . push args - 68/push "F - test-skip-string/precondition"/imm32 - 68/push 0/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # skip-string(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(line->read, 5, msg) - # . . push args - 68/push "F - test-skip-string"/imm32 - 68/push 5/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-string-ignores-spaces: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # . write(_test-stream, "\"a b\"/yz") - # . indices: 0123 45 - # . . push args - 68/push "\"a b\"/yz"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # precondition: line->read == 0 - # . . push args - 68/push "F - test-skip-string-ignores-spaces/precondition"/imm32 - 68/push 0/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # skip-string(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(line->read, 5, msg) - # . . push args - 68/push "F - test-skip-string-ignores-spaces"/imm32 - 68/push 5/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-string-ignores-escapes: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # . write(_test-stream, "\"a\\\"b\"/yz") - # . indices: 01 2 34 56 - # . . push args - 68/push "\"a\\\"b\"/yz"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # precondition: line->read == 0 - # . . push args - 68/push "F - test-skip-string-ignores-escapes/precondition"/imm32 - 68/push 0/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # skip-string(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(line->read, 6, msg) - # . . push args - 68/push "F - test-skip-string-ignores-escapes"/imm32 - 68/push 6/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-string-works-from-mid-stream: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # . write(_test-stream, "0 \"a\\\"b\"/yz") - # . indices: 01 2 34 56 - # . . push args - 68/push "0 \"a\\\"b\"/yz"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # precondition: line->read == 2 - b8/copy-to-eax _test-stream/imm32 - c7 0/subop/copy 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 2/imm32 # copy to *(eax+4) - # skip-string(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(line->read, 8, msg) - # . . push args - 68/push "F - test-skip-string-works-from-mid-stream"/imm32 - 68/push 8/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -skip-string-in-slice: # curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - # ecx = curr - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # edx = end - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx - # var c/eax: byte = 0 - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - # skip initial dquote - 41/increment-ecx -$skip-string-in-slice:loop: - # if (curr >= end) return curr - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 73/jump-if-addr>= $skip-string-in-slice:return-curr/disp8 - # c = *curr - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL -$skip-string-in-slice:dquote: - # if (c == '"') break - 3d/compare-eax-and 0x22/imm32/double-quote - 74/jump-if-= $skip-string-in-slice:break/disp8 -$skip-string-in-slice:check-for-escape: - # if (c == '\') escape next char - 3d/compare-eax-and 0x5c/imm32/backslash - 75/jump-if-!= $skip-string-in-slice:continue/disp8 -$skip-string-in-slice:escape: - 41/increment-ecx -$skip-string-in-slice:continue: - # ++curr - 41/increment-ecx - eb/jump $skip-string-in-slice:loop/disp8 -$skip-string-in-slice:break: - # skip final dquote - 41/increment-ecx -$skip-string-in-slice:return-curr: - # return curr - 89/copy 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to eax -$skip-string-in-slice:end: - # . restore registers - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-string-in-slice: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # setup: (eax..ecx) = "\"abc\" def" - b8/copy-to-eax "\"abc\" def"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-string-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 4, msg) # number of chars remaining after the string literal - # . . push args - 68/push "F - test-skip-string-in-slice"/imm32 - 68/push 4/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-string-in-slice-ignores-spaces: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # setup: (eax..ecx) = "\"a b\"/yz" - b8/copy-to-eax "\"a b\"/yz"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-string-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 3, msg) # number of chars remaining after the string literal - # . . push args - 68/push "F - test-skip-string-in-slice-ignores-spaces"/imm32 - 68/push 3/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-string-in-slice-ignores-escapes: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # setup: (eax..ecx) = "\"a\\\"b\"/yz" - b8/copy-to-eax "\"a\\\"b\"/yz"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-string-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 3, msg) # number of chars remaining after the string literal - # . . push args - 68/push "F - test-skip-string-in-slice-ignores-escapes"/imm32 - 68/push 3/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-string-in-slice-stops-at-end: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # setup: (eax..ecx) = "\"abc" # unbalanced dquote - b8/copy-to-eax "\"abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-string-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 0, msg) # skipped to end of slice - # . . push args - 68/push "F - test-skip-string-in-slice-stops-at-end"/imm32 - 68/push 0/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# update line->read to ')' -# line->read ends at ')' -skip-until-close-paren: # line: (addr stream byte) - # . prologue - 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 - 52/push-edx - # ecx = line - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # eax = skip-until-close-paren-in-slice(&line->data[line->read], &line->data[line->write]) - # . . push &line->data[line->write] - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . 2/r32/edx 8/disp8 . # copy *(ecx+8) to edx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx 0xc/disp8 . # copy ecx+edx+12 to edx - 52/push-edx - # . . push &line->data[line->read] - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx 0xc/disp8 . # copy ecx+edx+12 to edx - 52/push-edx - # . . call - e8/call skip-until-close-paren-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # line->read = eax - line->data - 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax - 2d/subtract-from-eax 0xc/imm32 - 89/copy 1/mod/*+disp8 1/rm32/ecx . . 0/r32/eax 4/disp8 . # copy eax to *(ecx+4) -$skip-until-close-paren:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-until-close-paren: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # . write(_test-stream, "*(abc) def") - # . indices: 0123 45 - # . . push args - 68/push "*(abc) def"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # precondition: line->read == 0 - # . . push args - 68/push "F - test-skip-until-close-paren/precondition"/imm32 - 68/push 0/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # skip-until-close-paren(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-until-close-paren/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(line->read, 5, msg) - # . . push args - 68/push "F - test-skip-until-close-paren"/imm32 - 68/push 5/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-until-close-paren-ignores-spaces: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # . write(_test-stream, "*(a b)/yz") - # . . push args - 68/push "*(a b)/yz"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # precondition: line->read == 0 - # . . push args - 68/push "F - test-skip-until-close-paren-ignores-spaces/precondition"/imm32 - 68/push 0/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # skip-until-close-paren(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-until-close-paren/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(line->read, 5, msg) - # . . push args - 68/push "F - test-skip-until-close-paren-ignores-spaces"/imm32 - 68/push 5/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-until-close-paren-works-from-mid-stream: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # . write(_test-stream, "0 *(a b)/yz") - # . . push args - 68/push "0 *(a b)/yz"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # precondition: _test-stream->read == 2 - b8/copy-to-eax _test-stream/imm32 - c7 0/subop/copy 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 2/imm32 # copy to *(eax+4) - # skip-until-close-paren(_test-stream) - # . . push args - 68/push _test-stream/imm32 - # . . call - e8/call skip-until-close-paren/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(_test-stream->read, 7, msg) - # . . push args - 68/push "F - test-skip-until-close-paren-works-from-mid-stream"/imm32 - 68/push 7/imm32 - b8/copy-to-eax _test-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -skip-until-close-paren-in-slice: # curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte) - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - 52/push-edx - # ecx = curr - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # edx = end - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx - # var c/eax: byte = 0 - 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax - # skip initial dquote - 41/increment-ecx -$skip-until-close-paren-in-slice:loop: - # if (curr >= end) break - 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx - 73/jump-if-addr>= $skip-until-close-paren-in-slice:break/disp8 - # c = *curr - 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL -$skip-until-close-paren-in-slice:check-close: - # if (c == ')') break - 3d/compare-eax-and 0x29/imm32/close-paren - 74/jump-if-= $skip-until-close-paren-in-slice:break/disp8 - # ++curr - 41/increment-ecx - eb/jump $skip-until-close-paren-in-slice:loop/disp8 -$skip-until-close-paren-in-slice:break: - # return curr - 89/copy 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to eax -$skip-until-close-paren-in-slice:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-until-close-paren-in-slice: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # setup: (eax..ecx) = "*(abc) def" - b8/copy-to-eax "*(abc) def"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-until-close-paren-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-until-close-paren-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 5, msg) # eax is at the ')' - # . . push args - 68/push "F - test-skip-until-close-paren-in-slice"/imm32 - 68/push 5/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-until-close-paren-in-slice-ignores-spaces: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # setup: (eax..ecx) = "*(a b)/yz" - b8/copy-to-eax "*(a b)/yz"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-until-close-paren-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-until-close-paren-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 4, msg) # eax is at the ')' - # . . push args - 68/push "F - test-skip-until-close-paren-in-slice-ignores-spaces"/imm32 - 68/push 4/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-skip-until-close-paren-in-slice-stops-at-end: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # setup: (eax..ecx) = "*(abc" # unbalanced dquote - b8/copy-to-eax "*(abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx - 05/add-to-eax 4/imm32 - # eax = skip-until-close-paren-in-slice(eax, ecx) - # . . push args - 51/push-ecx - 50/push-eax - # . . call - e8/call skip-until-close-paren-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(ecx-eax, 0, msg) # skipped to end of slice - # . . push args - 68/push "F - test-skip-until-close-paren-in-slice-stops-at-end"/imm32 - 68/push 0/imm32 - # . . push ecx-eax - 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx - 51/push-ecx - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/126write-int-decimal.subx b/baremetal/126write-int-decimal.subx deleted file mode 100644 index 9f148248..00000000 --- a/baremetal/126write-int-decimal.subx +++ /dev/null @@ -1,428 +0,0 @@ -# Helper to print an int32 in decimal. - -== 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 - -write-int32-decimal: # out: (addr stream byte), n: int - # works by generating characters from lowest to highest and pushing them - # to the stack, before popping them one by one into the stream - # - # pseudocode: - # push sentinel - # eax = abs(n) - # while true - # sign-extend eax into edx - # eax, edx = eax/10, eax%10 - # edx += '0' - # push edx - # if (eax == 0) break - # if n < 0 - # push '-' - # w = out->write - # curr = &out->data[out->write] - # max = &out->data[out->size] - # while true - # pop into eax - # if (eax == sentinel) break - # if (curr >= max) abort - # *curr = AL - # ++curr - # ++w - # out->write = w - # (based on K&R itoa: https://en.wikibooks.org/wiki/C_Programming/stdlib.h/itoa) - # (this pseudocode contains registers because operations like division - # require specific registers in x86) - # - # . prologue - 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 - 52/push-edx - 53/push-ebx - 57/push-edi - # const ten/ecx = 10 - b9/copy-to-ecx 0xa/imm32 - # push sentinel - 68/push 0/imm32/sentinel - # var eax: int = abs(n) - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax - 3d/compare-eax-with 0/imm32 - 7d/jump-if->= $write-int32-decimal:read-loop/disp8 -$write-int32-decimal:negative: - f7 3/subop/negate 3/mod/direct 0/rm32/eax . . . . . . # negate eax -$write-int32-decimal:read-loop: - # eax, edx = eax / 10, eax % 10 - 99/sign-extend-eax-into-edx - f7 7/subop/idiv 3/mod/direct 1/rm32/ecx . . . . . . # divide edx:eax by ecx, storing quotient in eax and remainder in edx - # edx += '0' - 81 0/subop/add 3/mod/direct 2/rm32/edx . . . . . 0x30/imm32 # add to edx - # push edx - 52/push-edx - # if (eax == 0) break - 3d/compare-eax-and 0/imm32 - 7f/jump-if-> $write-int32-decimal:read-loop/disp8 -$write-int32-decimal:read-break: - # if (n < 0) push('-') - 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 0/imm32 # compare *(ebp+12) - 7d/jump-if->= $write-int32-decimal:write/disp8 -$write-int32-decimal:push-negative: - 68/push 0x2d/imm32/- -$write-int32-decimal:write: - # edi = out - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi - # var w/edx: int = out->write - 8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx - # var curr/ecx: (addr byte) = &out->data[out->write] - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 2/index/edx . 1/r32/ecx 0xc/disp8 . # copy ebx+edx+12 to ecx - # var max/ebx: (addr byte) = &out->data[out->size] - 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 3/r32/ebx 8/disp8 . # copy *(edi+8) to ebx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 3/index/ebx . 3/r32/ebx 0xc/disp8 . # copy edi+ebx+12 to ebx -$write-int32-decimal:write-loop: - # pop into eax - 58/pop-to-eax - # if (eax == sentinel) break - 3d/compare-eax-and 0/imm32/sentinel - 74/jump-if-= $write-int32-decimal:write-break/disp8 - # if (curr >= max) abort - 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx - 73/jump-if-addr>= $write-int32-decimal:abort/disp8 -$write-int32-decimal:write-char: - # *curr = AL - 88/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy AL to byte at *ecx - # ++curr - 41/increment-ecx - # ++w - 42/increment-edx - eb/jump $write-int32-decimal:write-loop/disp8 -$write-int32-decimal:write-break: - # out->write = w - 89/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy edx to *edi -$write-int32-decimal:end: - # . restore registers - 5f/pop-to-edi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$write-int32-decimal:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "write-int32-decimal: stream out of space" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -test-write-int32-decimal: - # - check that a single-digit number converts correctly - # 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 - # write-int32-decimal(_test-stream, 9) - # . . push args - 68/push 9/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-int32-decimal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "9", msg) - # . . push args - 68/push "F - test-write-int32-decimal"/imm32 - 68/push "9"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . end - c3/return - -test-write-int32-decimal-zero: - # - check that 0 converts correctly - # 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 - # write-int32-decimal(_test-stream, 0) - # . . push args - 68/push 0/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-int32-decimal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "0", msg) - # . . push args - 68/push "F - test-write-int32-decimal-zero"/imm32 - 68/push "0"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . end - c3/return - -test-write-int32-decimal-multiple-digits: - # - check that a multi-digit number converts correctly - # 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 - # write-int32-decimal(_test-stream, 10) - # . . push args - 68/push 0xa/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-int32-decimal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "10", msg) - # . . push args - 68/push "F - test-write-int32-decimal-multiple-digits"/imm32 - 68/push "10"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . end - c3/return - -test-write-int32-decimal-negative: - # - check that a negative single-digit number converts correctly - # 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 - # write-int32-decimal(_test-stream, -9) - # . . push args - 68/push -9/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-int32-decimal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -#? # dump _test-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -#? # . write-stream(2/stderr, _test-stream) -#? # . . push args -#? 68/push _test-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp -#? # }}} - # check-stream-equal(_test-stream, "-9", msg) - # . . push args - 68/push "F - test-write-int32-decimal-negative"/imm32 - 68/push "-9"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . end - c3/return - -test-write-int32-decimal-negative-multiple-digits: - # - check that a multi-digit number converts correctly - # 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 - # write-int32-decimal(_test-stream, -10) - # . . push args - 68/push -0xa/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write-int32-decimal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-stream-equal(_test-stream, "-10", msg) - # . . push args - 68/push "F - test-write-int32-decimal-negative-multiple-digits"/imm32 - 68/push "-10"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . end - c3/return - -is-decimal-digit?: # c: grapheme -> result/eax: boolean - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # . save registers - 51/push-ecx - # ecx = c - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # result = false - b8/copy-to-eax 0/imm32/false - # return false if c < '0' - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x30/imm32 # compare ecx - 7c/jump-if-< $is-decimal-digit?:end/disp8 - # return (c <= '9') - 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x39/imm32 # compare ecx - 7f/jump-if-> $is-decimal-digit?:end/disp8 -$is-decimal-digit?:true: - b8/copy-to-eax 1/imm32/true -$is-decimal-digit?:end: - # . restore registers - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-is-decimal-digit-below-0: - # eax = is-decimal-digit?(0x2f) - # . . push args - 68/push 0x2f/imm32 - # . . call - e8/call is-decimal-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-is-decimal-digit-below-0"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-is-decimal-digit-0-to-9: - # eax = is-decimal-digit?(0x30) - # . . push args - 68/push 0x30/imm32 - # . . call - e8/call is-decimal-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-is-decimal-digit-at-0"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # eax = is-decimal-digit?(0x39) - # . . push args - 68/push 0x39/imm32 - # . . call - e8/call is-decimal-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 1, msg) - # . . push args - 68/push "F - test-is-decimal-digit-at-9"/imm32 - 68/push 1/imm32/true - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -test-is-decimal-digit-above-9: - # eax = is-decimal-digit?(0x3a) - # . . push args - 68/push 0x3a/imm32 - # . . call - e8/call is-decimal-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # check-ints-equal(eax, 0, msg) - # . . push args - 68/push "F - test-is-decimal-digit-above-9"/imm32 - 68/push 0/imm32/false - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - c3/return - -to-decimal-digit: # in: grapheme -> out/eax: int - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # eax = in - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax -$to-decimal-digit:check0: - # if (eax < '0') goto abort - 3d/compare-eax-with 0x30/imm32/0 - 7c/jump-if-< $to-decimal-digit:abort/disp8 -$to-decimal-digit:check1: - # if (eax > '9') goto abort - 3d/compare-eax-with 0x39/imm32/f - 7f/jump-if-> $to-decimal-digit:abort/disp8 -$to-decimal-digit:digit: - # return eax - '0' - 2d/subtract-from-eax 0x30/imm32/0 -$to-decimal-digit:end: - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$to-decimal-digit:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "to-decimal-digit: not a digit character" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -# . . vim:nowrap:textwidth=0 diff --git a/baremetal/127next-word.subx b/baremetal/127next-word.subx deleted file mode 100644 index 5af326d4..00000000 --- a/baremetal/127next-word.subx +++ /dev/null @@ -1,362 +0,0 @@ -# Tokenize by whitespace. - -== 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 - -# (re)compute the bounds of the next word in the line (surrounded by whitespace, -# treating '#' comments as a single word) -# return empty string on reaching end of file -next-word: # line: (addr stream byte), out: (addr slice) - # . prologue - 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 - 56/push-esi - 57/push-edi - # esi = line - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # edi = out - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi - # skip-chars-matching-whitespace(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call skip-chars-matching-whitespace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp -$next-word:check0: - # if (line->read >= line->write) clear out and return - # . eax = line->read - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy *(esi+4) to eax - # . if (eax < line->write) goto next check - 3b/compare 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # compare eax with *esi - 7c/jump-if-< $next-word:check-for-comment/disp8 - # . return out - c7 0/subop/copy 0/mod/direct 7/rm32/edi . . . . . 0/imm32 # copy to *edi - c7 0/subop/copy 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 0/imm32 # copy to *(edi+4) - eb/jump $next-word:end/disp8 -$next-word:check-for-comment: - # out->start = &line->data[line->read] - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/eax 0xc/disp8 . # copy esi+ecx+12 to eax - 89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi - # if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return - # . eax = line->data[line->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 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL - # . compare - 3d/compare-eax-and 0x23/imm32/pound - 75/jump-if-!= $next-word:regular-word/disp8 -$next-word:comment: - # . out->end = &line->data[line->write] - 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 0/index/eax . 0/r32/eax 0xc/disp8 . # copy esi+eax+12 to eax - 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4) - # . line->read = line->write - 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax - 89/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy eax to *(esi+4) - # . return - eb/jump $next-word:end/disp8 -$next-word:regular-word: - # otherwise skip-chars-not-matching-whitespace(line) # including trailing newline - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call skip-chars-not-matching-whitespace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # out->end = &line->data[line->read] - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/eax 0xc/disp8 . # copy esi+ecx+12 to eax - 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4) -$next-word:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-word: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # var slice/ecx: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # write(_test-stream, " ab") - # . . push args - 68/push " ab"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # next-word(_test-stream, slice) - # . . push args - 51/push-ecx - 68/push _test-stream/imm32 - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(slice->start - _test-stream->data, 2, msg) - # . check-ints-equal(slice->start - _test-stream, 14, msg) - # . . push args - 68/push "F - test-next-word: start"/imm32 - 68/push 0xe/imm32 - # . . push slice->start - _test-stream - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax - 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-stream/imm32 # subtract from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(slice->end - _test-stream->data, 4, msg) - # . check-ints-equal(slice->end - _test-stream, 16, msg) - # . . push args - 68/push "F - test-next-word: end"/imm32 - 68/push 0x10/imm32 - # . . push slice->end - _test-stream - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax - 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-stream/imm32 # subtract from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-word-returns-whole-comment: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # var slice/ecx: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # write(_test-stream, " # a") - # . . push args - 68/push " # a"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # next-word(_test-stream, slice) - # . . push args - 51/push-ecx - 68/push _test-stream/imm32 - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(slice->start - _test-stream->data, 2, msg) - # . check-ints-equal(slice->start - _test-stream, 14, msg) - # . . push args - 68/push "F - test-next-word-returns-whole-comment: start"/imm32 - 68/push 0xe/imm32 - # . . push slice->start - _test-stream - 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax - 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-stream/imm32 # subtract from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # check-ints-equal(slice->end - _test-stream->data, 5, msg) - # . check-ints-equal(slice->end - _test-stream, 17, msg) - # . . push args - 68/push "F - test-next-word-returns-whole-comment: end"/imm32 - 68/push 0x11/imm32 - # . . push slice->end - _test-stream - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax - 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-stream/imm32 # subtract from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-word-returns-empty-string-on-eof: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # var slice/ecx: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # write nothing to _test-stream - # next-word(_test-stream, slice) - # . . push args - 51/push-ecx - 68/push _test-stream/imm32 - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(slice->end - slice->start, 0, msg) - # . . push args - 68/push "F - test-next-word-returns-empty-string-on-eof"/imm32 - 68/push 0/imm32 - # . . push slice->end - slice->start - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax - 2b/subtract 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # subtract *ecx from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-next-word-returns-empty-string-on-newline: - # . prologue - 55/push-ebp - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - # 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 - # var slice/ecx: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx - # write some whitespace and a newline - # . . push args - 68/push " \n"/imm32 - 68/push _test-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # next-word(_test-stream, slice) - # . . push args - 51/push-ecx - 68/push _test-stream/imm32 - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp - # check-ints-equal(slice->end - slice->start, 0, msg) - # . . push args - 68/push "F - test-next-word-returns-empty-string-on-newline"/imm32 - 68/push 0/imm32 - # . . push slice->end - slice->start - 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax - 2b/subtract 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # subtract *ecx from eax - 50/push-eax - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# (re)compute the bounds of the next word in the line (separated by whitespace) -# return empty string on reaching end of file -next-raw-word: # line: (addr stream byte), out: (addr slice) - # . prologue - 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 - 56/push-esi - 57/push-edi - # esi = line - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi - # edi = out - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi - # skip-chars-matching-whitespace(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call skip-chars-matching-whitespace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp -$next-raw-word:check0: - # if (line->read >= line->write) clear out and return - # . eax = line->read - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy *(esi+4) to eax - # . if (eax < line->write) goto next check - 3b/compare 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # compare eax with *esi - 7c/jump-if-< $next-raw-word:word-exists/disp8 - # . return out - c7 0/subop/copy 0/mod/direct 7/rm32/edi . . . . . 0/imm32 # copy to *edi - c7 0/subop/copy 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 0/imm32 # copy to *(edi+4) - eb/jump $next-raw-word:end/disp8 -$next-raw-word:word-exists: - # out->start = &line->data[line->read] - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/eax 0xc/disp8 . # copy esi+ecx+12 to eax - 89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi - # skip-chars-not-matching-whitespace(line) # including trailing newline - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) - # . . call - e8/call skip-chars-not-matching-whitespace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # out->end = &line->data[line->read] - 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/eax 0xc/disp8 . # copy esi+ecx+12 to eax - 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4) -$next-raw-word:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/301array-equal.subx b/baremetal/301array-equal.subx deleted file mode 100644 index fd46ccb6..00000000 --- a/baremetal/301array-equal.subx +++ /dev/null @@ -1,432 +0,0 @@ -# Comparing arrays of numbers. - -== code - -array-equal?: # a: (addr array int), b: (addr array int) -> result/eax: boolean - # pseudocode: - # asize = a->size - # if (asize != b->size) return false - # i = 0 - # curra = a->data - # currb = b->data - # while i < asize - # i1 = *curra - # i2 = *currb - # if (c1 != c2) return false - # i+=4, curra+=4, currb+=4 - # return true - # - # registers: - # i: ecx - # asize: edx - # curra: esi - # currb: edi - # i1: eax - # i2: ebx - # - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # esi = a - 8b/-> *(ebp+8) 6/r32/esi - # edi = b - 8b/-> *(ebp+0xc) 7/r32/edi - # var asize/edx: int = a->size - 8b/-> *esi 2/r32/edx -$array-equal?:sizes: - # if (asize != b->size) return false - 39/compare *edi 2/r32/edx - 75/jump-if-!= $array-equal?:false/disp8 - # var curra/esi: (addr byte) = a->data - 81 0/subop/add %esi 4/imm32 - # var currb/edi: (addr byte) = b->data - 81 0/subop/add %edi 4/imm32 - # var i/ecx: int = 0 - 31/xor-with %ecx 1/r32/ecx - # var vala/eax: int - # var valb/ebx: int -$array-equal?:loop: - # if (i >= asize) return true - 39/compare %ecx 2/r32/edx - 7d/jump-if->= $array-equal?:true/disp8 - # var vala/eax: int = *curra - 8b/-> *esi 0/r32/eax - # var valb/ebx: int = *currb - 8b/-> *edi 3/r32/ebx - # if (vala != valb) return false - 39/compare %eax 3/r32/ebx - 75/jump-if-!= $array-equal?:false/disp8 - # i += 4 - 81 0/subop/add %ecx 4/imm32 - # currs += 4 - 81 0/subop/add %esi 4/imm32 - # currb += 4 - 81 0/subop/add %edi 4/imm32 - eb/jump $array-equal?:loop/disp8 -$array-equal?:true: - b8/copy-to-eax 1/imm32 - eb/jump $array-equal?:end/disp8 -$array-equal?:false: - b8/copy-to-eax 0/imm32 -$array-equal?:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-compare-empty-with-empty-array: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var ecx: (array _) = [] - 68/push 0/imm32/size - 89/<- %ecx 4/r32/esp - # var edx: (array _) = [] - 68/push 0/imm32/size - 89/<- %edx 4/r32/esp - # - (array-equal? %ecx %edx) # => eax - (check-ints-equal %eax 1 "F - test-compare-empty-with-empty-array") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-compare-empty-with-non-empty-array: # also checks size-mismatch code path - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var ecx: (array int) = [1] - 68/push 1/imm32 - 68/push 4/imm32/size - 89/<- %ecx 4/r32/esp - # var edx: (array int) = [] - 68/push 0/imm32/size - 89/<- %edx 4/r32/esp - # - (array-equal? %ecx %edx) # => eax - (check-ints-equal %eax 0 "F - test-compare-empty-with-non-empty-array") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-compare-equal-arrays: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var ecx: (array int) = [1, 2, 3] - 68/push 3/imm32 - 68/push 2/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %ecx 4/r32/esp - # var edx: (array int) = [1, 2, 3] - 68/push 3/imm32 - 68/push 2/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %edx 4/r32/esp - # - (array-equal? %ecx %edx) # => eax - (check-ints-equal %eax 1 "F - test-compare-equal-arrays") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-compare-inequal-arrays-equal-sizes: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var ecx: (array int) = [1, 4, 3] - 68/push 3/imm32 - 68/push 4/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %ecx 4/r32/esp - # var edx: (array int) = [1, 2, 3] - 68/push 3/imm32 - 68/push 2/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %edx 4/r32/esp - # - (array-equal? %ecx %edx) # => eax - (check-ints-equal %eax 0 "F - test-compare-inequal-arrays-equal-sizes") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -_parse-array-of-ints: # ad: (addr allocation-descriptor), s: (addr array byte), out: (addr handle array int) - # pseudocode - # end = &s->data[s->size] - # curr = s->data - # size = 0 - # while true - # if (curr >= end) break - # curr = skip-chars-matching-in-slice(curr, end, ' ') - # if (curr >= end) break - # curr = skip-chars-not-matching-in-slice(curr, end, ' ') - # ++size - # allocate-array(ad, size*4, out) - # var slice: slice = {s->data, 0} - # curr = lookup(out)->data - # while true - # if (slice->start >= end) break - # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ') - # if (slice->start >= end) break - # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ') - # *curr = parse-hex-int-from-slice(slice) - # curr += 4 - # slice->start = slice->end - # return result - # - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # esi = s - 8b/-> *(ebp+0xc) 6/r32/esi - # var curr/ecx: (addr byte) = s->data - 8d/copy-address *(esi+4) 1/r32/ecx - # var end/edx: (addr byte) = &s->data[s->size] - # . edx = s->size - 8b/-> *esi 2/r32/edx - # . edx += curr - 01/add-to %edx 1/r32/ecx - # var size/ebx: int = 0 - 31/xor-with %ebx 3/r32/ebx -$_parse-array-of-ints:loop1: - # if (curr >= end) break - 39/compare %ecx 2/r32/edx - 73/jump-if-addr>= $_parse-array-of-ints:break1/disp8 - # curr = skip-chars-matching-in-slice(curr, end, ' ') - (skip-chars-matching-in-slice %ecx %edx 0x20) # => eax - 89/<- %ecx 0/r32/eax - # if (curr >= end) break - 39/compare %ecx 2/r32/edx - 73/jump-if-addr>= $_parse-array-of-ints:break1/disp8 - # curr = skip-chars-not-matching-in-slice(curr, end, ' ') - (skip-chars-not-matching-in-slice %ecx %edx 0x20) # => eax - 89/<- %ecx 0/r32/eax - # size += 4 - 81 0/subop/add %ebx 4/imm32 - eb/jump $_parse-array-of-ints:loop1/disp8 -$_parse-array-of-ints:break1: - (allocate-array *(ebp+8) %ebx *(ebp+0x10)) -$_parse-array-of-ints:pass2: - # var slice/edi: slice = {s->data, 0} - 68/push 0/imm32/end - 8d/copy-address *(esi+4) 7/r32/edi - 57/push-edi - 89/<- %edi 4/r32/esp - # curr = lookup(out)->data - 8b/-> *(ebp+0x10) 0/r32/eax - (lookup *eax *(eax+4)) # => eax - 8d/copy-address *(eax+4) 1/r32/ecx -$_parse-array-of-ints:loop2: - # if (slice->start >= end) break - 39/compare *edi 2/r32/edx - 73/jump-if-addr>= $_parse-array-of-ints:end/disp8 - # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ') - (skip-chars-matching-in-slice *edi %edx 0x20) # => eax - 89/<- *edi 0/r32/eax - # if (slice->start >= end) break - 39/compare *edi 2/r32/edx - 73/jump-if-addr>= $_parse-array-of-ints:end/disp8 - # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ') - (skip-chars-not-matching-in-slice *edi %edx 0x20) # => eax - 89/<- *(edi+4) 0/r32/eax - # *curr = parse-hex-int-from-slice(slice) - (parse-hex-int-from-slice %edi) - 89/<- *ecx 0/r32/eax - # curr += 4 - 81 0/subop/add %ecx 4/imm32 - # slice->start = slice->end - 8b/-> *(edi+4) 0/r32/eax - 89/<- *edi 0/r32/eax - eb/jump $_parse-array-of-ints:loop2/disp8 -$_parse-array-of-ints:end: - # . reclaim locals - 81 0/subop/add %esp 8/imm32 - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-array-of-ints: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var h/esi: (handle array int) - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # var ecx: (array int) = [1, 2, 3] - 68/push 3/imm32 - 68/push 2/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %ecx 4/r32/esp - # - (_parse-array-of-ints Heap "1 2 3" %esi) - (lookup *esi *(esi+4)) # => eax - (array-equal? %ecx %eax) # => eax - (check-ints-equal %eax 1 "F - test-parse-array-of-ints") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-array-of-ints-empty: - # - empty string = empty array - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var h/esi: handle - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # - (_parse-array-of-ints Heap "" %esi) - (lookup *esi *(esi+4)) # => eax - (check-ints-equal *eax 0 "F - test-parse-array-of-ints-empty") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-array-of-ints-just-whitespace: - # - just whitespace = empty array - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var h/esi: handle - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # - (_parse-array-of-ints Heap Space %esi) - (lookup *esi *(esi+4)) # => eax - (check-ints-equal *eax 0 "F - test-parse-array-of-ints-just-whitespace") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-array-of-ints-extra-whitespace: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var h/esi: handle - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # var ecx: (array int) = [1, 2, 3] - 68/push 3/imm32 - 68/push 2/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %ecx 4/r32/esp - # - (_parse-array-of-ints Heap " 1 2 3 " %esi) - (lookup *esi *(esi+4)) # => eax - (array-equal? %ecx %eax) # => eax - (check-ints-equal %eax 1 "F - test-parse-array-of-ints-extra-whitespace") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -parse-array-of-ints: # s: (addr array byte), out: (addr handle array int) - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - (_parse-array-of-ints Heap *(ebp+8) *(ebp+0xc)) -$parse-array-of-ints:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -# helper for later tests -# compare an array with a string representation of an array literal -check-array-equal: # a: (addr array int), expected: (addr string), msg: (addr string) - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 56/push-esi - # var h/esi: handle - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # var b/eax: (addr array int) = parse-array-of-ints(Heap, expected) - (parse-array-of-ints *(ebp+0xc) %esi) - (lookup *esi *(esi+4)) # => eax - # - (array-equal? *(ebp+8) %eax) - (check-ints-equal %eax 1 *(ebp+0x10)) -$check-array-equal:end: - # . restore registers - 5e/pop-to-esi - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-check-array-equal: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var ecx: (array int) = [1, 2, 3] - 68/push 3/imm32 - 68/push 2/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %ecx 4/r32/esp - # - (check-array-equal %ecx "1 2 3" "F - test-check-array-equal") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -== data - -# length-prefixed string containing just a single space -Space: # (array byte) - # size: int - 1/imm32 - # data - 20/space diff --git a/baremetal/302stack_allocate.subx b/baremetal/302stack_allocate.subx deleted file mode 100644 index cd51d5ff..00000000 --- a/baremetal/302stack_allocate.subx +++ /dev/null @@ -1,61 +0,0 @@ -# A function which pushes n zeros on the stack. -# Really only intended to be called from code generated by mu.subx (for array -# vars on the stack). - -== code - -#? Entry: -#? # . prologue -#? 89/<- %ebp 4/r32/esp -#? # -#? 68/push 0xfcfdfeff/imm32 -#? b8/copy-to-eax 0x34353637/imm32 -#? $dump-stack0: -#? (push-n-zero-bytes 4) -#? 68/push 0x20/imm32 -#? $dump-stack9: -#? b8/copy-to-eax 1/imm32/exit -#? cd/syscall 0x80/imm8 - -# This is not a regular function, so it won't be idiomatic. -# Registers must be properly restored. -# Registers can be spilled, but that modifies the stack and needs to be -# cleaned up. - -# Overhead: -# 62 + n*6 instructions to push n bytes. -# If we just emitted code to push n zeroes, it would be: -# 5 bytes for 4 zero bytes, so 1.25 bytes per zero. And that's not even -# instructions. -# But on the other hand it would destroy the instruction cache, where this -# approach requires 15 instructions, fixed. - -# n must be positive -push-n-zero-bytes: # n: int -$push-n-zero-bytes:prologue: - 89/<- *Push-n-zero-bytes-ebp 5/r32/ebp # spill ebp without affecting stack - 89/<- %ebp 4/r32/esp -$push-n-zero-bytes:copy-ra: - # -- esp = ebp - 89/<- *Push-n-zero-bytes-eax 0/r32/eax - 8b/-> *esp 0/r32/eax - 2b/subtract *(ebp+4) 4/r32/esp - # -- esp+n = ebp - 89/<- *esp 0/r32/eax - 8b/-> *Push-n-zero-bytes-eax 0/r32/eax -$push-n-zero-bytes:bulk-cleaning: - 89/<- *Push-n-zero-bytes-esp 4/r32/esp - 81 0/subop/add *Push-n-zero-bytes-esp 4/imm32 - 81 0/subop/add *(ebp+4) 4/imm32 - (zero-out *Push-n-zero-bytes-esp *(ebp+4)) # n+4 -$push-n-zero-bytes:epilogue: - 8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp # restore spill - c3/return - -== data -Push-n-zero-bytes-ebp: # (addr int) - 0/imm32 -Push-n-zero-bytes-esp: # (addr int) - 0/imm32 -Push-n-zero-bytes-eax: - 0/imm32 diff --git a/baremetal/308allocate-array.subx b/baremetal/308allocate-array.subx deleted file mode 100644 index 5cc0fe1b..00000000 --- a/baremetal/308allocate-array.subx +++ /dev/null @@ -1,25 +0,0 @@ -# 2-arg version of allocate-array. -# Really only intended to be called from code generated by mu.subx. - -== code - -allocate-array2: # ad: (addr allocation-descriptor), array-len: int, elem-size: int, out: (addr handle array _) - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 52/push-edx - # - 8b/-> *(ebp+0xc) 0/r32/eax - f7 4/subop/multiply-into-edx-eax *(ebp+0x10) - # TODO: check edx for overflow - (allocate-array *(ebp+8) %eax *(ebp+0x14)) -$allocate-array2:end: - # . restore registers - 5a/pop-to-edx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/309stream.subx b/baremetal/309stream.subx deleted file mode 100644 index 56b19272..00000000 --- a/baremetal/309stream.subx +++ /dev/null @@ -1,214 +0,0 @@ -# Some unsafe methods not intended to be used directly in SubX, only through -# Mu after proper type-checking. - -== code - -stream-empty?: # s: (addr stream _) -> result/eax: boolean - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 56/push-esi - # result = false - b8/copy-to-eax 0/imm32/false - # esi = s - 8b/-> *(ebp+8) 6/r32/esi - # return s->read >= s->write - 8b/-> *esi 1/r32/ecx - 39/compare-with *(esi+4) 1/r32/ecx - 0f 9d/set-if->= %al -$stream-empty?:end: - # . restore registers - 5e/pop-to-esi - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -stream-full?: # s: (addr stream _) -> result/eax: boolean - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 56/push-esi - # result = false - b8/copy-to-eax 0/imm32/false - # esi = s - 8b/-> *(ebp+8) 6/r32/esi - # return s->write >= s->size - 8b/-> *(esi+8) 1/r32/ecx - 39/compare-with *esi 1/r32/ecx - 0f 9d/set-if->= %al -$stream-full?:end: - # . restore registers - 5e/pop-to-esi - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -write-to-stream: # s: (addr stream _), in: (addr byte), n: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 53/push-ebx - 57/push-edi - # edi = s - 8b/-> *(ebp+8) 7/r32/edi - # var swrite/edx: int = s->write - 8b/-> *edi 2/r32/edx - # if (swrite + n > s->size) abort - 8b/-> *(ebp+0x10) 1/r32/ecx - 01/add-to %ecx 2/r32/edx - 3b/compare 1/r32/ecx *(edi+8) - 0f 8f/jump-if-> $write-to-stream:abort/disp32 - # var out/edx: (addr byte) = s->data + s->write - 8d/copy-address *(edi+edx+0xc) 2/r32/edx - # var outend/ebx: (addr byte) = out + n - 8b/-> *(ebp+0x10) 3/r32/ebx - 8d/copy-address *(edx+ebx) 3/r32/ebx - # eax = in - 8b/-> *(ebp+0xc) 0/r32/eax - # var inend/ecx: (addr byte) = in + n - 8b/-> *(ebp+0x10) 1/r32/ecx - 8d/copy-address *(eax+ecx) 1/r32/ecx - # - (_append-4 %edx %ebx %eax %ecx) # => eax - # s->write += n - 8b/-> *(ebp+0x10) 1/r32/ecx - 01/add-to *edi 1/r32/ecx -$write-to-stream:end: - # . restore registers - 5f/pop-to-edi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -$write-to-stream:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "write-to-stream: stream full" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -read-from-stream: # s: (addr stream _), out: (addr byte), n: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - # esi = s - 8b/-> *(ebp+8) 6/r32/esi - # var sread/edx: int = s->read - 8b/-> *(esi+4) 2/r32/edx - # if (sread + n > s->write) abort - 8b/-> *(ebp+0x10) 1/r32/ecx - 01/add-to %ecx 2/r32/edx - 3b/compare 1/r32/ecx *esi - 0f 8f/jump-if-> $read-from-stream:abort/disp32 - # var in/edx: (addr byte) = s->data + s->read - 8d/copy-address *(esi+edx+0xc) 2/r32/edx - # var inend/ebx: (addr byte) = in + n - 8b/-> *(ebp+0x10) 3/r32/ebx - 8d/copy-address *(edx+ebx) 3/r32/ebx - # eax = out - 8b/-> *(ebp+0xc) 0/r32/eax - # var outend/ecx: (addr byte) = out + n - 8b/-> *(ebp+0x10) 1/r32/ecx - 8d/copy-address *(eax+ecx) 1/r32/ecx - # - (_append-4 %eax %ecx %edx %ebx) # => eax - # s->read += n - 8b/-> *(ebp+0x10) 1/r32/ecx - 01/add-to *(esi+4) 1/r32/ecx -$read-from-stream:end: - # . restore registers - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -$read-from-stream:abort: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "read-from-stream: stream empty" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here - -stream-first: # s: (addr stream byte) -> result/eax: byte - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 56/push-esi - # result = false - b8/copy-to-eax 0/imm32 - # esi = s - 8b/-> *(ebp+8) 6/r32/esi - # var idx/ecx: int = s->read - 8b/-> *(esi+4) 1/r32/ecx - # if idx >= s->write return 0 - 3b/compare-with 1/r32/ecx *esi - 7d/jump-if->= $stream-first:end/disp8 - # result = s->data[idx] - 8a/byte-> *(esi+ecx+0xc) 0/r32/AL -$stream-first:end: - # . restore registers - 5e/pop-to-esi - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -stream-final: # s: (addr stream byte) -> result/eax: byte - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 56/push-esi - # result = false - b8/copy-to-eax 0/imm32 - # esi = s - 8b/-> *(ebp+8) 6/r32/esi - # var max/ecx: int = s->write - 8b/-> *esi 1/r32/ecx - # if s->read >= max return 0 - 39/compare-with *(esi+4) 1/r32/ecx - 7d/jump-if->= $stream-final:end/disp8 - # var idx/ecx: int = max - 1 - 49/decrement-ecx - # result = s->data[idx] - 8a/byte-> *(esi+ecx+0xc) 0/r32/AL -$stream-final:end: - # . restore registers - 5e/pop-to-esi - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/310copy-bytes.subx b/baremetal/310copy-bytes.subx deleted file mode 100644 index 2586a53f..00000000 --- a/baremetal/310copy-bytes.subx +++ /dev/null @@ -1,157 +0,0 @@ -# Some helpers for copying non-overlapping regions of memory. -# Really only intended to be called from code generated by mu.subx. - -== code - -copy-bytes: # src: (addr byte), dest: (addr byte), size: int - # pseudocode: - # curr-src/esi = src - # curr-dest/edi = dest - # i/ecx = 0 - # while true - # if (i >= size) break - # *curr-dest = *curr-src - # ++curr-src - # ++curr-dest - # ++i - # - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 56/push-esi - 57/push-edi - # curr-src/esi = src - 8b/-> *(ebp+8) 6/r32/esi - # curr-dest/edi = dest - 8b/-> *(ebp+0xc) 7/r32/edi - # var i/ecx: int = 0 - b9/copy-to-ecx 0/imm32 - # edx = size - 8b/-> *(ebp+0x10) 2/r32/edx - { - # if (i >= size) break - 39/compare %ecx 2/r32/edx - 7d/jump-if->= break/disp8 - # *curr-dest = *curr-src - 8a/byte-> *esi 0/r32/AL - 88/byte<- *edi 0/r32/AL - # update - 46/increment-esi - 47/increment-edi - 41/increment-ecx - eb/jump loop/disp8 - } -$copy-bytes:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -stream-to-array: # in: (addr stream _), out: (addr handle array _) - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 56/push-esi - # esi = s - 8b/-> *(ebp+8) 6/r32/esi - # var len/ecx: int = s->write - s->read - 8b/-> *esi 1/r32/ecx - 2b/subtract *(esi+4) 1/r32/ecx - # allocate - (allocate-array Heap %ecx *(ebp+0xc)) - # var in/edx: (addr byte) = s->data + s->read - 8b/-> *(esi+4) 2/r32/edx - 8d/copy-address *(esi+edx+0xc) 2/r32/edx - # var dest/eax: (addr byte) = data for out - 8b/-> *(ebp+0xc) 0/r32/eax - (lookup *eax *(eax+4)) # => eax - 8d/copy-address *(eax+4) 0/r32/eax - # - (copy-bytes %edx %eax %ecx) -$stream-to-array:end: - # . restore registers - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-stream-to-array: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # setup - (clear-stream _test-input-stream) - (write _test-input-stream "abc") - # skip something - (read-byte _test-input-stream) # => eax - # var out/ecx: (handle array byte) - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %ecx 4/r32/esp - # - (stream-to-array _test-input-stream %ecx) - (lookup *ecx *(ecx+4)) # => eax - (check-strings-equal %eax "bc") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -# like stream-to-array but ignore surrounding quotes -# we might do other stuff here later -unquote-stream-to-array: # in: (addr stream _), out: (addr handle array _) - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 56/push-esi - # esi = s - 8b/-> *(ebp+8) 6/r32/esi - # var len/ecx: int = s->write - s->read - 2 - 8b/-> *esi 1/r32/ecx - 2b/subtract *(esi+4) 1/r32/ecx - 81 7/subop/compare %ecx 2/imm32 - 7c/jump-if-< $unquote-stream-to-array:end/disp8 - 81 5/subop/subtract %ecx 2/imm32 - # allocate - (allocate-array Heap %ecx *(ebp+0xc)) - # var in/edx: (addr byte) = s->data + s->read + 1 - 8b/-> *(esi+4) 2/r32/edx - 8d/copy-address *(esi+edx+0xd) 2/r32/edx # Stream-data + 1 - # var dest/eax: (addr byte) = data for out - 8b/-> *(ebp+0xc) 0/r32/eax - (lookup *eax *(eax+4)) # => eax - 8d/copy-address *(eax+4) 0/r32/eax - # - (copy-bytes %edx %eax %ecx) -$unquote-stream-to-array:end: - # . restore registers - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/311decimal-int.subx b/baremetal/311decimal-int.subx deleted file mode 100644 index d0d8dde7..00000000 --- a/baremetal/311decimal-int.subx +++ /dev/null @@ -1,633 +0,0 @@ -# Helpers for decimal ints. - -# if slice doesn't contain a decimal number, return 0 -parse-decimal-int-from-slice: # in: (addr slice) -> out/eax: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - # ecx = in - 8b/-> *(ebp+8) 1/r32/ecx - # - (parse-decimal-int-helper *ecx *(ecx+4)) # => eax -$parse-decimal-int-from-slice:end: - # . restore registers - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -# if slice doesn't contain a decimal number, return 0 -parse-decimal-int: # in: (addr array byte) -> result/eax: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 52/push-edx - # eax = in - 8b/-> *(ebp+8) 0/r32/eax - # var start/ecx: (addr byte) = &in->data - 8d/copy-address *(eax+4) 1/r32/ecx - # var end/edx: (addr byte) = &in->data[in->size] - 8b/-> *eax 2/r32/edx - 8d/copy-address *(eax+edx+4) 2/r32/edx - # - (parse-decimal-int-helper %ecx %edx) # => eax -$parse-decimal-int:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -parse-decimal-int-from-stream: # in: (addr stream byte) -> result/eax: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 52/push-edx - # eax = in - 8b/-> *(ebp+8) 0/r32/eax - # var start/ecx: (addr byte) = &in->data[in->read] - 8b/-> *(eax+4) 1/r32/ecx - 8d/copy-address *(eax+ecx+0xc) 1/r32/ecx - # var end/edx: (addr byte) = &in->data[in->write] - 8b/-> *eax 2/r32/edx - 8d/copy-address *(eax+edx+0xc) 2/r32/edx - # trim a trailing newline - { - # speculatively trim - 4a/decrement-edx - # if it's a newline, break - 8a/byte-> *edx 0/r32/eax - 81 4/subop/and %eax 0xff/imm32 - 3d/compare-eax-and 0xa/imm32/newline - 74/jump-if-= break/disp8 - # not a newline, so restore it - 42/increment-edx - } - # - (parse-decimal-int-helper %ecx %edx) # => eax -$parse-decimal-int-from-stream:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -parse-decimal-int-helper: # start: (addr byte), end: (addr byte) -> result/eax: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # var curr/esi: (addr byte) = start - 8b/-> *(ebp+8) 6/r32/esi - # edi = end - 8b/-> *(ebp+0xc) 7/r32/edi - # var negate?/edx: boolean = false - ba/copy-to-edx 0/imm32/false - # if (*curr == '-') ++curr, negate = true - { -$parse-decimal-int-helper:negative: - b8/copy-to-eax 0/imm32 - 8a/copy-byte *esi 0/r32/AL - 3d/compare-eax-and 0x2d/imm32/- - 75/jump-if-!= break/disp8 - # . ++curr - 46/increment-esi - # . negate = true - ba/copy-to-edx 1/imm32/true - } - # spill negate? - 52/push-edx - # var result/eax: int = 0 - b8/copy-to-eax 0/imm32 - # var digit/ecx: int = 0 - b9/copy-to-ecx 0/imm32 - # const TEN/ebx: int = 10 - bb/copy-to-ebx 0xa/imm32 - { -$parse-decimal-int-helper:loop: - # if (curr >= in->end) break - 39/compare %esi 7/r32/edi - 73/jump-if-addr>= break/disp8 - # if !is-decimal-digit?(*curr) return 0 - 8a/copy-byte *esi 1/r32/CL - 50/push-eax - (is-decimal-digit? %ecx) # => eax - { - 3d/compare-eax-and 0/imm32/false - 75/jump-if-!= break/disp8 - 58/pop-to-eax - b8/copy-to-eax 0/imm32 - eb/jump $parse-decimal-int-helper:negate/disp8 - } - 58/pop-to-eax - # digit = from-decimal-char(*curr) - 81 5/subop/subtract %ecx 0x30/imm32/zero - # TODO: error checking - # result = result * 10 + digit - ba/copy-to-edx 0/imm32 - f7 4/subop/multiply-into-edx-eax %ebx - # TODO: check edx for overflow - 01/add %eax 1/r32/ecx - # ++curr - 46/increment-esi - # - eb/jump loop/disp8 - } -$parse-decimal-int-helper:negate: - # if (negate?) result = -result - 5a/pop-to-edx - { - 81 7/subop/compare %edx 0/imm32/false - 74/jump-if-= break/disp8 - f7 3/subop/negate %eax - } -$parse-decimal-int-helper:end: - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-decimal-int-from-slice-single-digit: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - # (eax..ecx) = "3" - b8/copy-to-eax "3"/imm32 - 8b/-> *eax 1/r32/ecx - 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/<- %ecx 4/r32/esp - # - (parse-decimal-int-from-slice %ecx) # => eax - (check-ints-equal %eax 3 "F - test-parse-decimal-int-from-slice-single-digit") -$test-parse-decimal-int-helper-single-digit:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-decimal-int-from-slice-multi-digit: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - # (eax..ecx) = "34" - b8/copy-to-eax "34"/imm32 - 8b/-> *eax 1/r32/ecx - 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/<- %ecx 4/r32/esp - # - (parse-decimal-int-from-slice %ecx) # => eax - (check-ints-equal %eax 0x22 "F - test-parse-decimal-int-from-slice-multi-digit") # 34 in hex -$test-parse-decimal-int-helper-multi-digit:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-decimal-int-from-slice-zero: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - # (eax..ecx) = "00" - b8/copy-to-eax "00"/imm32 - 8b/-> *eax 1/r32/ecx - 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/<- %ecx 4/r32/esp - # - (parse-decimal-int-from-slice %ecx) # => eax - (check-ints-equal %eax 0 "F - test-parse-decimal-int-from-slice-zero") -$test-parse-decimal-int-helper-zero:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-decimal-int-from-slice-negative: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - # (eax..ecx) = "-3" - b8/copy-to-eax "-3"/imm32 - 8b/-> *eax 1/r32/ecx - 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/<- %ecx 4/r32/esp - # - (parse-decimal-int-from-slice %ecx) # => eax - (check-ints-equal %eax -3 "F - test-parse-decimal-int-from-slice-negative") -$test-parse-decimal-int-helper-negative:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-decimal-int-from-slice-multi-digit-negative: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - # (eax..ecx) = "-32" - b8/copy-to-eax "-32"/imm32 - 8b/-> *eax 1/r32/ecx - 8d/copy-address *(eax+ecx+4) 1/r32/ecx - 05/add-to-eax 4/imm32 - # var slice/ecx: slice = {eax, ecx} - 51/push-ecx - 50/push-eax - 89/<- %ecx 4/r32/esp - # - (parse-decimal-int-from-slice %ecx) # => eax - (check-ints-equal %eax -0x20 "F - test-parse-decimal-int-from-slice-multi-digit-negative") # -32 in hex -$test-parse-decimal-int-helper-multi-digit-negative:end: - # . restore registers - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -decimal-size: # n: int -> result/eax: int - # pseudocode: - # edi = 0 - # eax = n - # if eax < 0 - # ++edi # for '-' - # negate eax - # while true - # edx = 0 - # eax, edx = eax/10, eax%10 - # ++edi - # if (eax == 0) break - # eax = edi - # - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 51/push-ecx - 52/push-edx - 57/push-edi - # edi = 0 - bf/copy-to-edi 0/imm32 - # eax = n - 8b/-> *(ebp+8) 0/r32/eax - # if (n < 0) negate n, increment edi - { - 3d/compare-eax-with 0/imm32 - 7d/jump-if->= break/disp8 - f7 3/subop/negate %eax - 47/increment-edi - } - # const ten/ecx = 10 - b9/copy-to-ecx 0xa/imm32 - { - ba/copy-to-edx 0/imm32 - f7 7/subop/idiv-edx-eax-by %ecx # eax = edx:eax/10; edx = edx:eax%10 - 47/increment-edi - 3d/compare-eax-and 0/imm32 - 75/jump-if-!= loop/disp8 - } -$decimal-size:end: - 89/<- %eax 7/r32/edi - # . restore registers - 5f/pop-to-edi - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-decimal-size-of-zero: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - (decimal-size 0) # => eax - (check-ints-equal %eax 1 "F - test-decimal-size-of-zero") -$test-decimal-size-of-zero:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-decimal-size-single-digit: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - (decimal-size 4) # => eax - (check-ints-equal %eax 1 "F - test-decimal-size-single-digit") -$test-decimal-size-single-digit:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-decimal-size-multi-digit: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - (decimal-size 0xa) # => eax - (check-ints-equal %eax 2 "F - test-decimal-size-multi-digit") -$test-decimal-size-multi-digit:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-decimal-size-single-digit-negative: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - (decimal-size -4) # => eax - (check-ints-equal %eax 2 "F - test-decimal-size-single-digit-negative") -$test-decimal-size-single-digit-negative:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-decimal-size-multi-digit-negative: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - (decimal-size -0xa) # => eax - (check-ints-equal %eax 3 "F - test-decimal-size-multi-digit-negative") -$test-decimal-size-multi-digit-negative:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -_parse-array-of-decimal-ints: # ad: (addr allocation-descriptor), s: (addr array byte), out: (addr handle array int) - # pseudocode - # end = &s->data[s->size] - # curr = s->data - # size = 0 - # while true - # if (curr >= end) break - # curr = skip-chars-matching-in-slice(curr, end, ' ') - # if (curr >= end) break - # curr = skip-chars-not-matching-in-slice(curr, end, ' ') - # ++size - # allocate-array(ad, size*4, out) - # var slice: slice = {s->data, 0} - # curr = lookup(out)->data - # while true - # if (slice->start >= end) break - # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ') - # if (slice->start >= end) break - # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ') - # *curr = parse-hex-int-from-slice(slice) - # curr += 4 - # slice->start = slice->end - # return result - # - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - 53/push-ebx - 56/push-esi - 57/push-edi - # esi = s - 8b/-> *(ebp+0xc) 6/r32/esi - # var curr/ecx: (addr byte) = s->data - 8d/copy-address *(esi+4) 1/r32/ecx - # var end/edx: (addr byte) = &s->data[s->size] - # . edx = s->size - 8b/-> *esi 2/r32/edx - # . edx += curr - 01/add-to %edx 1/r32/ecx - # var size/ebx: int = 0 - 31/xor-with %ebx 3/r32/ebx -$_parse-array-of-decimal-ints:loop1: - # if (curr >= end) break - 39/compare %ecx 2/r32/edx - 73/jump-if-addr>= $_parse-array-of-decimal-ints:break1/disp8 - # curr = skip-chars-matching-in-slice(curr, end, ' ') - (skip-chars-matching-in-slice %ecx %edx 0x20) # => eax - 89/<- %ecx 0/r32/eax - # if (curr >= end) break - 39/compare %ecx 2/r32/edx - 73/jump-if-addr>= $_parse-array-of-decimal-ints:break1/disp8 - # curr = skip-chars-not-matching-in-slice(curr, end, ' ') - (skip-chars-not-matching-in-slice %ecx %edx 0x20) # => eax - 89/<- %ecx 0/r32/eax - # size += 4 - 81 0/subop/add %ebx 4/imm32 - eb/jump $_parse-array-of-decimal-ints:loop1/disp8 -$_parse-array-of-decimal-ints:break1: - (allocate-array *(ebp+8) %ebx *(ebp+0x10)) -$_parse-array-of-decimal-ints:pass2: - # var slice/edi: slice = {s->data, 0} - 68/push 0/imm32/end - 8d/copy-address *(esi+4) 7/r32/edi - 57/push-edi - 89/<- %edi 4/r32/esp - # curr = lookup(out)->data - 8b/-> *(ebp+0x10) 0/r32/eax - (lookup *eax *(eax+4)) # => eax - 8d/copy-address *(eax+4) 1/r32/ecx -$_parse-array-of-decimal-ints:loop2: - # if (slice->start >= end) break - 39/compare *edi 2/r32/edx - 73/jump-if-addr>= $_parse-array-of-decimal-ints:end/disp8 - # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ') - (skip-chars-matching-in-slice *edi %edx 0x20) # => eax - 89/<- *edi 0/r32/eax - # if (slice->start >= end) break - 39/compare *edi 2/r32/edx - 73/jump-if-addr>= $_parse-array-of-decimal-ints:end/disp8 - # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ') - (skip-chars-not-matching-in-slice *edi %edx 0x20) # => eax - 89/<- *(edi+4) 0/r32/eax - # *curr = parse-hex-int-from-slice(slice) - (parse-decimal-int-from-slice %edi) - 89/<- *ecx 0/r32/eax - # curr += 4 - 81 0/subop/add %ecx 4/imm32 - # slice->start = slice->end - 8b/-> *(edi+4) 0/r32/eax - 89/<- *edi 0/r32/eax - eb/jump $_parse-array-of-decimal-ints:loop2/disp8 -$_parse-array-of-decimal-ints:end: - # . reclaim locals - 81 0/subop/add %esp 8/imm32 - # . restore registers - 5f/pop-to-edi - 5e/pop-to-esi - 5b/pop-to-ebx - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-array-of-decimal-ints: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var h/esi: (handle array int) - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # var ecx: (array int) = [1, 2, 3] - 68/push 3/imm32 - 68/push 2/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %ecx 4/r32/esp - # - (_parse-array-of-decimal-ints Heap "1 2 3" %esi) - (lookup *esi *(esi+4)) # => eax - (array-equal? %ecx %eax) # => eax - (check-ints-equal %eax 1 "F - test-parse-array-of-decimal-ints") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-array-of-decimal-ints-empty: - # - empty string = empty array - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var h/esi: handle - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # - (_parse-array-of-decimal-ints Heap "" %esi) - (lookup *esi *(esi+4)) # => eax - (check-ints-equal *eax 0 "F - test-parse-array-of-decimal-ints-empty") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-array-of-decimal-ints-just-whitespace: - # - just whitespace = empty array - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var h/esi: handle - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # - (_parse-array-of-decimal-ints Heap Space %esi) - (lookup *esi *(esi+4)) # => eax - (check-ints-equal *eax 0 "F - test-parse-array-of-decimal-ints-just-whitespace") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -test-parse-array-of-decimal-ints-extra-whitespace: - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # var h/esi: handle - 68/push 0/imm32 - 68/push 0/imm32 - 89/<- %esi 4/r32/esp - # var ecx: (array int) = [1, 2, 3] - 68/push 3/imm32 - 68/push 2/imm32 - 68/push 1/imm32 - 68/push 0xc/imm32/size - 89/<- %ecx 4/r32/esp - # - (_parse-array-of-decimal-ints Heap " 1 2 3 " %esi) - (lookup *esi *(esi+4)) # => eax - (array-equal? %ecx %eax) # => eax - (check-ints-equal %eax 1 "F - test-parse-array-of-decimal-ints-extra-whitespace") - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -parse-array-of-decimal-ints: # s: (addr array byte), out: (addr handle array int) - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - (_parse-array-of-decimal-ints Heap *(ebp+8) *(ebp+0xc)) -$parse-array-of-decimal-ints:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/312copy.subx b/baremetal/312copy.subx deleted file mode 100644 index d2a6f661..00000000 --- a/baremetal/312copy.subx +++ /dev/null @@ -1,13 +0,0 @@ -== code - -copy-array-object: # src: (addr array T), dest-ah: (addr handle array T) - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # - (copy-array Heap *(ebp+8) *(ebp+0xc)) -$copy-array-object:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/313index-bounds-check.subx b/baremetal/313index-bounds-check.subx deleted file mode 100644 index c9d01ee2..00000000 --- a/baremetal/313index-bounds-check.subx +++ /dev/null @@ -1,60 +0,0 @@ -# Helper to check an array's bounds, and to abort if they're violated. -# Really only intended to be called from code generated by mu.subx. - -== code - -__check-mu-array-bounds: # index: int, elem-size: int, arr-size: int, function-name: (addr array byte), array-name: (addr array byte) - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # . save registers - 50/push-eax - 51/push-ecx - 52/push-edx - # . not bothering saving ebx; it's only clobbered if we're going to abort - # ecx = arr-size - 8b/-> *(ebp+0x10) 1/r32/ecx - # var overflow/edx: int = 0 - ba/copy-to-edx 0/imm32 - # var offset/eax: int = index * elem-size - 8b/-> *(ebp+8) 0/r32/eax - f7 4/subop/multiply-eax-with *(ebp+0xc) - # check for overflow - 81 7/subop/compare %edx 0/imm32 - 0f 85/jump-if-!= __check-mu-array-bounds:overflow/disp32 - # check bounds - 39/compare %eax 1/r32/ecx - 0f 82/jump-if-unsigned< $__check-mu-array-bounds:end/disp32 # negative index should always abort - # abort if necessary - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "fn " 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x14) 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 ": offset " 3 0) # 3=cyan - (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %eax 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 " is too large for array '" 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x18) 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "'" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here -$__check-mu-array-bounds:end: - # . restore registers - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return - -__check-mu-array-bounds:overflow: - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "fn " 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x14) 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 ": offset to array '" 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "offset to array overflowed 32 bits" 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x18) 3 0) # 3=cyan - (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "' overflowed 32 bits" 3 0) # 3=cyan - { - eb/jump loop/disp8 - } - # never gets here diff --git a/baremetal/314divide.subx b/baremetal/314divide.subx deleted file mode 100644 index c0b85526..00000000 --- a/baremetal/314divide.subx +++ /dev/null @@ -1,17 +0,0 @@ -== code - -integer-divide: # a: int, b: int -> quotient/eax: int, remainder/edx: int - # . prologue - 55/push-ebp - 89/<- %ebp 4/r32/esp - # eax = a - 8b/-> *(ebp+8) 0/r32/eax - # edx = all 0s or all 1s - 99/sign-extend-eax-into-edx - # quotient, remainder = divide eax by b - f7 7/subop/divide-eax-edx-by *(ebp+0xc) -$integer-divide:end: - # . epilogue - 89/<- %esp 5/r32/ebp - 5d/pop-to-ebp - c3/return diff --git a/baremetal/400.mu b/baremetal/400.mu deleted file mode 100644 index 9d0c095f..00000000 --- a/baremetal/400.mu +++ /dev/null @@ -1,82 +0,0 @@ -# screen -sig pixel-on-real-screen x: int, y: int, color: int -sig draw-grapheme-on-real-screen g: grapheme, x: int, y: int, color: int, background-color: int -sig cursor-position-on-real-screen -> _/eax: int, _/ecx: int -sig set-cursor-position-on-real-screen x: int, y: int -sig show-cursor-on-real-screen g: grapheme - -# keyboard -sig read-key kbd: (addr keyboard) -> _/eax: byte - -# tests -sig count-test-failure -sig num-test-failures -> _/eax: int - -sig string-equal? s: (addr array byte), benchmark: (addr array byte) -> _/eax: boolean -sig string-starts-with? s: (addr array byte), benchmark: (addr array byte) -> _/eax: boolean -sig check-strings-equal s: (addr array byte), expected: (addr array byte), msg: (addr array byte) - -# streams -sig clear-stream f: (addr stream _) -sig rewind-stream f: (addr stream _) -sig stream-data-equal? f: (addr stream byte), s: (addr array byte) -> _/eax: boolean -sig check-stream-equal f: (addr stream byte), s: (addr array byte), msg: (addr array byte) -sig next-stream-line-equal? f: (addr stream byte), s: (addr array byte) -> _/eax: boolean -sig check-next-stream-line-equal f: (addr stream byte), s: (addr array byte), msg: (addr array byte) -sig write f: (addr stream byte), s: (addr array byte) -sig write-stream f: (addr stream byte), s: (addr stream byte) -sig read-byte s: (addr stream byte) -> _/eax: byte -sig append-byte f: (addr stream byte), n: int -#sig to-hex-char in/eax: int -> out/eax: int -sig append-byte-hex f: (addr stream byte), n: int -sig write-int32-hex f: (addr stream byte), n: int -sig write-int32-hex-bits f: (addr stream byte), n: int, bits: int -sig is-hex-int? in: (addr slice) -> _/eax: boolean -sig parse-hex-int in: (addr array byte) -> _/eax: int -sig parse-hex-int-from-slice in: (addr slice) -> _/eax: int -#sig parse-hex-int-helper start: (addr byte), end: (addr byte) -> _/eax: int -sig is-hex-digit? c: byte -> _/eax: boolean -#sig from-hex-char in/eax: byte -> out/eax: nibble -sig parse-decimal-int in: (addr array byte) -> _/eax: int -sig parse-decimal-int-from-slice in: (addr slice) -> _/eax: int -sig parse-decimal-int-from-stream in: (addr stream byte) -> _/eax: int -#sig parse-decimal-int-helper start: (addr byte), end: (addr byte) -> _/eax: int -sig decimal-size n: int -> _/eax: int -#sig allocate ad: (addr allocation-descriptor), n: int, out: (addr handle _) -#sig allocate-raw ad: (addr allocation-descriptor), n: int, out: (addr handle _) -sig lookup h: (handle _T) -> _/eax: (addr _T) -sig handle-equal? a: (handle _T), b: (handle _T) -> _/eax: boolean -sig copy-handle src: (handle _T), dest: (addr handle _T) -#sig allocate-region ad: (addr allocation-descriptor), n: int, out: (addr handle allocation-descriptor) -#sig allocate-array ad: (addr allocation-descriptor), n: int, out: (addr handle _) -sig copy-array ad: (addr allocation-descriptor), src: (addr array _T), out: (addr handle array _T) -#sig zero-out start: (addr byte), size: int -sig slice-empty? s: (addr slice) -> _/eax: boolean -sig slice-equal? s: (addr slice), p: (addr array byte) -> _/eax: boolean -sig slice-starts-with? s: (addr slice), head: (addr array byte) -> _/eax: boolean -sig write-slice out: (addr stream byte), s: (addr slice) -# bad name alert -sig slice-to-string ad: (addr allocation-descriptor), in: (addr slice), out: (addr handle array byte) -sig write-int32-decimal out: (addr stream byte), n: int -sig is-decimal-digit? c: grapheme -> _/eax: boolean -sig to-decimal-digit in: grapheme -> _/eax: int -# bad name alert -# next-word really tokenizes -# next-raw-word really reads whitespace-separated words -sig next-word line: (addr stream byte), out: (addr slice) # skips '#' comments -sig next-raw-word line: (addr stream byte), out: (addr slice) # does not skip '#' comments -sig stream-empty? s: (addr stream _) -> _/eax: boolean -sig stream-full? s: (addr stream _) -> _/eax: boolean -sig stream-to-array in: (addr stream _), out: (addr handle array _) -sig unquote-stream-to-array in: (addr stream _), out: (addr handle array _) -sig stream-first s: (addr stream byte) -> _/eax: byte -sig stream-final s: (addr stream byte) -> _/eax: byte - -#sig copy-bytes src: (addr byte), dest: (addr byte), n: int -sig copy-array-object src: (addr array _), dest-ah: (addr handle array _) -sig array-equal? a: (addr array int), b: (addr array int) -> _/eax: boolean -sig parse-array-of-ints s: (addr array byte), out: (addr handle array int) -sig parse-array-of-decimal-ints s: (addr array byte), out: (addr handle array int) -sig check-array-equal a: (addr array int), expected: (addr string), msg: (addr string) - -sig integer-divide a: int, b: int -> _/eax: int, _/edx: int diff --git a/baremetal/403unicode.mu b/baremetal/403unicode.mu deleted file mode 100644 index 6ec30c3d..00000000 --- a/baremetal/403unicode.mu +++ /dev/null @@ -1,193 +0,0 @@ -# Helpers for Unicode. -# -# Mu has no characters, only code points and graphemes. -# Code points are the indivisible atoms of text streams. -# https://en.wikipedia.org/wiki/Code_point -# Graphemes are the smallest self-contained unit of text. -# Graphemes may consist of multiple code points. -# -# Mu graphemes are always represented in utf-8, and they are required to fit -# in 4 bytes. -# -# Mu doesn't currently support combining code points, or graphemes made of -# multiple code points. One day we will. -# We also don't currently support code points that translate into multiple -# or wide graphemes. (In particular, Tab will never be supported.) - -# transliterated from tb_utf8_unicode_to_char in https://github.com/nsf/termbox -# https://wiki.tcl-lang.org/page/UTF%2D8+bit+by+bit explains the algorithm -# -# The day we want to support combining characters, this function will need to -# take multiple code points. Or something. -fn to-grapheme in: code-point -> _/eax: grapheme { - var c/eax: int <- copy in - var num-trailers/ecx: int <- copy 0 - var first/edx: int <- copy 0 - $to-grapheme:compute-length: { - # single byte: just return it - compare c, 0x7f - { - break-if-> - var g/eax: grapheme <- copy c - return g - } - # 2 bytes - compare c, 0x7ff - { - break-if-> - num-trailers <- copy 1 - first <- copy 0xc0 - break $to-grapheme:compute-length - } - # 3 bytes - compare c, 0xffff - { - break-if-> - num-trailers <- copy 2 - first <- copy 0xe0 - break $to-grapheme:compute-length - } - # 4 bytes - compare c, 0x1fffff - { - break-if-> - num-trailers <- copy 3 - first <- copy 0xf0 - break $to-grapheme:compute-length - } - # more than 4 bytes: unsupported - # TODO: print error message to stderr - compare c, 0x1fffff - { - break-if-> - return 0 - } - } - # emit trailer bytes, 6 bits from 'in', first two bits '10' - var result/edi: grapheme <- copy 0 - { - compare num-trailers, 0 - break-if-<= - var tmp/esi: int <- copy c - tmp <- and 0x3f - tmp <- or 0x80 - result <- shift-left 8 - result <- or tmp - # update loop state - c <- shift-right 6 - num-trailers <- decrement - loop - } - # emit engine - result <- shift-left 8 - result <- or c - result <- or first - # - return result -} - -# TODO: bring in tests once we have check-ints-equal - -# read the next grapheme from a stream of bytes -fn read-grapheme in: (addr stream byte) -> _/eax: grapheme { - # if at eof, return EOF - { - var eof?/eax: boolean <- stream-empty? in - compare eof?, 0/false - break-if-= - return 0xffffffff - } - var c/eax: byte <- read-byte in - var num-trailers/ecx: int <- copy 0 - $read-grapheme:compute-length: { - # single byte: just return it - compare c, 0xc0 - { - break-if->= - var g/eax: grapheme <- copy c - return g - } - compare c, 0xfe - { - break-if-< - var g/eax: grapheme <- copy c - return g - } - # 2 bytes - compare c, 0xe0 - { - break-if->= - num-trailers <- copy 1 - break $read-grapheme:compute-length - } - # 3 bytes - compare c, 0xf0 - { - break-if->= - num-trailers <- copy 2 - break $read-grapheme:compute-length - } - # 4 bytes - compare c, 0xf8 - { - break-if->= - num-trailers <- copy 3 - break $read-grapheme:compute-length - } - # TODO: print error message - return 0 - } - # prepend trailer bytes - var result/edi: grapheme <- copy c - var num-byte-shifts/edx: int <- copy 1 - { - compare num-trailers, 0 - break-if-<= - var tmp/eax: byte <- read-byte in - var tmp2/eax: int <- copy tmp - tmp2 <- shift-left-bytes tmp2, num-byte-shifts - result <- or tmp2 - # update loop state - num-byte-shifts <- increment - num-trailers <- decrement - loop - } - return result -} - -# needed because available primitives only shift by a literal/constant number of bits -fn shift-left-bytes n: int, k: int -> _/eax: int { - var i/ecx: int <- copy 0 - var result/eax: int <- copy n - { - compare i, k - break-if->= - compare i, 4 # only 4 bytes in 32 bits - break-if->= - result <- shift-left 8 - i <- increment - loop - } - return result -} - -# write a grapheme to a stream of bytes -# this is like write-to-stream, except we skip leading 0 bytes -fn write-grapheme out: (addr stream byte), g: grapheme { -$write-grapheme:body: { - var c/eax: int <- copy g - append-byte out, c # first byte is always written - c <- shift-right 8 - compare c, 0 - break-if-= $write-grapheme:body - append-byte out, c - c <- shift-right 8 - compare c, 0 - break-if-= $write-grapheme:body - append-byte out, c - c <- shift-right 8 - compare c, 0 - break-if-= $write-grapheme:body - append-byte out, c -} -} diff --git a/baremetal/408float.mu b/baremetal/408float.mu deleted file mode 100644 index d1c04836..00000000 --- a/baremetal/408float.mu +++ /dev/null @@ -1,23 +0,0 @@ -# Some quick-n-dirty ways to create floats. - -fn fill-in-rational _out: (addr float), nr: int, dr: int { - var out/edi: (addr float) <- copy _out - var result/xmm0: float <- convert nr - var divisor/xmm1: float <- convert dr - result <- divide divisor - copy-to *out, result -} - -fn fill-in-sqrt _out: (addr float), n: int { - var out/edi: (addr float) <- copy _out - var result/xmm0: float <- convert n - result <- square-root result - copy-to *out, result -} - -fn rational nr: int, dr: int -> _/xmm0: float { - var result/xmm0: float <- convert nr - var divisor/xmm1: float <- convert dr - result <- divide divisor - return result -} diff --git a/baremetal/411string.mu b/baremetal/411string.mu deleted file mode 100644 index cf0471ac..00000000 --- a/baremetal/411string.mu +++ /dev/null @@ -1,125 +0,0 @@ -# read up to 'len' graphemes after skipping the first 'start' ones -fn substring in: (addr array byte), start: int, len: int, out-ah: (addr handle array byte) { - var in-stream: (stream byte 0x100) - var in-stream-addr/esi: (addr stream byte) <- address in-stream - write in-stream-addr, in - var out-stream: (stream byte 0x100) - var out-stream-addr/edi: (addr stream byte) <- address out-stream - $substring:core: { - # skip 'start' graphemes - var i/eax: int <- copy 0 - { - compare i, start - break-if->= - { - var dummy/eax: grapheme <- read-grapheme in-stream-addr - compare dummy, 0xffffffff/end-of-file - break-if-= $substring:core - } - i <- increment - loop - } - # copy 'len' graphemes - i <- copy 0 - { - compare i, len - break-if->= - { - var g/eax: grapheme <- read-grapheme in-stream-addr - compare g, 0xffffffff/end-of-file - break-if-= $substring:core - write-grapheme out-stream-addr, g - } - i <- increment - loop - } - } - stream-to-array out-stream-addr, out-ah -} - -fn test-substring { - var out-h: (handle array byte) - var out-ah/edi: (addr handle array byte) <- address out-h - # prefix substrings - substring 0, 0, 3, out-ah - var out/eax: (addr array byte) <- lookup *out-ah - check-strings-equal out, "", "F - test-substring/null" - substring "", 0, 3, out-ah - var out/eax: (addr array byte) <- lookup *out-ah -#? print-string-to-real-screen out -#? print-string-to-real-screen "\n" - check-strings-equal out, "", "F - test-substring/empty" - # - substring "abcde", 0, 3, out-ah - var out/eax: (addr array byte) <- lookup *out-ah -#? print-string-to-real-screen out -#? print-string-to-real-screen "\n" - check-strings-equal out, "abc", "F - test-substring/truncate" - # - substring "abcde", 0, 5, out-ah - var out/eax: (addr array byte) <- lookup *out-ah - check-strings-equal out, "abcde", "F - test-substring/all" - # - substring "abcde", 0, 7, out-ah - var out/eax: (addr array byte) <- lookup *out-ah - check-strings-equal out, "abcde", "F - test-substring/too-small" - # substrings outside string - substring "abcde", 6, 1, out-ah - var out/eax: (addr array byte) <- lookup *out-ah - check-strings-equal out, "", "F - test-substring/start-too-large" - # trim prefix - substring "", 2, 3, out-ah - var out/eax: (addr array byte) <- lookup *out-ah - check-strings-equal out, "", "F - test-substring/middle-empty" - # - substring "abcde", 1, 2, out-ah - var out/eax: (addr array byte) <- lookup *out-ah - check-strings-equal out, "bc", "F - test-substring/middle-truncate" - # - substring "abcde", 1, 4, out-ah - var out/eax: (addr array byte) <- lookup *out-ah - check-strings-equal out, "bcde", "F - test-substring/middle-all" - # - substring "abcde", 1, 5, out-ah - var out/eax: (addr array byte) <- lookup *out-ah - check-strings-equal out, "bcde", "F - test-substring/middle-too-small" -} - -fn split-string in: (addr array byte), delim: grapheme, out: (addr handle array (handle array byte)) { - var in-stream: (stream byte 0x100) - var in-stream-addr/esi: (addr stream byte) <- address in-stream - write in-stream-addr, in - var tokens-stream: (stream (handle array byte) 0x100) - var tokens-stream-addr/edi: (addr stream (handle array byte)) <- address tokens-stream - var curr-stream: (stream byte 0x100) - var curr-stream-addr/ecx: (addr stream byte) <- address curr-stream - $split-string:core: { - var g/eax: grapheme <- read-grapheme in-stream-addr - compare g, 0xffffffff - break-if-= -#? print-grapheme-to-real-screen g -#? print-string-to-real-screen "\n" - compare g, delim - { - break-if-!= - # token complete; flush - var token: (handle array byte) - var token-ah/eax: (addr handle array byte) <- address token - stream-to-array curr-stream-addr, token-ah - write-to-stream tokens-stream-addr, token-ah - clear-stream curr-stream-addr - loop $split-string:core - } - write-grapheme curr-stream-addr, g - loop - } - stream-to-array tokens-stream-addr, out -} - -fn test-split-string { - var out-h: (handle array (handle array byte)) - var out-ah/edi: (addr handle array (handle array byte)) <- address out-h - # prefix substrings - split-string "bab", 0x61, out-ah - # no crash -} diff --git a/baremetal/412render-float-decimal.mu b/baremetal/412render-float-decimal.mu deleted file mode 100644 index 7aaf8b3a..00000000 --- a/baremetal/412render-float-decimal.mu +++ /dev/null @@ -1,597 +0,0 @@ -# print out floats in decimal -# https://research.swtch.com/ftoa -# -# Basic idea: -# Ignoring sign, floating point numbers are represented as 1.mantissa * 2^exponent -# Therefore, to print a float in decimal, we need to: -# - compute its value without decimal point -# - convert to an array of decimal digits -# - print out the array while inserting the decimal point appropriately -# -# Basic complication: the computation generates numbers larger than an int can -# hold. We need a way to represent big ints. -# -# Key insight: use a representation for big ints that's close to what we need -# anyway, an array of decimal digits. -# -# Style note: we aren't creating a big int library here. The only operations -# we need are halving and doubling. Following the link above, it seems more -# comprehensible to keep these operations inlined so that we can track the -# position of the decimal point with dispatch. -# -# This approach turns out to be fast enough for most purposes. -# Optimizations, however, get wildly more complex. - -fn test-write-float-decimal-approximate-normal { - var s-storage: (stream byte 0x10) - var s/ecx: (addr stream byte) <- address s-storage - # 0.5 - var half/xmm0: float <- rational 1, 2 - write-float-decimal-approximate s, half, 3 - check-stream-equal s, "0.5", "F - test-write-float-decimal-approximate-normal 0.5" - # 0.25 - clear-stream s - var quarter/xmm0: float <- rational 1, 4 - write-float-decimal-approximate s, quarter, 3 - check-stream-equal s, "0.25", "F - test-write-float-decimal-approximate-normal 0.25" - # 0.75 - clear-stream s - var three-quarters/xmm0: float <- rational 3, 4 - write-float-decimal-approximate s, three-quarters, 3 - check-stream-equal s, "0.75", "F - test-write-float-decimal-approximate-normal 0.75" - # 0.125 - clear-stream s - var eighth/xmm0: float <- rational 1, 8 - write-float-decimal-approximate s, eighth, 3 - check-stream-equal s, "0.125", "F - test-write-float-decimal-approximate-normal 0.125" - # 0.0625; start using scientific notation - clear-stream s - var sixteenth/xmm0: float <- rational 1, 0x10 - write-float-decimal-approximate s, sixteenth, 3 - check-stream-equal s, "6.25e-2", "F - test-write-float-decimal-approximate-normal 0.0625" - # sqrt(2); truncate floats with lots of digits after the decimal but not too many before - clear-stream s - var two-f/xmm0: float <- rational 2, 1 - var sqrt-2/xmm0: float <- square-root two-f - write-float-decimal-approximate s, sqrt-2, 3 - check-stream-equal s, "1.414", "F - test-write-float-decimal-approximate-normal √2" -} - -# print whole integers without decimals -fn test-write-float-decimal-approximate-integer { - var s-storage: (stream byte 0x10) - var s/ecx: (addr stream byte) <- address s-storage - # 1 - var one-f/xmm0: float <- rational 1, 1 - write-float-decimal-approximate s, one-f, 3 - check-stream-equal s, "1", "F - test-write-float-decimal-approximate-integer 1" - # 2 - clear-stream s - var two-f/xmm0: float <- rational 2, 1 - write-float-decimal-approximate s, two-f, 3 - check-stream-equal s, "2", "F - test-write-float-decimal-approximate-integer 2" - # 10 - clear-stream s - var ten-f/xmm0: float <- rational 0xa, 1 - write-float-decimal-approximate s, ten-f, 3 - check-stream-equal s, "10", "F - test-write-float-decimal-approximate-integer 10" - # -10 - clear-stream s - var minus-ten-f/xmm0: float <- rational -0xa, 1 - write-float-decimal-approximate s, minus-ten-f, 3 - check-stream-equal s, "-10", "F - test-write-float-decimal-approximate-integer -10" - # 999 - clear-stream s - var minus-ten-f/xmm0: float <- rational 0x3e7, 1 - write-float-decimal-approximate s, minus-ten-f, 3 - check-stream-equal s, "999", "F - test-write-float-decimal-approximate-integer 1000" - # 1000 - start using scientific notation - clear-stream s - var minus-ten-f/xmm0: float <- rational 0x3e8, 1 - write-float-decimal-approximate s, minus-ten-f, 3 - check-stream-equal s, "1.00e3", "F - test-write-float-decimal-approximate-integer 1000" - # 100,000 - clear-stream s - var hundred-thousand/eax: int <- copy 0x186a0 - var hundred-thousand-f/xmm0: float <- convert hundred-thousand - write-float-decimal-approximate s, hundred-thousand-f, 3 - check-stream-equal s, "1.00e5", "F - test-write-float-decimal-approximate-integer 100,000" -} - -fn test-write-float-decimal-approximate-zero { - var s-storage: (stream byte 0x10) - var s/ecx: (addr stream byte) <- address s-storage - var zero: float - write-float-decimal-approximate s, zero, 3 - check-stream-equal s, "0", "F - test-write-float-decimal-approximate-zero" -} - -fn test-write-float-decimal-approximate-negative-zero { - var s-storage: (stream byte 0x10) - var s/ecx: (addr stream byte) <- address s-storage - var n: int - copy-to n, 0x80000000 - var negative-zero/xmm0: float <- reinterpret n - write-float-decimal-approximate s, negative-zero, 3 - check-stream-equal s, "-0", "F - test-write-float-decimal-approximate-negative-zero" -} - -fn test-write-float-decimal-approximate-infinity { - var s-storage: (stream byte 0x10) - var s/ecx: (addr stream byte) <- address s-storage - var n: int - # 0|11111111|00000000000000000000000 - # 0111|1111|1000|0000|0000|0000|0000|0000 - copy-to n, 0x7f800000 - var infinity/xmm0: float <- reinterpret n - write-float-decimal-approximate s, infinity, 3 - check-stream-equal s, "Inf", "F - test-write-float-decimal-approximate-infinity" -} - -fn test-write-float-decimal-approximate-negative-infinity { - var s-storage: (stream byte 0x10) - var s/ecx: (addr stream byte) <- address s-storage - var n: int - copy-to n, 0xff800000 - var negative-infinity/xmm0: float <- reinterpret n - write-float-decimal-approximate s, negative-infinity, 3 - check-stream-equal s, "-Inf", "F - test-write-float-decimal-approximate-negative-infinity" -} - -fn test-write-float-decimal-approximate-not-a-number { - var s-storage: (stream byte 0x10) - var s/ecx: (addr stream byte) <- address s-storage - var n: int - copy-to n, 0xffffffff # exponent must be all 1's, and mantissa must be non-zero - var nan/xmm0: float <- reinterpret n - write-float-decimal-approximate s, nan, 3 - check-stream-equal s, "NaN", "F - test-write-float-decimal-approximate-not-a-number" -} - -fn render-float-decimal screen: (addr screen), in: float, precision: int, x: int, y: int, color: int, background-color: int -> _/eax: int { - var s-storage: (stream byte 0x10) - var s/esi: (addr stream byte) <- address s-storage - write-float-decimal-approximate s, in, precision - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size screen - var result/eax: int <- draw-stream-rightward screen, s, x, width, y, color, background-color - return result -} - -# 'precision' controls the maximum width past which we resort to scientific notation -fn write-float-decimal-approximate out: (addr stream byte), in: float, precision: int { - # - special names - var bits/eax: int <- reinterpret in - compare bits, 0 - { - break-if-!= - write out, "0" - return - } - compare bits, 0x80000000 - { - break-if-!= - write out, "-0" - return - } - compare bits, 0x7f800000 - { - break-if-!= - write out, "Inf" - return - } - compare bits, 0xff800000 - { - break-if-!= - write out, "-Inf" - return - } - var exponent/ecx: int <- copy bits - exponent <- shift-right 0x17 # 23 bits of mantissa - exponent <- and 0xff - exponent <- subtract 0x7f - compare exponent, 0x80 - { - break-if-!= - write out, "NaN" - return - } - # - regular numbers - var sign/edx: int <- copy bits - sign <- shift-right 0x1f - { - compare sign, 1 - break-if-!= - append-byte out, 0x2d/minus - } - - # v = 1.mantissa (in base 2) << 0x17 - var v/ebx: int <- copy bits - v <- and 0x7fffff - v <- or 0x00800000 # insert implicit 1 - # e = exponent - 0x17 - var e/ecx: int <- copy exponent - e <- subtract 0x17 # move decimal place from before mantissa to after - - # initialize buffer with decimal representation of v - # unlike https://research.swtch.com/ftoa, no ascii here - var buf-storage: (array byte 0x7f) - var buf/edi: (addr array byte) <- address buf-storage - var n/eax: int <- decimal-digits v, buf - # I suspect we can do without reversing, but we'll follow https://research.swtch.com/ftoa - # closely for now. - reverse-digits buf, n - - # loop if e > 0 - { - compare e, 0 - break-if-<= - n <- double-array-of-decimal-digits buf, n - e <- decrement - loop - } - - var dp/edx: int <- copy n - - # loop if e < 0 - { - compare e, 0 - break-if->= - n, dp <- halve-array-of-decimal-digits buf, n, dp - e <- increment - loop - } - - _write-float-array-of-decimal-digits out, buf, n, dp, precision -} - -# store the decimal digits of 'n' into 'buf', units first -# n must be positive -fn decimal-digits n: int, _buf: (addr array byte) -> _/eax: int { - var buf/edi: (addr array byte) <- copy _buf - var i/ecx: int <- copy 0 - var curr/eax: int <- copy n - var curr-byte/edx: int <- copy 0 - { - compare curr, 0 - break-if-= - curr, curr-byte <- integer-divide curr, 0xa - var dest/ebx: (addr byte) <- index buf, i - copy-byte-to *dest, curr-byte - i <- increment - loop - } - return i -} - -fn reverse-digits _buf: (addr array byte), n: int { - var buf/esi: (addr array byte) <- copy _buf - var left/ecx: int <- copy 0 - var right/edx: int <- copy n - right <- decrement - { - compare left, right - break-if->= - { - var l-a/ecx: (addr byte) <- index buf, left - var r-a/edx: (addr byte) <- index buf, right - var l/ebx: byte <- copy-byte *l-a - var r/eax: byte <- copy-byte *r-a - copy-byte-to *l-a, r - copy-byte-to *r-a, l - } - left <- increment - right <- decrement - loop - } -} - -fn double-array-of-decimal-digits _buf: (addr array byte), _n: int -> _/eax: int { - var buf/edi: (addr array byte) <- copy _buf - # initialize delta - var delta/edx: int <- copy 0 - { - var curr/ebx: (addr byte) <- index buf, 0 - var tmp/eax: byte <- copy-byte *curr - compare tmp, 5 - break-if-< - delta <- copy 1 - } - # loop - var x/eax: int <- copy 0 - var i/ecx: int <- copy _n - i <- decrement - { - compare i, 0 - break-if-<= - # x += 2*buf[i] - { - var tmp/ecx: (addr byte) <- index buf, i - var tmp2/ecx: byte <- copy-byte *tmp - x <- add tmp2 - x <- add tmp2 - } - # x, buf[i+delta] = x/10, x%10 - { - var dest-index/ecx: int <- copy i - dest-index <- add delta - var dest/edi: (addr byte) <- index buf, dest-index - var next-digit/edx: int <- copy 0 - x, next-digit <- integer-divide x, 0xa - copy-byte-to *dest, next-digit - } - # - i <- decrement - loop - } - # final patch-up - var n/eax: int <- copy _n - compare delta, 1 - { - break-if-!= - var curr/ebx: (addr byte) <- index buf, 0 - var one/edx: int <- copy 1 - copy-byte-to *curr, one - n <- increment - } - return n -} - -fn halve-array-of-decimal-digits _buf: (addr array byte), _n: int, _dp: int -> _/eax: int, _/edx: int { - var buf/edi: (addr array byte) <- copy _buf - var n/eax: int <- copy _n - var dp/edx: int <- copy _dp - # initialize one side - { - # if buf[n-1]%2 == 0, break - var right-index/ecx: int <- copy n - right-index <- decrement - var right-a/ecx: (addr byte) <- index buf, right-index - var right/ecx: byte <- copy-byte *right-a - var right-int/ecx: int <- copy right - var remainder/edx: int <- copy 0 - { - var dummy/eax: int <- copy 0 - dummy, remainder <- integer-divide right-int, 2 - } - compare remainder, 0 - break-if-= - # buf[n] = 0 - var next-a/ecx: (addr byte) <- index buf, n - var zero/edx: byte <- copy 0 - copy-byte-to *next-a, zero - # n++ - n <- increment - } - # initialize the other - var delta/ebx: int <- copy 0 - var x/esi: int <- copy 0 - { - # if buf[0] >= 2, break - var left/ecx: (addr byte) <- index buf, 0 - var src/ecx: byte <- copy-byte *left - compare src, 2 - break-if->= - # delta, x = 1, buf[0] - delta <- copy 1 - x <- copy src - # n-- - n <- decrement - # dp-- - dp <- decrement - } - # loop - var i/ecx: int <- copy 0 - { - compare i, n - break-if->= - # x = x*10 + buf[i+delta] - { - var ten/edx: int <- copy 0xa - x <- multiply ten - var src-index/edx: int <- copy i - src-index <- add delta - var src-a/edx: (addr byte) <- index buf, src-index - var src/edx: byte <- copy-byte *src-a - x <- add src - } - # buf[i], x = x/2, x%2 - { - var quotient/eax: int <- copy 0 - var remainder/edx: int <- copy 0 - quotient, remainder <- integer-divide x, 2 - x <- copy remainder - var dest/edx: (addr byte) <- index buf, i - copy-byte-to *dest, quotient - } - # - i <- increment - loop - } - return n, dp -} - -fn _write-float-array-of-decimal-digits out: (addr stream byte), _buf: (addr array byte), n: int, dp: int, precision: int { - var buf/edi: (addr array byte) <- copy _buf - { - compare dp, 0 - break-if->= - _write-float-array-of-decimal-digits-in-scientific-notation out, buf, n, dp, precision - return - } - { - var dp2/eax: int <- copy dp - compare dp2, precision - break-if-<= - _write-float-array-of-decimal-digits-in-scientific-notation out, buf, n, dp, precision - return - } - { - compare dp, 0 - break-if-!= - append-byte out, 0x30/0 - } - var i/eax: int <- copy 0 - # bounds = min(n, dp+3) - var limit/edx: int <- copy dp - limit <- add 3 - { - compare limit, n - break-if-<= - limit <- copy n - } - { - compare i, limit - break-if->= - # print '.' if necessary - compare i, dp - { - break-if-!= - append-byte out, 0x2e/decimal-point - } - var curr-a/ecx: (addr byte) <- index buf, i - var curr/ecx: byte <- copy-byte *curr-a - var curr-int/ecx: int <- copy curr - curr-int <- add 0x30/0 - append-byte out, curr-int - # - i <- increment - loop - } -} - -fn _write-float-array-of-decimal-digits-in-scientific-notation out: (addr stream byte), _buf: (addr array byte), n: int, dp: int, precision: int { - var buf/edi: (addr array byte) <- copy _buf - var i/eax: int <- copy 0 - { - compare i, n - break-if->= - compare i, precision - break-if->= - compare i, 1 - { - break-if-!= - append-byte out, 0x2e/decimal-point - } - var curr-a/ecx: (addr byte) <- index buf, i - var curr/ecx: byte <- copy-byte *curr-a - var curr-int/ecx: int <- copy curr - curr-int <- add 0x30/0 - append-byte out, curr-int - # - i <- increment - loop - } - append-byte out, 0x65/e - decrement dp - write-int32-decimal out, dp -} - -# follows the structure of write-float-decimal-approximate -# 'precision' controls the maximum width past which we resort to scientific notation -fn float-size in: float, precision: int -> _/eax: int { - # - special names - var bits/eax: int <- reinterpret in - compare bits, 0 - { - break-if-!= - return 1 # for "0" - } - compare bits, 0x80000000 - { - break-if-!= - return 2 # for "-0" - } - compare bits, 0x7f800000 - { - break-if-!= - return 3 # for "Inf" - } - compare bits, 0xff800000 - { - break-if-!= - return 4 # for "-Inf" - } - var exponent/ecx: int <- copy bits - exponent <- shift-right 0x17 # 23 bits of mantissa - exponent <- and 0xff - exponent <- subtract 0x7f - compare exponent, 0x80 - { - break-if-!= - return 3 # for "NaN" - } - # - regular numbers - # v = 1.mantissa (in base 2) << 0x17 - var v/ebx: int <- copy bits - v <- and 0x7fffff - v <- or 0x00800000 # insert implicit 1 - # e = exponent - 0x17 - var e/ecx: int <- copy exponent - e <- subtract 0x17 # move decimal place from before mantissa to after - - # initialize buffer with decimal representation of v - var buf-storage: (array byte 0x7f) - var buf/edi: (addr array byte) <- address buf-storage - var n/eax: int <- decimal-digits v, buf - reverse-digits buf, n - - # loop if e > 0 - { - compare e, 0 - break-if-<= - n <- double-array-of-decimal-digits buf, n - e <- decrement - loop - } - - var dp/edx: int <- copy n - - # loop if e < 0 - { - compare e, 0 - break-if->= - n, dp <- halve-array-of-decimal-digits buf, n, dp - e <- increment - loop - } - - compare dp, 0 - { - break-if->= - return 8 # hacky for scientific notation - } - { - var dp2/eax: int <- copy dp - compare dp2, precision - break-if-<= - return 8 # hacky for scientific notation - } - - # result = min(n, dp+3) - var result/ecx: int <- copy dp - result <- add 3 - { - compare result, n - break-if-<= - result <- copy n - } - - # account for decimal point - compare dp, n - { - break-if->= - result <- increment - } - - # account for sign - var sign/edx: int <- reinterpret in - sign <- shift-right 0x1f - { - compare sign, 1 - break-if-!= - result <- increment - } - return result -} diff --git a/baremetal/500text-screen.mu b/baremetal/500text-screen.mu deleted file mode 100644 index a764aa06..00000000 --- a/baremetal/500text-screen.mu +++ /dev/null @@ -1,298 +0,0 @@ -# Testable primitives for writing text to screen. -# (Mu doesn't yet have testable primitives for graphics.) -# -# Unlike the top-level, this text mode has no scrolling. - -# coordinates here don't match top-level -# Here we're consistent with graphics mode. Top-level is consistent with -# terminal emulators. -type screen { - width: int - height: int - data: (handle array screen-cell) - cursor-x: int - cursor-y: int -} - -type screen-cell { - data: grapheme - color: int - background-color: int -} - -fn initialize-screen screen: (addr screen), width: int, height: int { - var screen-addr/esi: (addr screen) <- copy screen - var tmp/eax: int <- copy 0 - var dest/edi: (addr int) <- copy 0 - # screen->width = width - dest <- get screen-addr, width - tmp <- copy width - copy-to *dest, tmp - # screen->height = height - dest <- get screen-addr, height - tmp <- copy height - copy-to *dest, tmp - # screen->data = new screen-cell[width*height] - { - var data-addr/edi: (addr handle array screen-cell) <- get screen-addr, data - tmp <- multiply width - populate data-addr, tmp - } - # screen->cursor-x = 0 - dest <- get screen-addr, cursor-x - copy-to *dest, 0 - # screen->cursor-y = 0 - dest <- get screen-addr, cursor-y - copy-to *dest, 0 -} - -# in graphemes -fn screen-size screen: (addr screen) -> _/eax: int, _/ecx: int { - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - compare screen, 0 - { - break-if-!= - return 0x80/128, 0x30/48 - } - # fake screen - var screen-addr/esi: (addr screen) <- copy screen - var tmp/edx: (addr int) <- get screen-addr, width - width <- copy *tmp - tmp <- get screen-addr, height - height <- copy *tmp - return width, height -} - -# testable screen primitive -fn draw-grapheme screen: (addr screen), g: grapheme, x: int, y: int, color: int, background-color: int { - { - compare screen, 0 - break-if-!= - draw-grapheme-on-real-screen g, x, y, color, background-color - return - } - # fake screen - var screen-addr/esi: (addr screen) <- copy screen - var idx/ecx: int <- screen-cell-index screen-addr, x, y - var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data - var data/eax: (addr array screen-cell) <- lookup *data-ah - var offset/ecx: (offset screen-cell) <- compute-offset data, idx - var dest-cell/ecx: (addr screen-cell) <- index data, offset - var dest-grapheme/eax: (addr grapheme) <- get dest-cell, data - var g2/edx: grapheme <- copy g - copy-to *dest-grapheme, g2 - var dest-color/eax: (addr int) <- get dest-cell, color - var src-color/edx: int <- copy color - copy-to *dest-color, src-color - dest-color <- get dest-cell, background-color - src-color <- copy background-color - copy-to *dest-color, src-color -} - -# we can't really render non-ASCII yet, but when we do we'll be ready -fn draw-code-point screen: (addr screen), c: code-point, x: int, y: int, color: int, background-color: int { - var g/eax: grapheme <- copy c - draw-grapheme screen, g, x, y, color, background-color -} - -# not really needed for a real screen, though it shouldn't do any harm -fn screen-cell-index screen-on-stack: (addr screen), x: int, y: int -> _/ecx: int { - var screen/esi: (addr screen) <- copy screen-on-stack - # only one bounds check isn't automatically handled - { - var xmax/eax: (addr int) <- get screen, width - var xcurr/ecx: int <- copy x - compare xcurr, *xmax - break-if-< - abort "tried to print out of screen bounds" - } - var width-addr/eax: (addr int) <- get screen, width - var result/ecx: int <- copy y - result <- multiply *width-addr - result <- add x - return result -} - -fn cursor-position screen: (addr screen) -> _/eax: int, _/ecx: int { - { - compare screen, 0 - break-if-!= - var x/eax: int <- copy 0 - var y/ecx: int <- copy 0 - x, y <- cursor-position-on-real-screen - return x, y - } - # fake screen - var screen-addr/esi: (addr screen) <- copy screen - var cursor-x-addr/eax: (addr int) <- get screen-addr, cursor-x - var cursor-y-addr/ecx: (addr int) <- get screen-addr, cursor-y - return *cursor-x-addr, *cursor-y-addr -} - -fn set-cursor-position screen: (addr screen), x: int, y: int { - { - compare screen, 0 - break-if-!= - set-cursor-position-on-real-screen x, y - return - } - # fake screen - var screen-addr/esi: (addr screen) <- copy screen - # ignore x < 0 - { - compare x, 0 - break-if->= - return - } - # ignore x >= width - { - var width-addr/eax: (addr int) <- get screen-addr, width - var width/eax: int <- copy *width-addr - compare x, width - break-if-<= - return - } - # ignore y < 0 - { - compare y, 0 - break-if->= - return - } - # ignore y >= height - { - var height-addr/eax: (addr int) <- get screen-addr, height - var height/eax: int <- copy *height-addr - compare y, height - break-if-< - return - } - # screen->cursor-x = x - var dest/edi: (addr int) <- get screen-addr, cursor-x - var src/eax: int <- copy x - copy-to *dest, src - # screen->cursor-y = y - dest <- get screen-addr, cursor-y - src <- copy y - copy-to *dest, src -} - -fn show-cursor screen: (addr screen), g: grapheme { - { - compare screen, 0 - break-if-!= - show-cursor-on-real-screen g - return - } - # fake screen - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - draw-grapheme screen, g, cursor-x, cursor-y, 0/fg, 7/bg -} - -fn clear-screen screen: (addr screen) { - { - compare screen, 0 - break-if-!= - clear-real-screen - return - } - # fake screen - set-cursor-position screen, 0, 0 - var screen-addr/esi: (addr screen) <- copy screen - var y/eax: int <- copy 0 - var height/ecx: (addr int) <- get screen-addr, height - { - compare y, *height - break-if->= - var x/edx: int <- copy 0 - var width/ebx: (addr int) <- get screen-addr, width - { - compare x, *width - break-if->= - draw-code-point screen, 0x20/space, x, y, 0/fg=black, 0/bg=black - x <- increment - loop - } - y <- increment - loop - } - set-cursor-position screen, 0, 0 -} - -# there's no grapheme that guarantees to cover every pixel, so we'll bump down -# to pixels for a real screen -fn clear-real-screen { - var y/eax: int <- copy 0 - { - compare y, 0x300/screen-height=768 - break-if->= - var x/edx: int <- copy 0 - { - compare x, 0x400/screen-width=1024 - break-if->= - pixel-on-real-screen x, y, 0/color=black - x <- increment - loop - } - y <- increment - loop - } -} - -fn screen-grapheme-at screen-on-stack: (addr screen), x: int, y: int -> _/eax: grapheme { - var screen-addr/esi: (addr screen) <- copy screen-on-stack - var idx/ecx: int <- screen-cell-index screen-addr, x, y - var result/eax: grapheme <- screen-grapheme-at-idx screen-addr, idx - return result -} - -fn screen-grapheme-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> _/eax: grapheme { - var screen-addr/esi: (addr screen) <- copy screen-on-stack - var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data - var data/eax: (addr array screen-cell) <- lookup *data-ah - var idx/ecx: int <- copy idx-on-stack - var offset/ecx: (offset screen-cell) <- compute-offset data, idx - var cell/eax: (addr screen-cell) <- index data, offset - var src/eax: (addr grapheme) <- get cell, data - return *src -} - -fn screen-color-at screen-on-stack: (addr screen), x: int, y: int -> _/eax: int { - var screen-addr/esi: (addr screen) <- copy screen-on-stack - var idx/ecx: int <- screen-cell-index screen-addr, x, y - var result/eax: int <- screen-color-at-idx screen-addr, idx - return result -} - -fn screen-color-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> _/eax: int { - var screen-addr/esi: (addr screen) <- copy screen-on-stack - var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data - var data/eax: (addr array screen-cell) <- lookup *data-ah - var idx/ecx: int <- copy idx-on-stack - var offset/ecx: (offset screen-cell) <- compute-offset data, idx - var cell/eax: (addr screen-cell) <- index data, offset - var src/eax: (addr int) <- get cell, color - var result/eax: int <- copy *src - return result -} - -fn screen-background-color-at screen-on-stack: (addr screen), x: int, y: int -> _/eax: int { - var screen-addr/esi: (addr screen) <- copy screen-on-stack - var idx/ecx: int <- screen-cell-index screen-addr, x, y - var result/eax: int <- screen-background-color-at-idx screen-addr, idx - return result -} - -fn screen-background-color-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> _/eax: int { - var screen-addr/esi: (addr screen) <- copy screen-on-stack - var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data - var data/eax: (addr array screen-cell) <- lookup *data-ah - var idx/ecx: int <- copy idx-on-stack - var offset/ecx: (offset screen-cell) <- compute-offset data, idx - var cell/eax: (addr screen-cell) <- index data, offset - var src/eax: (addr int) <- get cell, background-color - var result/eax: int <- copy *src - return result -} diff --git a/baremetal/501draw-text.mu b/baremetal/501draw-text.mu deleted file mode 100644 index 9b207361..00000000 --- a/baremetal/501draw-text.mu +++ /dev/null @@ -1,466 +0,0 @@ -# some primitives for moving the cursor without making assumptions about -# raster order -fn move-cursor-left screen: (addr screen) { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - compare cursor-x, 0 - { - break-if-> - return - } - cursor-x <- decrement - set-cursor-position screen, cursor-x, cursor-y -} - -fn move-cursor-right screen: (addr screen) { - var _width/eax: int <- copy 0 - var dummy/ecx: int <- copy 0 - _width, dummy <- screen-size screen - var limit/edx: int <- copy _width - limit <- decrement - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - compare cursor-x, limit - { - break-if-< - return - } - cursor-x <- increment - set-cursor-position screen, cursor-x, cursor-y -} - -fn move-cursor-up screen: (addr screen) { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - compare cursor-y, 0 - { - break-if-> - return - } - cursor-y <- decrement - set-cursor-position screen, cursor-x, cursor-y -} - -fn move-cursor-down screen: (addr screen) { - var dummy/eax: int <- copy 0 - var _height/ecx: int <- copy 0 - dummy, _height <- screen-size screen - var limit/edx: int <- copy _height - limit <- decrement - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - compare cursor-y, limit - { - break-if-< - return - } - cursor-y <- increment - set-cursor-position screen, cursor-x, cursor-y -} - -fn move-cursor-to-start-of-next-line screen: (addr screen) { - var dummy/eax: int <- copy 0 - var _height/ecx: int <- copy 0 - dummy, _height <- screen-size screen - var limit/edx: int <- copy _height - limit <- decrement - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - compare cursor-y, limit - { - break-if-< - return - } - cursor-y <- increment - cursor-x <- copy 0 - set-cursor-position screen, cursor-x, cursor-y -} - -fn draw-grapheme-at-cursor screen: (addr screen), g: grapheme, color: int, background-color: int { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - draw-grapheme screen, g, cursor-x, cursor-y, color, background-color -} - -# we can't really render non-ASCII yet, but when we do we'll be ready -fn draw-code-point-at-cursor screen: (addr screen), c: code-point, color: int, background-color: int { - var g/eax: grapheme <- copy c - draw-grapheme-at-cursor screen, g, color, background-color -} - -# draw a single line of text from x, y to xmax -# return the next 'x' coordinate -# if there isn't enough space, truncate -fn draw-text-rightward screen: (addr screen), text: (addr array byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int { - var stream-storage: (stream byte 0x100) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, text - var xcurr/eax: int <- draw-stream-rightward screen, stream, x, xmax, y, color, background-color - return xcurr -} - -# draw a single-line stream from x, y to xmax -# return the next 'x' coordinate -# if there isn't enough space, truncate -fn draw-stream-rightward screen: (addr screen), stream: (addr stream byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int { - var xcurr/ecx: int <- copy x - { - var g/eax: grapheme <- read-grapheme stream - compare g, 0xffffffff/end-of-file - break-if-= - draw-grapheme screen, g, xcurr, y, color, background-color - xcurr <- increment - loop - } - set-cursor-position screen, xcurr, y - return xcurr -} - -fn draw-text-rightward-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int { - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size screen - var result/eax: int <- draw-text-rightward screen, text, x, width, y, color, background-color - return result -} - -fn draw-text-rightward-from-cursor screen: (addr screen), text: (addr array byte), xmax: int, color: int, background-color: int { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - cursor-x <- draw-text-rightward screen, text, cursor-x, xmax, cursor-y, color, background-color - set-cursor-position screen, cursor-x, cursor-y -} - -fn render-grapheme screen: (addr screen), g: grapheme, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - compare g, 0xa/newline - var x/eax: int <- copy x - { - break-if-!= - # minimum effort to clear cursor - draw-code-point screen, 0x20/space, x, y, color, background-color - x <- copy xmin - increment y - return x, y - } - draw-grapheme screen, g, x, y, color, background-color - x <- increment - compare x, xmax - { - break-if-< - x <- copy xmin - increment y - } - return x, y -} - -# draw text in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary -# return the next (x, y) coordinate in raster order where drawing stopped -# that way the caller can draw more if given the same min and max bounding-box. -# if there isn't enough space, truncate -fn draw-text-wrapping-right-then-down screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var stream-storage: (stream byte 0x100) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, text - var x/eax: int <- copy _x - var y/ecx: int <- copy _y - x, y <- draw-stream-wrapping-right-then-down screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color - return x, y -} - -# draw a stream in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary -# return the next (x, y) coordinate in raster order where drawing stopped -# that way the caller can draw more if given the same min and max bounding-box. -# if there isn't enough space, truncate -fn draw-stream-wrapping-right-then-down screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var xcurr/eax: int <- copy x - var ycurr/ecx: int <- copy y - var g/ebx: grapheme <- copy 0 - { - { - var _g/eax: grapheme <- read-grapheme stream - g <- copy _g - } - compare g, 0xffffffff/end-of-file - break-if-= - xcurr, ycurr <- render-grapheme screen, g, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color - loop - } - set-cursor-position screen, xcurr, ycurr - return xcurr, ycurr -} - -fn move-cursor-rightward-and-downward screen: (addr screen), xmin: int, xmax: int { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - cursor-x <- increment - compare cursor-x, xmax - { - break-if-< - cursor-x <- copy xmin - cursor-y <- increment - } - set-cursor-position screen, cursor-x, cursor-y -} - -fn draw-text-wrapping-right-then-down-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var x2/eax: int <- copy 0 - var y2/ecx: int <- copy 0 - x2, y2 <- screen-size screen # width, height - x2, y2 <- draw-text-wrapping-right-then-down screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color - return x2, y2 # cursor-x, cursor-y -} - -fn draw-text-wrapping-right-then-down-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - var end-x/edx: int <- copy cursor-x - end-x <- increment - compare end-x, xmax - { - break-if-< - cursor-x <- copy xmin - cursor-y <- increment - } - cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color -} - -fn draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int { - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size screen - draw-text-wrapping-right-then-down-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color -} - -fn draw-int32-hex-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var stream-storage: (stream byte 0x100) - var stream/esi: (addr stream byte) <- address stream-storage - write-int32-hex stream, n - var xcurr/edx: int <- copy x - var ycurr/ecx: int <- copy y - { - var g/eax: grapheme <- read-grapheme stream - compare g, 0xffffffff/end-of-file - break-if-= - draw-grapheme screen, g, xcurr, ycurr, color, background-color - xcurr <- increment - compare xcurr, xmax - { - break-if-< - xcurr <- copy xmin - ycurr <- increment - } - loop - } - set-cursor-position screen, xcurr, ycurr - return xcurr, ycurr -} - -fn draw-int32-hex-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var x2/eax: int <- copy 0 - var y2/ecx: int <- copy 0 - x2, y2 <- screen-size screen # width, height - x2, y2 <- draw-int32-hex-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color - return x2, y2 # cursor-x, cursor-y -} - -fn draw-int32-hex-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - var end-x/edx: int <- copy cursor-x - end-x <- increment - compare end-x, xmax - { - break-if-< - cursor-x <- copy xmin - cursor-y <- increment - } - cursor-x, cursor-y <- draw-int32-hex-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color -} - -fn draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int { - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size screen - draw-int32-hex-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color -} - -fn draw-int32-decimal-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var stream-storage: (stream byte 0x100) - var stream/esi: (addr stream byte) <- address stream-storage - write-int32-decimal stream, n - var xcurr/edx: int <- copy x - var ycurr/ecx: int <- copy y - { - var g/eax: grapheme <- read-grapheme stream - compare g, 0xffffffff/end-of-file - break-if-= - draw-grapheme screen, g, xcurr, ycurr, color, background-color - xcurr <- increment - compare xcurr, xmax - { - break-if-< - xcurr <- copy xmin - ycurr <- increment - } - loop - } - set-cursor-position screen, xcurr, ycurr - return xcurr, ycurr -} - -fn draw-int32-decimal-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var x2/eax: int <- copy 0 - var y2/ecx: int <- copy 0 - x2, y2 <- screen-size screen # width, height - x2, y2 <- draw-int32-decimal-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color - return x2, y2 # cursor-x, cursor-y -} - -fn draw-int32-decimal-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - var end-x/edx: int <- copy cursor-x - end-x <- increment - compare end-x, xmax - { - break-if-< - cursor-x <- copy xmin - cursor-y <- increment - } - cursor-x, cursor-y <- draw-int32-decimal-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color -} - -fn draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int { - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size screen - draw-int32-decimal-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color -} - -## Text direction: down then right - -# draw a single line of text vertically from x, y to ymax -# return the next 'y' coordinate -# if there isn't enough space, truncate -fn draw-text-downward screen: (addr screen), text: (addr array byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int { - var stream-storage: (stream byte 0x100) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, text - var ycurr/eax: int <- draw-stream-downward screen, stream, x, y, ymax, color, background-color - return ycurr -} - -# draw a single-line stream vertically from x, y to ymax -# return the next 'y' coordinate -# if there isn't enough space, truncate -fn draw-stream-downward screen: (addr screen), stream: (addr stream byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int { - var ycurr/ecx: int <- copy y - { - var g/eax: grapheme <- read-grapheme stream - compare g, 0xffffffff/end-of-file - break-if-= - draw-grapheme screen, g, x, ycurr, color, background-color - ycurr <- increment - loop - } - set-cursor-position screen, x, ycurr - return ycurr -} - -fn draw-text-downward-from-cursor screen: (addr screen), text: (addr array byte), ymax: int, color: int, background-color: int { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - var result/eax: int <- draw-text-downward screen, text, cursor-x, cursor-y, ymax, color, background-color -} - -# draw text down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary -# return the next (x, y) coordinate in raster order where drawing stopped -# that way the caller can draw more if given the same min and max bounding-box. -# if there isn't enough space, truncate -fn draw-text-wrapping-down-then-right screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var stream-storage: (stream byte 0x100) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, text - var x/eax: int <- copy _x - var y/ecx: int <- copy _y - x, y <- draw-stream-wrapping-down-then-right screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color - return x, y -} - -# draw a stream down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary -# return the next (x, y) coordinate in raster order where drawing stopped -# that way the caller can draw more if given the same min and max bounding-box. -# if there isn't enough space, truncate -fn draw-stream-wrapping-down-then-right screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var xcurr/edx: int <- copy x - var ycurr/ecx: int <- copy y - { - var g/eax: grapheme <- read-grapheme stream - compare g, 0xffffffff/end-of-file - break-if-= - draw-grapheme screen, g, xcurr, ycurr, color, background-color - ycurr <- increment - compare ycurr, ymax - { - break-if-< - xcurr <- increment - ycurr <- copy ymin - } - loop - } - set-cursor-position screen, xcurr, ycurr - return xcurr, ycurr -} - -fn draw-text-wrapping-down-then-right-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { - var x2/eax: int <- copy 0 - var y2/ecx: int <- copy 0 - x2, y2 <- screen-size screen # width, height - x2, y2 <- draw-text-wrapping-down-then-right screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color - return x2, y2 # cursor-x, cursor-y -} - -fn draw-text-wrapping-down-then-right-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { - var cursor-x/eax: int <- copy 0 - var cursor-y/ecx: int <- copy 0 - cursor-x, cursor-y <- cursor-position screen - var end-y/edx: int <- copy cursor-y - end-y <- increment - compare end-y, ymax - { - break-if-< - cursor-x <- increment - cursor-y <- copy ymin - } - cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color -} - -fn draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int { - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size screen - draw-text-wrapping-down-then-right-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color -} - -# hacky error-handling -# just go into an infinite loop -fn abort e: (addr array byte) { - var dummy1/eax: int <- copy 0 - var dummy2/ecx: int <- copy 0 - dummy1, dummy2 <- draw-text-wrapping-right-then-down-over-full-screen 0/screen, e, 0/x, 0x2f/y, 0xf/fg=white, 0xc/bg=red - { - loop - } -} diff --git a/baremetal/502test.mu b/baremetal/502test.mu deleted file mode 100644 index 00d55d34..00000000 --- a/baremetal/502test.mu +++ /dev/null @@ -1,43 +0,0 @@ -# print msg to screen if a != b, otherwise print "." -fn check-ints-equal _a: int, b: int, msg: (addr array byte) { - var a/eax: int <- copy _a - compare a, b - { - break-if-!= - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg - return - } - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - count-test-failure -} - -fn test-check-ints-equal { - check-ints-equal 0, 0, "abc" -} - -fn check _a: boolean, msg: (addr array byte) { - var a/eax: int <- copy _a - compare a, 0/false - { - break-if-= - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg - return - } - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - count-test-failure -} - -fn check-not _a: boolean, msg: (addr array byte) { - var a/eax: int <- copy _a - compare a, 0/false - { - break-if-!= - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg - return - } - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - count-test-failure -} diff --git a/baremetal/503manhattan-line.mu b/baremetal/503manhattan-line.mu deleted file mode 100644 index 5c51473d..00000000 --- a/baremetal/503manhattan-line.mu +++ /dev/null @@ -1,28 +0,0 @@ -fn draw-box-on-real-screen x1: int, y1: int, x2: int, y2: int, color: int { - draw-horizontal-line-on-real-screen x1, x2, y1, color - draw-vertical-line-on-real-screen x1, y1, y2, color - draw-horizontal-line-on-real-screen x1, x2, y2, color - draw-vertical-line-on-real-screen x2, y1, y2, color -} - -fn draw-horizontal-line-on-real-screen x1: int, x2: int, y: int, color: int { - var x/eax: int <- copy x1 - { - compare x, x2 - break-if->= - pixel-on-real-screen x, y, color - x <- increment - loop - } -} - -fn draw-vertical-line-on-real-screen x: int, y1: int, y2: int, color: int { - var y/eax: int <- copy y1 - { - compare y, y2 - break-if->= - pixel-on-real-screen x, y, color - y <- increment - loop - } -} diff --git a/baremetal/504test-screen.mu b/baremetal/504test-screen.mu deleted file mode 100644 index a409443b..00000000 --- a/baremetal/504test-screen.mu +++ /dev/null @@ -1,327 +0,0 @@ -# Some primitives for checking the state of fake screen objects. - -# validate data on screen regardless of attributes (color, bold, etc.) -# Mu doesn't have multi-line strings, so we provide functions for rows or portions of rows. -# Tab characters (that translate into multiple screen cells) not supported. - -fn check-screen-row screen: (addr screen), y: int, expected: (addr array byte), msg: (addr array byte) { - check-screen-row-from screen, 0/x, y, expected, msg -} - -fn check-screen-row-from screen-on-stack: (addr screen), x: int, y: int, expected: (addr array byte), msg: (addr array byte) { - var screen/esi: (addr screen) <- copy screen-on-stack - var idx/ecx: int <- screen-cell-index screen, x, y - # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme - var e: (stream byte 0x100) - var e-addr/edx: (addr stream byte) <- address e - write e-addr, expected - { - var done?/eax: boolean <- stream-empty? e-addr - compare done?, 0 - break-if-!= - var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx - var g/ebx: grapheme <- copy _g - var expected-grapheme/eax: grapheme <- read-grapheme e-addr - # compare graphemes - $check-screen-row-from:compare-graphemes: { - # if expected-grapheme is space, null grapheme is also ok - { - compare expected-grapheme, 0x20 - break-if-!= - compare g, 0 - break-if-= $check-screen-row-from:compare-graphemes - } - # if (g == expected-grapheme) print "." - compare g, expected-grapheme - { - break-if-!= - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg - break $check-screen-row-from:compare-graphemes - } - # otherwise print an error - count-test-failure - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg - draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg - move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg - draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg - move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - } - idx <- increment - increment x - loop - } -} - -# various variants by screen-cell attribute; spaces in the 'expected' data should not match the attribute - -fn check-screen-row-in-color screen: (addr screen), fg: int, y: int, expected: (addr array byte), msg: (addr array byte) { - check-screen-row-in-color-from screen, fg, y, 0/x, expected, msg -} - -fn check-screen-row-in-color-from screen-on-stack: (addr screen), fg: int, y: int, x: int, expected: (addr array byte), msg: (addr array byte) { - var screen/esi: (addr screen) <- copy screen-on-stack - var idx/ecx: int <- screen-cell-index screen, x, y - # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme - var e: (stream byte 0x100) - var e-addr/edx: (addr stream byte) <- address e - write e-addr, expected - { - var done?/eax: boolean <- stream-empty? e-addr - compare done?, 0 - break-if-!= - var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx - var g/ebx: grapheme <- copy _g - var _expected-grapheme/eax: grapheme <- read-grapheme e-addr - var expected-grapheme/edi: grapheme <- copy _expected-grapheme - $check-screen-row-in-color-from:compare-cells: { - # if expected-grapheme is space, null grapheme is also ok - { - compare expected-grapheme, 0x20 - break-if-!= - compare g, 0 - break-if-= $check-screen-row-in-color-from:compare-cells - } - # if expected-grapheme is space, a different color is ok - { - compare expected-grapheme, 0x20 - break-if-!= - var color/eax: int <- screen-color-at-idx screen, idx - compare color, fg - break-if-!= $check-screen-row-in-color-from:compare-cells - } - # compare graphemes - $check-screen-row-in-color-from:compare-graphemes: { - # if (g == expected-grapheme) print "." - compare g, expected-grapheme - { - break-if-!= - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg - break $check-screen-row-in-color-from:compare-graphemes - } - # otherwise print an error - count-test-failure - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg - draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg - move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg - draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg - move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - } - $check-screen-row-in-color-from:compare-colors: { - var color/eax: int <- screen-color-at-idx screen, idx - compare fg, color - { - break-if-!= - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg - break $check-screen-row-in-color-from:compare-colors - } - # otherwise print an error - count-test-failure - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg - draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg - move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") in color ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, fg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed color ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, color, 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - } - } - idx <- increment - increment x - loop - } -} - -fn check-screen-row-in-background-color screen: (addr screen), bg: int, y: int, expected: (addr array byte), msg: (addr array byte) { - check-screen-row-in-background-color-from screen, bg, y, 0/x, expected, msg -} - -fn check-screen-row-in-background-color-from screen-on-stack: (addr screen), bg: int, y: int, x: int, expected: (addr array byte), msg: (addr array byte) { - var screen/esi: (addr screen) <- copy screen-on-stack - var idx/ecx: int <- screen-cell-index screen, x, y - # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme - var e: (stream byte 0x100) - var e-addr/edx: (addr stream byte) <- address e - write e-addr, expected - { - var done?/eax: boolean <- stream-empty? e-addr - compare done?, 0 - break-if-!= - var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx - var g/ebx: grapheme <- copy _g - var _expected-grapheme/eax: grapheme <- read-grapheme e-addr - var expected-grapheme/edi: grapheme <- copy _expected-grapheme - $check-screen-row-in-background-color-from:compare-cells: { - # if expected-grapheme is space, null grapheme is also ok - { - compare expected-grapheme, 0x20 - break-if-!= - compare g, 0 - break-if-= $check-screen-row-in-background-color-from:compare-cells - } - # if expected-grapheme is space, a different background-color is ok - { - compare expected-grapheme, 0x20 - break-if-!= - var background-color/eax: int <- screen-background-color-at-idx screen, idx - compare background-color, bg - break-if-!= $check-screen-row-in-background-color-from:compare-cells - } - # compare graphemes - $check-screen-row-in-background-color-from:compare-graphemes: { - # if (g == expected-grapheme) print "." - compare g, expected-grapheme - { - break-if-!= - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg - break $check-screen-row-in-background-color-from:compare-graphemes - } - # otherwise print an error - count-test-failure - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg - draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg - move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg - draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg - move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - break $check-screen-row-in-background-color-from:compare-graphemes - } - $check-screen-row-in-background-color-from:compare-background-colors: { - var background-color/eax: int <- screen-background-color-at-idx screen, idx - compare bg, background-color - { - break-if-!= - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg - break $check-screen-row-in-background-color-from:compare-background-colors - } - # otherwise print an error - count-test-failure - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg - draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg - move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") in background-color ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed background-color ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, background-color, 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - } - } - idx <- increment - increment x - loop - } -} - -# helpers for checking just background color, not screen contents -# these can validate bg for spaces - -fn check-background-color-in-screen-row screen: (addr screen), bg: int, y: int, expected-bitmap: (addr array byte), msg: (addr array byte) { - check-background-color-in-screen-row-from screen, bg, y, 0/x, expected-bitmap, msg -} - -fn check-background-color-in-screen-row-from screen-on-stack: (addr screen), bg: int, y: int, x: int, expected-bitmap: (addr array byte), msg: (addr array byte) { - var screen/esi: (addr screen) <- copy screen-on-stack - var idx/ecx: int <- screen-cell-index screen, x, y - # compare background color where 'expected-bitmap' is a non-space - var e: (stream byte 0x100) - var e-addr/edx: (addr stream byte) <- address e - write e-addr, expected-bitmap - { - var done?/eax: boolean <- stream-empty? e-addr - compare done?, 0 - break-if-!= - var _expected-bit/eax: grapheme <- read-grapheme e-addr - var expected-bit/edi: grapheme <- copy _expected-bit - $check-background-color-in-screen-row-from:compare-cells: { - var background-color/eax: int <- screen-background-color-at-idx screen, idx - # if expected-bit is space, assert that background is NOT bg - compare expected-bit, 0x20 - { - break-if-!= - compare background-color, bg - break-if-!= $check-background-color-in-screen-row-from:compare-cells - count-test-failure - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected (", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") to not be in background-color ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - break $check-background-color-in-screen-row-from:compare-cells - } - # otherwise assert that background IS bg - compare background-color, bg - break-if-= $check-background-color-in-screen-row-from:compare-cells - count-test-failure - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected (", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") in background-color ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed background-color ", 3/fg/cyan, 0/bg - draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, background-color, 3/fg/cyan, 0/bg - move-cursor-to-start-of-next-line 0/screen - } - idx <- increment - increment x - loop - } -} - -fn test-draw-single-grapheme { - var screen-on-stack: screen - var screen/esi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5, 4 - draw-code-point screen, 0x61/a, 0/x, 0/y, 1/fg, 2/bg - check-screen-row screen, 0/y, "a", "F - test-draw-single-grapheme" # top-left corner of the screen - check-screen-row-in-color screen, 1/fg, 0/y, "a", "F - test-draw-single-grapheme-fg" - check-screen-row-in-background-color screen, 2/bg, 0/y, "a", "F - test-draw-single-grapheme-bg" - check-background-color-in-screen-row screen, 2/bg, 0/y, "x ", "F - test-draw-single-grapheme-bg2" -} - -fn test-draw-multiple-graphemes { - var screen-on-stack: screen - var screen/esi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/rows, 4/cols - draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "Hello, 世界", 1/fg, 2/bg - check-screen-row screen, 0/y, "Hello, 世界", "F - test-draw-multiple-graphemes" - check-screen-row-in-color screen, 1/fg, 0/y, "Hello, 世界", "F - test-draw-multiple-graphemes-fg" - check-background-color-in-screen-row screen, 2/bg, 0/y, "xxxxxxxxx ", "F - test-draw-multiple-graphemes-bg2" -} diff --git a/baremetal/README.md b/baremetal/README.md deleted file mode 100644 index 5cdb75ed..00000000 --- a/baremetal/README.md +++ /dev/null @@ -1,45 +0,0 @@ -Some apps written in SubX and Mu. Where the rest of this repo relies on a few -Linux syscalls, the apps in this subdirectory interface directly with hardware. -We still need the top-level and apps to build them. - -I'd like to eventually test these programs on real hardware, and to that end -they are extremely parsimonious in the hardware they assume: - - 0. Lots (more than 640KB/1MB[1]) of RAM - 1. Pure-graphics video mode (1024x768 pixels) in 256-color mode. At 8x8 - pixels per grapheme, this will give us 160x128 graphemes. But it's still - an open question if it's reasonably widely supported by modern hardware. - If it isn't, I'll downsize. - 2. Keyboard. Just a partial US keyboard for now. Main qwerty zone only. No - number pad, no function keys, no ctrl/alt/meta/fn/super/capslck/numlck. - -That's it: - * No wifi, no networking - * No multitouch, no touchscreen, no mouse - * No graphics acceleration - * No virtual memory, no memory reclamation - -Just your processor, gigabytes of RAM[1], a moderately-sized monitor and a -keyboard. (The mouse should also be easy to provide.) - -We can't yet read from or write to disk, except for the initial load of the -program. Enabling access to lots of RAM gives up access to BIOS helpers for -the disk. - -These programs don't convert to formats like ELF that can load on other -operating systems. There's also currently no code/data segment separation, -just labels and bytes. I promise not to write self-modifying code. Security -and sandboxing is still an open question. - -Programs start executing at address 0x9400. See baremetal/boot.hex for -details. - -Mu programs always run all their automated tests first. `main` only runs if -there are no failing tests. See baremetal/mu-init.subx for details. - -So far the programs have only been tested in Qemu and Bochs emulators. - -[1] Though we might need to start thinking of [the PC memory map](https://wiki.osdev.org/Memory_Map_(x86)) -as our programs grow past the first 32MB of memory. Mu doesn't yet make any -attempt to understand how much RAM the underlying computer has. Also, writing -to random locations can damage hardware or corrupt storage devices. diff --git a/baremetal/boot.bochsrc b/baremetal/boot.bochsrc deleted file mode 100644 index 9a02d67c..00000000 --- a/baremetal/boot.bochsrc +++ /dev/null @@ -1,15 +0,0 @@ -# Configuration for the Bochs x86 CPU emulator to run baremetal Mu programs -# See baremetal/boot.hex for more details. -# -# Installing Bochs: -# On Mac OS: -# brew install bochs -# On Ubuntu Linux 20.04: -# sudo apt install bochs bochs-sdl bochsbios vgabios - -display_library: sdl2 - -ata0-master: type=disk, path="disk.img", mode=flat, cylinders=20, heads=16, spt=63 # 10MB, 512 bytes per sector -boot: disk -# PS/2 mouse requires black magic that I don't know how to explain. -log: - diff --git a/baremetal/boot.hex b/baremetal/boot.hex deleted file mode 100644 index 6fa874c2..00000000 --- a/baremetal/boot.hex +++ /dev/null @@ -1,1181 +0,0 @@ -# Code for the first few disk sectors that all programs in this directory need: -# - load sectors past the first (using BIOS primitives) since only the first is available by default -# - if this fails, print 'D' at top-left of screen and halt -# - initialize a minimal graphics mode -# - switch to 32-bit mode (giving up access to BIOS primitives) -# - set up a handler for keyboard events -# - jump to start of program -# -# To convert to a disk image, first prepare a realistically sized disk image: -# dd if=/dev/zero of=disk.img count=20160 # 512-byte sectors, so 10MB -# Create initial sectors from this file: -# ./bootstrap run apps/hex < baremetal/boot.hex > boot.bin -# Translate other sectors into a file called a.img -# Load all sectors into the disk image: -# cat boot.bin a.img > disk.bin -# dd if=disk.bin of=disk.img conv=notrunc -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Since we start out in 16-bit mode, we need instructions SubX doesn't -# support. -# This file contains just lowercase hex bytes and comments. Programming it -# requires liberal use of: -# - comments documenting expected offsets -# - size checks on the emitted file (currently: 6144 bytes) -# - xxd to spot-check contents of specific offsets in the generated output -# -# Programs using this initialization: -# - can't use any syscalls -# - can't print text to video memory (past these boot sectors) -# - must only print raw pixels (256 colors) to video memory (resolution 1024x768) -# - must start executing immediately after this file (see outline below) -# -# Don't panic! This file doesn't contain any loops or function calls. 80% of -# it is data. One pass through less than 1KB of code (there's lots of -# padding), and then we jump into a better notation. The rest of the stack -# (really only in a couple of slightly higher-level places) needs to know just -# a few magic constants: -# Video memory: start is stored at 0x8128 -# Keyboard buffer: starts at 0x8028 -# -# No mouse support. _That_ would require panicking. - -# Outline of this file with offsets and the addresses they map to at run-time: -# -- 16-bit mode code -# offset 0 (address 7c00): boot code -# -- 16-bit mode data -# e0 (address 7c80) global descriptor table -# f8 (address 7ca0) <== gdt_descriptor -# -- 32-bit mode code -# offset 100 (address 7d00): boot code -# 1fe (address 7dfe) boot sector marker (2 bytes) -# offset 200 (address 7e00): interrupt handler code -# -- 32-bit mode data -# offset 400 (address 8000): handler data -# 410 (address 8010): keyboard handler data -# 428 (address 8028) <== keyboard buffer -# offset 500 (address 8100): video mode data (256 bytes) -# 528 (address 8128) <== start of video RAM stored here -# offset 600 (address 8200): interrupt descriptor table (1KB) -# offset a00 (address 8600): keyboard mappings (1.5KB) -# offset 1000 (address 8c00): bitmap font (2KB) -# offset 1800 (address 9400): entrypoint for applications (don't forget to adjust survey_baremetal if this changes) - -# Other details of the current memory map: -# code: 4 tracks of disk to [0x00007c00, 0x00027400) -# stack grows down from 0x00070000 -# see below -# heap: [0x01000000, 0x02000000) -# see baremetal/120allocate.subx -# Consult https://wiki.osdev.org/Memory_Map_(x86) before modifying any of this. - -## 16-bit entry point - -# Upon reset, the IBM PC: -# - loads the first sector (512 bytes) -# from some bootable image (see the boot sector marker at the end of this file) -# to the address range [0x7c00, 0x7e00) -# - starts executing code at address 0x7c00 - -# offset 00 (address 0x7c00): - # disable interrupts for this initialization - fa # cli - - # initialize segment registers - # this isn't always needed, but the recommendation is to not make assumptions - b8 00 00 # ax <- 0 - 8e d8 # ds <- ax - 8e c0 # es <- ax - 8e e0 # fs <- ax - 8e e8 # gs <- ax - - # initialize stack to 0x00070000 - # We don't read or write the stack before we get to 32-bit mode, but BIOS - # calls do. We need to move the stack in case BIOS initializes it to some - # low address that we want to write code into. - b8 00 70 # ax <- 0x7000 - 8e d0 # ss <- ax - bc 00 00 # sp <- 0x0000 - - # undo the A20 hack: https://en.wikipedia.org/wiki/A20_line - # this is from https://github.com/mit-pdos/xv6-public/blob/master/bootasm.S - # seta20.1: - e4 64 # al <- port 0x64 - a8 02 # set zf if bit 1 (second-least significant) is not set - 75 fa # if zf not set, goto seta20.1 (-6) - b0 d1 # al <- 0xd1 - e6 64 # port 0x64 <- al - # seta20.2: - e4 64 # al <- port 0x64 - a8 02 # set zf if bit 1 (second-least significant) is not set - 75 fa # if zf not set, goto seta20.2 (-6) - b0 df # al <- 0xdf - e6 64 # port 0x64 <- al - - # load remaining sectors from first two tracks of disk into addresses [0x7e00, 0x17800) - b4 02 # ah <- 2 # read sectors from disk - # dl comes conveniently initialized at boot time with the index of the device being booted - b5 00 # ch <- 0 # cylinder 0 - b6 00 # dh <- 0 # track 0 - b1 02 # cl <- 2 # second sector, 1-based - b0 7d # al <- 125 # number of sectors to read = 2*63 - 1 - # address to write sectors to = es:bx = 0x7e00, contiguous with boot segment - bb 00 00 # bx <- 0 - 8e c3 # es <- bx - bb 00 7e # bx <- 0x7e00 [label] - cd 13 # int 13h, BIOS disk service - 0f 82 a3 00 # jump-if-carry disk_error [label] - - # load two more tracks of disk into addresses [0x17800, 0x27400) - b4 02 # ah <- 2 # read sectors from disk - # dl comes conveniently initialized at boot time with the index of the device being booted - b5 00 # ch <- 0 # cylinder 0 - b6 02 # dh <- 2 # track 0 - b1 01 # cl <- 1 # first sector, 1-based - b0 7e # al <- 126 # number of sectors to read = 2*63 - # address to write sectors to = es:bx = 0x17800 - bb 80 17 # bx <- 0x1780 [label] - 8e c3 # es <- bx - bb 00 00 # bx <- 0 - cd 13 # int 13h, BIOS disk service - 0f 82 9b 00 # jump-if-carry disk_error [label] - - # load two more tracks of disk into addresses [0x27400, 0x37000) - b4 02 # ah <- 2 # read sectors from disk - # dl comes conveniently initialized at boot time with the index of the device being booted - b5 00 # ch <- 0 # cylinder 0 - b6 02 # dh <- 2 # track 0 - b1 01 # cl <- 1 # first sector, 1-based - b0 7e # al <- 126 # number of sectors to read = 2*63 - # address to write sectors to = es:bx = 0x17800 - bb 80 17 # bx <- 0x1780 [label] - 8e c3 # es <- bx - bb 00 00 # bx <- 0 - cd 13 # int 13h, BIOS disk service - 0f 82 9b 00 # jump-if-carry disk_error [label] - - # reset es - bb 00 00 # bx <- 0 - 8e c3 # es <- bx - - # adjust video mode - b4 4f # ah <- 4f (VBE) - b0 02 # al <- 02 (set video mode) - bb 05 41 # bx <- 0x0105 (graphics 1024x768x256 - # 0x4000 bit = configure linear frame buffer in Bochs emulator; hopefully this doesn't hurt anything when running natively) - # fallback mode: 0x0101 (640x480x256) - cd 10 # int 10h, Vesa BIOS extensions - - # load information for the (hopefully) current video mode - # mostly just for the address to the linear frame buffer - b4 4f # ah <- 4f (VBE) - b0 01 # al <- 01 (get video mode info) - b9 07 01 # cx <- 0x0107 (mode we requested) - bf 00 81 # di <- 0x8100 (video mode info) [label] - cd 10 - - # switch to 32-bit mode - 0f 01 16 # lgdt 00/mod/indirect 010/subop 110/rm/use-disp16 - f8 7c # *gdt_descriptor [label] - 0f 20 c0 # eax <- cr0 - 66 83 c8 01 # eax <- or 0x1 - 0f 22 c0 # cr0 <- eax - ea 00 7d 08 00 # far jump to initialize_32bit_mode after setting cs to the record at offset 8 in the gdt (gdt_code) [label] - -# padding -# 8e: - 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# cf: -# disk_error: - # print 'D' to top-left of screen to indicate disk error - # *0xb8000 <- 0x0f44 - # bx <- 0xb800 - bb 00 b8 - # ds <- bx - 8e db # 11b/mod 011b/reg/ds 011b/rm/bx - # al <- 'D' - b0 44 - # ah <- 0x0f # white on black - b4 0f - # bx <- 0 - bb 00 00 - # *ds:bx <- ax - 89 07 # 00b/mod/indirect 000b/reg/ax 111b/rm/bx - -e9 fd ff # loop forever - -## GDT: 3 records of 8 bytes each - -# e0: -# gdt_start: -# gdt_null: mandatory null descriptor - 00 00 00 00 00 00 00 00 -# gdt_code: (offset 8 from gdt_start) - ff ff # limit[0:16] - 00 00 00 # base[0:24] - 9a # 1/present 00/privilege 1/descriptor type = 1001b - # 1/code 0/conforming 1/readable 0/accessed = 1010b - cf # 1/granularity 1/32-bit 0/64-bit-segment 0/AVL = 1100b - # limit[16:20] = 1111b - 00 # base[24:32] -# gdt_data: (offset 16 from gdt_start) - ff ff # limit[0:16] - 00 00 00 # base[0:24] - 92 # 1/present 00/privilege 1/descriptor type = 1001b - # 0/data 0/conforming 1/readable 0/accessed = 0010b - cf # same as gdt_code - 00 # base[24:32] -# gdt_end: - -# f8: -# gdt_descriptor: - 17 00 # final index of gdt = gdt_end - gdt_start - 1 - e0 7c 00 00 # start = gdt_start [label] - -# padding -# fe: - 00 00 - -## 32-bit code from this point (still some instructions not in SubX) - -# offset 100 (address 0x7d00): -# initialize_32bit_mode: - 66 b8 10 00 # ax <- offset 16 from gdt_start - 8e d8 # ds <- ax - 8e d0 # ss <- ax - 8e c0 # es <- ax - 8e e0 # fs <- ax - 8e e8 # gs <- ax - -# 10e: - bc 00 00 07 00 # esp <- 0x00070000 - -# 113: - # load interrupt handlers - 0f 01 1d # lidt 00/mod/indirect 011/subop 101/rm32/use-disp32 - 00 80 00 00 # *idt_descriptor [label] - - # For now, not bothering reprogramming the IRQ to not conflict with software - # exceptions. - # https://wiki.osdev.org/index.php?title=8259_PIC&oldid=24650#Protected_Mode - # - # Interrupt 1 (keyboard) conflicts with debugger faults. We don't use a - # debugger. - # Reference: - # https://wiki.osdev.org/Exceptions - -# 11a: - # enable keyboard IRQ (1) - b0 fd # al <- 0xfd # disable mask for IRQ1 - e6 21 # port 0x21 <- al - -# 11e: - fb # enable interrupts - db e3 # initialize FPU - # eax <- cr4 - 0f 20 # copy cr4 to rm32 - e0 # 11/mod/direct 100/r32/CR4 000/rm32/eax - # eax <- or bit 9 - 0f ba - e8 # 11/mod/direct 101/subop/bit-test-and-set 000/rm32/eax - 09 # imm8 - # cr4 <- eax - 0f 22 # copy rm32 to cr4 - e0 # 11/mod/direct 100/r32/CR4 000/rm32/eax - e9 d0 16 00 00 # jump to 0x9400 [label] - -# padding -# 130: -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# 1fe: -# final 2 bytes of boot sector -55 aa - -## sector 2 onwards loaded by load_disk, not automatically on boot - -# offset 200 (address 0x7e00): -# null interrupt handler: - cf # iret - -# padding -# 201: - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# 210: -# keyboard interrupt handler: - # prologue - fa # disable interrupts - 60 # push all registers to stack - # acknowledge interrupt - b0 20 # al <- 0x20 - e6 20 # port 0x20 <- al - 31 c0 # eax <- xor eax; 11/direct 000/r32/eax 000/rm32/eax - # check output buffer of 8042 keyboard controller (https://web.archive.org/web/20040604041507/http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/keyboard/atkeyboard.html) - e4 64 # al <- port 0x64 - a8 01 # set zf if bit 0 (least significant) is not set - 74 bb # jump to epilogue if 0 bit is not set [label] -# 21e: - # - if keyboard buffer is full, return - 31 c9 # ecx <- xor ecx; 11/direct 001/r32/ecx 001/rm32/ecx - # var index/ecx: byte - 8a # copy m8 at r32 to r8 - 0d # 00/mod/indirect 001/r8/cl 101/rm32/use-disp32 - 28 80 00 00 # disp32 [label] - # al = *(keyboard buffer + index) - 8a # copy m8 at r32 to r8 - 81 # 10/mod/*+disp32 000/r8/al 001/rm32/ecx - 30 80 00 00 # disp32 [label] - # if (al != 0) return - 3c 00 # compare al, 0 - 75 a9 # jump to epilogue if != [label] -# 230: - # - read keycode - e4 60 # al <- port 0x60 - # - key released - # if (al == 0xaa) shift = false # left shift is being lifted - 3c aa # compare al, 0xaa - 75 0a # jump to $1 if != [label] - # *shift = 0 - c7 # copy imm32 to rm32 - 05 # 00/mod/indirect 000/subop/copy 101/rm32/use-disp32 - 10 80 00 00 # disp32 [label] - 00 00 00 00 # imm32 -# 240: -# $1: - # if (al == 0xb6) shift = false # right shift is being lifted - 3c b6 # compare al, 0xb6 - 75 0a # jump to $2 if != [label] - # *shift = 0 - c7 # copy imm32 to rm32 - 05 # 00/mod/indirect 000/subop/copy 101/rm32/use-disp32 - 10 80 00 00 # disp32 [label] - 00 00 00 00 # imm32 -# 24e: -# $2: - # if (al == 0x9d) ctrl = false # ctrl is being lifted - 3c 9d # compare al, 0x9d - 75 0a # jump to $3 if != [label] - # *ctrl = 0 - c7 # copy imm32 to rm32 - 05 # 00/mod/indirect 000/subop/copy 101/rm32/use-disp32 - 14 80 00 00 # disp32 [label] - 00 00 00 00 # imm32 -# 25c: -# $3: - # if (al & 0x80) a key is being lifted; return - 50 # push eax - 24 80 # al <- and 0x80 - 3c 00 # compare al, 0 - 58 # pop to eax (without touching flags) - 75 75 # jump to epilogue if != [label] -# 264: - # - key pressed - # if (al == 0x2a) shift = true, return # left shift pressed - 3c 2a # compare al, 0x2a - 75 0c # jump to $4 if != [label] - # *shift = 1 - c7 # copy imm32 to rm32 - 05 # 00/mod/indirect 000/subop/copy 101/rm32/use-disp32 - 10 80 00 00 # disp32 [label] - 01 00 00 00 # imm32 - eb 65 # jump to epilogue [label] -# 274: -# $4: - # if (al == 0x36) shift = true, return # right shift pressed - 3c 36 # compare al, 0x36 - 75 0c # jump to $5 if != [label] - # *shift = 1 - c7 # copy imm32 to rm32 - 05 # 00/mod/indirect 000/subop/copy 101/rm32/use-disp32 - 10 80 00 00 # disp32 [label] - 01 00 00 00 # imm32 - eb 55 # jump to epilogue [label] -# 284: -# $5: - # if (al == 0x1d) ctrl = true, return - 3c 1d # compare al, 0x36 - 75 0c # jump to $6 if != [label] - # *shift = 1 - c7 # copy imm32 to rm32 - 05 # 00/mod/indirect 000/subop/copy 101/rm32/use-disp32 - 14 80 00 00 # disp32 [label] - 01 00 00 00 # imm32 - eb 45 # jump to epilogue [label] -# 294: -# $6: - # - convert key to character - # if (shift) use keyboard shift map - 81 # operate on rm32 and imm32 - 3d # 00/mod/indirect 111/subop/compare 101/rm32/use-disp32 - 10 80 00 00 # disp32 = shift [label] - 00 00 00 00 # imm32 - 74 08 # jump to $7 if = [label] - # al <- *(keyboard shift map + eax) - 8a # copy m8 at rm32 to r8 - 80 # 10/mod/*+disp32 000/r8/al 000/rm32/eax - 00 87 00 00 # disp32 [label] - eb 1a # jump to $8 [label] -# 2a8: -# $7: - # if (ctrl) use keyboard ctrl map - 81 # operate on rm32 and imm32 - 3d # 00/mod/indirect 111/subop/compare 101/rm32/use-disp32 - 14 80 00 00 # disp32 = ctrl [label] - 00 00 00 00 # imm32 - 74 08 # jump to $8 if = [label] - # al <- *(keyboard ctrl map + eax) - 8a # copy m8 at rm32 to r8 - 80 # 10/mod/*+disp32 000/r8/al 000/rm32/eax - 00 88 00 00 # disp32 [label] - eb 06 # jump to $9 [label] -# 2bc: -# $8: - # otherwise use keyboard normal map - # al <- *(keyboard normal map + eax) - 8a # copy m8 at rm32 to r8 - 80 # 10/mod/*+disp32 000/r8/al 000/rm32/eax - 00 86 00 00 # disp32 [label] -# 2c2: -# $9: - # - if there's no character mapping, return - 3c 00 # compare al, 0 - 74 13 # jump to epilogue if = [label] -# 2c6: - # - store al in keyboard buffer - 88 # copy r8 to m8 at r32 - 81 # 10/mod/*+disp32 000/r8/al 001/rm32/ecx - 30 80 00 00 # disp32 [label] - # increment index - fe # increment byte - 05 # 00/mod/indirect 000/subop/increment 101/rm32/use-disp32 - 28 80 00 00 # disp32 [label] - # clear top nibble of index (keyboard buffer is circular) - 80 # and byte - 25 # 00/mod/indirect 100/subop/and 101/rm32/use-disp32 - 28 80 00 00 # disp32 [label] - 0f # imm8 -# 2d9: - # epilogue - 61 # pop all registers - fb # enable interrupts - cf # iret - -# padding -# 2dc: - 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -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 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# offset 400 (address 0x8000): interrupt handler data -# idt_descriptor: - ff 03 # idt_end - idt_start - 1 - 00 82 00 00 # start = idt_start [label] - -# padding -# 406: - 00 00 00 00 00 00 00 00 00 00 - -# 410: -# var shift: boolean - 00 00 00 00 - -# 414: -# var ctrl: boolean - 00 00 00 00 - -# padding -# 418: - 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 - -# 428: -# var keyboard circular buffer -# write index: nibble -# still take up 4 bytes so SubX can handle it - 00 00 00 00 -# 42c: -# read index: nibble -# still take up 4 bytes so SubX can handle it - 00 00 00 00 -# 430: -# circular buffer: byte[16] - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# padding -# 440: -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# offset 500 (address 0x8100): -# video mode info {{{ - 00 00 # attributes - 00 # winA - 00 # winB -# 04 - 00 00 # granularity - 00 00 # winsize -# 08 - 00 00 # segmentA - 00 00 # segmentB -# 0c - 00 00 00 00 # realFctPtr (who knows) -# 10 - 00 00 # pitch - 00 00 # Xres -# 14 - 00 00 # Yres - 00 00 # Wchar Ychar -# 18 - 00 # planes - 00 # bpp - 00 # banks - 00 # memory_model -# 1c - 00 # bank_size - 00 # image_pages - 00 # reserved -# 1f - 00 00 # red_mask red_position - 00 00 # green_mask green_position - 00 00 # blue_mask blue_position - 00 00 # rsv_mask rsv_position - 00 # directcolor_attributes -# 28 - 00 00 00 00 # physbase <== linear frame buffer - -# 2c -# reserved for video mode info - 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# }}} - -# offset 600 (address 0x8200): -# interrupt descriptor table {{{ -# 128 entries * 8 bytes each = 1024 bytes (0x400) -# idt_start: - -# entry 0 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 - -# By default, BIOS maps IRQ0-7 to interrupt vectors 8-15. -# https://wiki.osdev.org/index.php?title=Interrupts&oldid=25102#Default_PC_Interrupt_Vector_Assignment - -# entry 8: clock - 00 7e # target[0:16] = null interrupt handler [label] - 08 00 # segment selector (gdt_code) - 00 # unused - 8e # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate - 00 00 # target[16:32] - -# entry 9: keyboard - 10 7e # target[0:16] = keyboard interrupt handler [label] - 08 00 # segment selector (gdt_code) - 00 # unused - 8e # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate - 00 00 # target[16:32] - -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 - -# 500: -# entry 0x20 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 - -# 600: -# entry 0x40 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 - -# 700: -# entry 0x60 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -# entry 0x70 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -# idt_end: -# }}} - -## the rest of this file has data - -# offset a00 (address 0x8600): -# translating keys to ASCII {{{ -# keyboard normal map: -00 -# es - 1b -# |<--- digits -------------->| - = backspace - 31 32 33 34 35 36 37 38 39 30 2d 3d 08 -# 0f -# tab q w e r t y u i o p [ ] - 09 71 77 65 72 74 79 75 69 6f 70 5b 5d -# 1c -# enter (newline) - 0a 00 -# 1e -# a s d f g h j k l ; ' ` \ - 61 73 64 66 67 68 6a 6b 6c 3b 27 60 00 5c - # ^ left shift -# 2c -# z x c v b n m , . / * - 7a 78 63 76 62 6e 6d 2c 2e 2f 00 2a - # ^ right shift -# 38 -# space - 00 20 -# 3a - 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# numeric keypad would start here, but isn't implemented - 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# offset b00: -# keyboard shift map: -00 -# es - 1b -# ! @ # $ % ^ & * ( ) _ + backspace - 21 40 23 24 25 53 26 2a 28 29 5f 2b 08 -# 0f -# tab Q W E R T Y U I O P { } - 09 51 57 45 52 54 59 55 49 5f 50 7b 7d -# 1c -# enter (newline) - 0a 00 -# 1e -# A S D F G H J K L : " ~ | - 41 53 44 46 47 48 4a 4b 4c 3a 22 7e 00 7c -# 2c -# Z X C V B N M < > ? * - 5a 58 43 56 42 4e 4d 3c 3e 3f 00 2a -# 38 -# space - 00 20 -# 3a - 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# numeric keypad would start here, but isn't implemented - 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# c00: -# keyboard ctrl map: -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# 10 -# ^q ^w ^e ^r ^t ^y ^u tb ^o ^p - 11 17 05 12 14 19 15 09 1f 10 00 00 -# 1c -# carriage-return - 0d 00 -# 1e -# ^a ^s ^d ^f ^g ^h ^j ^j ^l ^\ - 01 13 04 06 07 08 0a 0b 0c 00 00 00 00 1c -# 2c -# ^z ^x ^c ^v ^b ^n ^m ^/ - 1a 18 03 16 02 0e 0d 00 00 1f 00 00 -# 38 - 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# padding (there might be more keyboard tables) -# d00: -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# e00: -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# f00: -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# }}} - -# offset 1000 (address 0x8c00) -# Bitmaps for some ASCII characters (soon Unicode) {{{ -# Part of GNU Unifont -# 8px wide, 16px tall -# Based on http://unifoundry.com/pub/unifont/unifont-13.0.05/font-builds/unifont-13.0.05.hex.gz -# See https://en.wikipedia.org/wiki/GNU_Unifont#The_.hex_font_format -# Website: http://unifoundry.com/unifont/index.html -# License: http://unifoundry.com/LICENSE.txt (GPL v2) -# Each line below is a bitmap for a single character. -# Each byte is a bitmap for a single row of 8 pixels. - -# some unprintable ASCII chars - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# 0x20 = space - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# ! - 00 00 00 00 08 08 08 08 08 08 08 00 08 08 00 00 -# " - 00 00 22 22 22 22 00 00 00 00 00 00 00 00 00 00 -# 0x23 = '#' - 00 00 00 00 12 12 12 7e 24 24 7e 48 48 48 00 00 -# $ - 00 00 00 00 08 3e 49 48 38 0e 09 49 3e 08 00 00 -# % - 00 00 00 00 31 4a 4a 34 08 08 16 29 29 46 00 00 -# & - 00 00 00 00 1c 22 22 14 18 29 45 42 46 39 00 00 -# ' - 00 00 08 08 08 08 00 00 00 00 00 00 00 00 00 00 -# ( - 00 00 00 04 08 08 10 10 10 10 10 10 08 08 04 00 -# ) - 00 00 00 20 10 10 08 08 08 08 08 08 10 10 20 00 -# * - 00 00 00 00 00 00 08 49 2a 1c 2a 49 08 00 00 00 -# + - 00 00 00 00 00 00 08 08 08 7f 08 08 08 00 00 00 -# , - 00 00 00 00 00 00 00 00 00 00 00 00 18 08 08 10 -# - - 00 00 00 00 00 00 00 00 00 3c 00 00 00 00 00 00 -# . - 00 00 00 00 00 00 00 00 00 00 00 00 18 18 00 00 -# / - 00 00 00 00 02 02 04 08 08 10 10 20 40 40 00 00 -# 0x30 = '0' - 00 00 00 00 18 24 42 46 4a 52 62 42 24 18 00 00 -# 1 - 00 00 00 00 08 18 28 08 08 08 08 08 08 3e 00 00 -# 2 - 00 00 00 00 3c 42 42 02 0c 10 20 40 40 7e 00 00 -# 3 - 00 00 00 00 3c 42 42 02 1c 02 02 42 42 3c 00 00 -# 4 - 00 00 00 00 04 0c 14 24 44 44 7e 04 04 04 00 00 -# 5 - 00 00 00 00 7e 40 40 40 7c 02 02 02 42 3c 00 00 -# 6 - 00 00 00 00 1c 20 40 40 7c 42 42 42 42 3c 00 00 -# 7 - 00 00 00 00 7e 02 02 04 04 04 08 08 08 08 00 00 -# 8 - 00 00 00 00 3c 42 42 42 3c 42 42 42 42 3c 00 00 -# 9 - 00 00 00 00 3c 42 42 42 3e 02 02 02 04 38 00 00 -# : - 00 00 00 00 00 00 18 18 00 00 00 18 18 00 00 00 -# ; - 00 00 00 00 00 00 18 18 00 00 00 18 08 08 10 00 -# < - 00 00 00 00 00 02 04 08 10 20 10 08 04 02 00 00 -# = - 00 00 00 00 00 00 00 7e 00 00 00 7e 00 00 00 00 -# > - 00 00 00 00 00 40 20 10 08 04 08 10 20 40 00 00 -# ? - 00 00 00 00 3c 42 42 02 04 08 08 00 08 08 00 00 -# 0x40 = @ - 00 00 00 00 1c 22 4a 56 52 52 52 4e 20 1e 00 00 -# A - 00 00 00 00 18 24 24 42 42 7e 42 42 42 42 00 00 -# B - 00 00 00 00 7c 42 42 42 7c 42 42 42 42 7c 00 00 -# C - 00 00 00 00 3c 42 42 40 40 40 40 42 42 3c 00 00 -# D - 00 00 00 00 78 44 42 42 42 42 42 42 44 78 00 00 -# E - 00 00 00 00 7e 40 40 40 7c 40 40 40 40 7e 00 00 -# F - 00 00 00 00 7e 40 40 40 7c 40 40 40 40 40 00 00 -# G - 00 00 00 00 3c 42 42 40 40 4e 42 42 46 3a 00 00 -# H - 00 00 00 00 42 42 42 42 7e 42 42 42 42 42 00 00 -# I - 00 00 00 00 3e 08 08 08 08 08 08 08 08 3e 00 00 -# J - 00 00 00 00 1f 04 04 04 04 04 04 44 44 38 00 00 -# K - 00 00 00 00 42 44 48 50 60 60 50 48 44 42 00 00 -# L - 00 00 00 00 40 40 40 40 40 40 40 40 40 7e 00 00 -# M - 00 00 00 00 42 42 66 66 5a 5a 42 42 42 42 00 00 -# N - 00 00 00 00 42 62 62 52 52 4a 4a 46 46 42 00 00 -# O - 00 00 00 00 3c 42 42 42 42 42 42 42 42 3c 00 00 -# 0x50 = P - 00 00 00 00 7c 42 42 42 7c 40 40 40 40 40 00 00 -# Q - 00 00 00 00 3c 42 42 42 42 42 42 5a 66 3c 03 00 -# R - 00 00 00 00 7c 42 42 42 7c 48 44 44 42 42 00 00 -# S - 00 00 00 00 3c 42 42 40 30 0c 02 42 42 3c 00 00 -# T - 00 00 00 00 7f 08 08 08 08 08 08 08 08 08 00 00 -# U - 00 00 00 00 42 42 42 42 42 42 42 42 42 3c 00 00 -# V - 00 00 00 00 41 41 41 22 22 22 14 14 08 08 00 00 -# W - 00 00 00 00 42 42 42 42 5a 5a 66 66 42 42 00 00 -# X - 00 00 00 00 42 42 24 24 18 18 24 24 42 42 00 00 -# Y - 00 00 00 00 41 41 22 22 14 08 08 08 08 08 00 00 -# Z - 00 00 00 00 7e 02 02 04 08 10 20 40 40 7e 00 00 -# [ - 00 00 00 0e 08 08 08 08 08 08 08 08 08 08 0e 00 -# \ - 00 00 00 00 40 40 20 10 10 08 08 04 02 02 00 00 -# ] - 00 00 00 70 10 10 10 10 10 10 10 10 10 10 70 00 -# ^ - 00 00 18 24 42 00 00 00 00 00 00 00 00 00 00 00 -# _ - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7f 00 -# 0x60 = backtick - 00 20 10 08 00 00 00 00 00 00 00 00 00 00 00 00 -# a - 00 00 00 00 00 00 3c 42 02 3e 42 42 46 3a 00 00 -# b - 00 00 00 40 40 40 5c 62 42 42 42 42 62 5c 00 00 -# c - 00 00 00 00 00 00 3c 42 40 40 40 40 42 3c 00 00 -# d - 00 00 00 02 02 02 3a 46 42 42 42 42 46 3a 00 00 -# e - 00 00 00 00 00 00 3c 42 42 7e 40 40 42 3c 00 00 -# f - 00 00 00 0c 10 10 10 7c 10 10 10 10 10 10 00 00 -# g - 00 00 00 00 00 02 3a 44 44 44 38 20 3c 42 42 3c -# h - 00 00 00 40 40 40 5c 62 42 42 42 42 42 42 00 00 -# i - 00 00 00 08 08 00 18 08 08 08 08 08 08 3e 00 00 -# j - 00 00 00 04 04 00 0c 04 04 04 04 04 04 04 48 30 -# k - 00 00 00 40 40 40 44 48 50 60 50 48 44 42 00 00 -# l - 00 00 00 18 08 08 08 08 08 08 08 08 08 3e 00 00 -# m - 00 00 00 00 00 00 76 49 49 49 49 49 49 49 00 00 -# n - 00 00 00 00 00 00 5c 62 42 42 42 42 42 42 00 00 -# o - 00 00 00 00 00 00 3c 42 42 42 42 42 42 3c 00 00 -# 0x70 = p - 00 00 00 00 00 00 5c 62 42 42 42 42 62 5c 40 40 -# q - 00 00 00 00 00 00 3a 46 42 42 42 42 46 3a 02 02 -# r - 00 00 00 00 00 00 5c 62 42 40 40 40 40 40 00 00 -# s - 00 00 00 00 00 00 3c 42 40 30 0c 02 42 3c 00 00 -# t - 00 00 00 00 10 10 10 7c 10 10 10 10 10 0c 00 00 -# u - 00 00 00 00 00 00 42 42 42 42 42 42 46 3a 00 00 -# v - 00 00 00 00 00 00 42 42 42 24 24 24 18 18 00 00 -# w - 00 00 00 00 00 00 41 49 49 49 49 49 49 36 00 00 -# x - 00 00 00 00 00 00 42 42 24 18 18 24 42 42 00 00 -# y - 00 00 00 00 00 00 42 42 42 42 42 26 1a 02 02 3c -# z - 00 00 00 00 00 00 7e 02 04 08 10 20 40 7e 00 00 -# { - 00 00 00 0c 10 10 08 08 10 20 10 08 08 10 10 0c -# | - 00 00 08 08 08 08 08 08 08 08 08 08 08 08 08 08 -# } - 00 00 00 30 08 08 10 10 08 04 08 10 10 08 08 30 -# ~ - 00 00 00 31 49 46 00 00 00 00 00 00 00 00 00 00 -# 0x7f = del (unused) - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -# }}} - -# offset 1800 (address 0x9400) - -# vim:ft=subx diff --git a/baremetal/boot0.hex b/baremetal/boot0.hex deleted file mode 100644 index adb320d1..00000000 --- a/baremetal/boot0.hex +++ /dev/null @@ -1,344 +0,0 @@ -# A minimal bootable image that: -# - loads more sectors past the first boot sector (using BIOS primitives) -# - switches to 32-bit mode (giving up access to BIOS primitives) -# - sets up a keyboard handler to print '1' at the top-left of screen when '1' is typed -# -# When it's ready to accept keys, it prints 'H' to the top-left of the screen. -# -# If the initial load fails, it prints 'D' to the top-left of the screen and -# halts. -# -# To convert to a disk image, first prepare a realistically sized disk image: -# dd if=/dev/zero of=disk.img count=20160 # 512-byte sectors, so 10MB -# Now fill in sectors: -# ./bootstrap run apps/hex < baremetal/boot0.hex > boot.bin -# dd if=boot.bin of=disk.img conv=notrunc -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Since we start out in 16-bit mode, we need instructions SubX doesn't -# support. -# This file contains just lowercase hex bytes and comments. Zero -# error-checking. Make liberal use of: -# - comments documenting expected offsets -# - size checks on the emitted file (currently: 512 bytes) -# - xxd to eyeball that offsets contain expected bytes - -## 16-bit entry point - -# Upon reset, the IBM PC -# loads the first sector (512 bytes) -# from some bootable image (see the boot sector marker at the end of this file) -# to the address range [0x7c00, 0x7e00) - -# offset 00 (address 0x7c00): - # disable interrupts for this initialization - fa # cli - - # initialize segment registers - # this isn't always needed, but the recommendation is to not make assumptions - b8 00 00 # ax <- 0 - 8e d8 # ds <- ax - 8e d0 # ss <- ax - 8e c0 # es <- ax - 8e e0 # fs <- ax - 8e e8 # gs <- ax - - # We don't read or write the stack before we get to 32-bit mode. No function - # calls, so we don't need to initialize the stack. - -# 0e: - # load more sectors from disk - b4 02 # ah <- 2 # read sectors from disk - # dl comes conveniently initialized at boot time with the index of the device being booted - b5 00 # ch <- 0 # cylinder 0 - b6 00 # dh <- 0 # track 0 - b1 02 # cl <- 2 # second sector, 1-based - b0 01 # al <- 1 # number of sectors to read - # address to write sectors to = es:bx = 0x7e00, contiguous with boot segment - bb 00 00 # bx <- 0 - 8e c3 # es <- bx - bb 00 7e # bx <- 0x7e00 - cd 13 # int 13h, BIOS disk service - 0f 82 76 00 # jump-if-carry disk-error - -# 26: - # undo the A20 hack: https://en.wikipedia.org/wiki/A20_line - # this is from https://github.com/mit-pdos/xv6-public/blob/master/bootasm.S - # seta20.1: - e4 64 # al <- port 0x64 - a8 02 # set zf if bit 1 (second-least significant) is not set - 75 fa # if zf not set, goto seta20.1 (-6) - - b0 d1 # al <- 0xd1 - e6 64 # port 0x64 <- al - -# 30: - # seta20.2: - e4 64 # al <- port 0x64 - a8 02 # set zf if bit 1 (second-least significant) is not set - 75 fa # if zf not set, goto seta20.2 (-6) - - b0 df # al <- 0xdf - e6 64 # port 0x64 <- al - -# 3a: - # switch to 32-bit mode - 0f 01 16 # lgdt 00/mod/indirect 010/subop 110/rm/use-disp16 - 80 7c # *gdt_descriptor -# 3f: - 0f 20 c0 # eax <- cr0 - 66 83 c8 01 # eax <- or 0x1 - 0f 22 c0 # cr0 <- eax - ea c0 7c 08 00 # far jump to initialize_32bit_mode after setting cs to the record at offset 8 in the gdt (gdt_code) - -# padding -# 4e: - 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -## GDT: 3 records of 8 bytes each - -# 60: -# gdt_start: -# gdt_null: mandatory null descriptor - 00 00 00 00 00 00 00 00 -# gdt_code: (offset 8 from gdt_start) - ff ff # limit[0:16] - 00 00 00 # base[0:24] - 9a # 1/present 00/privilege 1/descriptor type = 1001b - # 1/code 0/conforming 1/readable 0/accessed = 1010b - cf # 1/granularity 1/32-bit 0/64-bit-segment 0/AVL = 1100b - # limit[16:20] = 1111b - 00 # base[24:32] -# gdt_data: (offset 16 from gdt_start) - ff ff # limit[0:16] - 00 00 00 # base[0:24] - 92 # 1/present 00/privilege 1/descriptor type = 1001b - # 0/data 0/conforming 1/readable 0/accessed = 0010b - cf # same as gdt_code - 00 # base[24:32] -# gdt_end: - -# padding -# 78: - 00 00 00 00 00 00 00 00 - -# 80: -# gdt_descriptor: - 17 00 # final index of gdt = gdt_end - gdt_start - 1 - 60 7c 00 00 # start = gdt_start - -# padding -# 85: - 00 00 00 00 00 00 00 00 00 00 - -# 90: -# disk_error: - # print 'D' to top-left of screen to indicate disk error - # *0xb8000 <- 0x0f44 - # bx <- 0xb800 - bb 00 b8 - # ds <- bx - 8e db # 11b/mod 011b/reg/ds 011b/rm/bx - # al <- 'D' - b0 44 - # ah <- 0x0f # white on black - b4 0f - # bx <- 0 - bb 00 00 - # *ds:bx <- ax - 89 07 # 00b/mod/indirect 000b/reg/ax 111b/rm/bx - -e9 fb ff # loop forever - -# padding -# a1: - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -## 32-bit code from this point (still some instructions not in SubX) - -# c0: -# initialize_32bit_mode: - 66 b8 10 00 # ax <- offset 16 from gdt_start - 8e d8 # ds <- ax - 8e d0 # ss <- ax - 8e c0 # es <- ax - 8e e0 # fs <- ax - 8e e8 # gs <- ax - - # load interrupt handlers - 0f 01 1d # lidt 00/mod/indirect 011/subop 101/rm32/use-disp32 - 00 7f 00 00 # *idt_descriptor - - # enable keyboard IRQ - b0 fd # al <- 0xfd # enable just IRQ1 - e6 21 # port 0x21 <- al - - # initialization is done; enable interrupts - fb - e9 21 00 00 00 # jump to 0x7d00 - -# padding -# df: - 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -## 'application' SubX code: print one character to top-left of screen - -# offset 100 (address 0x7d00): -# Entry: - # eax <- *0x7ff4 # random address in second segment containing 'H' - 8b # copy rm32 to r32 - 05 # 00/mod/indirect 000/r32/eax 101/rm32/use-disp32 - # disp32 - f4 7f 00 00 - # *0xb8000 <- eax - 89 # copy r32 to rm32 - 05 # 00/mod/indirect 000/r32/eax 101/rm32/use-disp32 - # disp32 - 00 80 0b 00 - -e9 fb ff ff ff # loop forever - -# padding -# 111: - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# 120: -# null interrupt handler: - cf # iret - -# padding -# 121: - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# 130: -# keyboard interrupt handler: - # prologue - fa # disable interrupts - 60 # push all registers to stack - # acknowledge interrupt - b0 20 # al <- 0x20 - e6 20 # port 0x20 <- al - # check output buffer of 8042 keyboard controller (https://web.archive.org/web/20040604041507/http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/keyboard/atkeyboard.html) - e4 64 # al <- port 0x64 - a8 01 # set zf if bit 0 (least significant) is not set - 74 11 # if bit 0 is not set, skip to epilogue - # read keycode into eax - 31 c0 # eax <- xor eax; 11/direct 000/r32/eax 000/rm32/eax - e4 60 # al <- port 0x60 - # map key '1' to ascii; if eax == 2, eax = 0x31 - 3d 02 00 00 00 # compare eax with 0x02 - 75 0b # if not equal, goto epilogue - b8 31 0f 00 00 # eax <- 0x0f31 - # print eax to top-left of screen (*0xb8000) - 89 # copy r32 to rm32 - 05 # 00/mod/indirect 000/r32/eax 101/rm32/use-disp32 - # disp32 - 00 80 0b 00 - # epilogue - 61 # pop all registers - fb # enable interrupts - cf # iret - -# padding -# 155 - 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# final 2 bytes of boot sector -55 aa - -## sector 2 -# loaded by load_disk, not automatically on boot - -# offset 200 (address 0x7e00): interrupt descriptor table -# 32 entries * 8 bytes each = 256 bytes (0x100) -# idt_start: - -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 - -# entry 8: clock - 20 7d # target[0:16] = null interrupt handler - 08 00 # segment selector (gdt_code) - 00 # unused - 8e # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate - 00 00 # target[16:32] - -# entry 9: keyboard - 30 7d # target[0:16] = keyboard interrupt handler - 08 00 # segment selector (gdt_code) - 00 # unused - 8e # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate - 00 00 # target[16:32] - -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 -# idt_end: - -# offset 300 (address 0x7f00): -# idt_descriptor: - ff 00 # idt_end - idt_start - 1 - 00 7e 00 00 # start = idt_start - -# padding - 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -00 00 00 00 48 0f 00 00 00 00 00 00 00 00 00 00 # spot the 'H' with attributes -# offset 400 (address 0x8000) - -# vim:ft=conf diff --git a/baremetal/ex1.hex b/baremetal/ex1.hex deleted file mode 100644 index 6f969f90..00000000 --- a/baremetal/ex1.hex +++ /dev/null @@ -1,19 +0,0 @@ -# The simplest possible program: just an infinite loop. -# All is well if your computer clears screen and hangs without restarting. -# On an emulator the window may get bigger to accomodate the higher-resolution -# graphics mode. -# -# To convert to a disk image, first prepare a realistically sized disk image: -# dd if=/dev/zero of=disk.img count=20160 # 512-byte sectors, so 10MB -# Load the program on the disk image: -# cat baremetal/boot.hex baremetal/ex1.hex |./bootstrap run apps/hex > a.bin -# dd if=a.bin of=disk.img conv=notrunc -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img - -# main: (address 0x9400) -e9 fb ff ff ff # jump to main, hanging indefinitely - -# vim:ft=subx diff --git a/baremetal/ex1.subx b/baremetal/ex1.subx deleted file mode 100644 index 8a5dfdb7..00000000 --- a/baremetal/ex1.subx +++ /dev/null @@ -1,18 +0,0 @@ -# The simplest possible program: just an infinite loop. -# All is well if your computer clears screen and hangs without restarting. -# On an emulator the window may get bigger to accomodate the higher-resolution -# graphics mode. -# -# To build a disk image: -# ./translate_subx_baremetal baremetal/ex2.subx # emits disk.img -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img - -== code - -main: - e9/jump main/disp32 - -# vim:ft=subx diff --git a/baremetal/ex2.hex b/baremetal/ex2.hex deleted file mode 100644 index 6c06565f..00000000 --- a/baremetal/ex2.hex +++ /dev/null @@ -1,42 +0,0 @@ -# Test out the video mode by filling in the screen with pixels. -# -# To run, first prepare a realistically sized disk image: -# dd if=/dev/zero of=disk.img count=20160 # 512-byte sectors, so 10MB -# Load the program on the disk image: -# cat baremetal/boot.hex baremetal/ex2.hex |./bootstrap run apps/hex > a.bin -# dd if=a.bin of=disk.img conv=notrunc -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Expected output: -# html/baremetal.png - -# main: (address 0x9400) - -# ecx <- LFB -8b # copy *rm32 to r32 - 0d # 00/mod/indirect 001/r32/ecx 101/rm32/use-disp32 - 28 81 00 00 # disp32 [label] - -# eax <- LFB + 0xbffff (1024*768 - 1) -8d # copy-address rm32 to r32 - 81 # 10/mod/*+disp32 000/r32/eax 001/rm32/ecx - ff ff 0b 00 # disp32 - -# $loop: -# if (eax < ecx) break -39 # compare rm32 with r32 - c8 # 11/mod/direct 001/r32/ecx 000/rm32/eax -7c 05 # break if < [label] -# *eax <- al -88 # copy r8 to m8 at r32 - 00 # 00/mod/indirect 000/r8/AL 000/rm32/eax -48 # decrement eax -eb f7 # loop to -9 bytes [label] - -# $break: -e9 fb ff ff ff # hang indefinitely - -# vim:ft=subx diff --git a/baremetal/ex2.mu b/baremetal/ex2.mu deleted file mode 100644 index adc905e9..00000000 --- a/baremetal/ex2.mu +++ /dev/null @@ -1,31 +0,0 @@ -# Test out the video mode by filling in the screen with pixels. -# -# To build a disk image: -# ./translate_mu_baremetal baremetal/ex2.mu # emits disk.img -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Expected output: -# html/baremetal.png - -fn main { - var y/eax: int <- copy 0 - { - compare y, 0x300/screen-height=768 - break-if->= - var x/edx: int <- copy 0 - { - compare x, 0x400/screen-width=1024 - break-if->= - var color/ecx: int <- copy x - color <- and 0xff - pixel-on-real-screen x, y, color - x <- increment - loop - } - y <- increment - loop - } -} diff --git a/baremetal/ex2.subx b/baremetal/ex2.subx deleted file mode 100644 index 074d641e..00000000 --- a/baremetal/ex2.subx +++ /dev/null @@ -1,35 +0,0 @@ -# Test out the video mode by filling in the screen with pixels. -# -# To build a disk image: -# ./translate_subx_baremetal baremetal/ex2.subx # emits disk.img -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Expected output: -# html/baremetal.png - -== code - -main: - # ecx <- start of video memory - 8b/-> *0x8128 1/r32/ecx - - # eax <- final pixel of video memory - 8d/copy-address *(ecx + 0x0bffff) 0/r32/eax # 0xbffff = 1024*768 - 1 - - # for each pixel in video memory - { - 39/compare %eax 1/r32/ecx - 7c/jump-if-< break/disp8 - # write its column number to it - 88/byte<- *eax 0/r32/AL - 48/decrement-eax - eb/jump loop/disp8 - } - - # hang indefinitely - { - eb/jump loop/disp8 - } diff --git a/baremetal/ex3.hex b/baremetal/ex3.hex deleted file mode 100644 index d3639948..00000000 --- a/baremetal/ex3.hex +++ /dev/null @@ -1,58 +0,0 @@ -# Draw pixels in response to keyboard events, starting from the top-left -# and in raster order. -# -# To run, first prepare a realistically sized disk image: -# dd if=/dev/zero of=disk.img count=20160 # 512-byte sectors, so 10MB -# Load the program on the disk image: -# cat baremetal/boot.hex baremetal/ex3.hex |./bootstrap run apps/hex > a.bin -# dd if=a.bin of=disk.img conv=notrunc -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img - -# main: (address 0x9000) - -# eax <- LFB -8b # copy *rm32 to r32 - 05 # 00/mod/indirect 000/r32/eax 101/rm32/use-disp32 - 28 81 00 00 # disp32 [label] - -# var read index/ecx: byte = 0 -31 c9 # ecx <- xor ecx; 11/direct 001/r32/ecx 001/rm32/ecx - -# $loop: - # CL = *read index - 8a # copy m8 at r32 to r8 - 0d # 00/mod/indirect 001/r8/cl 101/rm32/use-disp32 - cc 7d 00 00 # disp32 [label] - # CL = *(keyboard buffer + ecx) - 8a # copy m8 at r32 to r8 - 89 # 10/mod/*+disp32 001/r8/cl 001/rm32/ecx - d0 7d 00 00 # disp32 [label] - # if (CL == 0) loop (spin loop) - 80 - f9 # 11/mod/direct 111/subop/compare 001/rm8/CL - 00 # imm8 - 74 ef # loop -17 [label] -# offset 0x19: - # otherwise increment read index - fe # increment byte - 05 # 00/mod/indirect 000/subop/increment 101/rm32/use-disp32 - cc 7d 00 00 # disp32 [label] - # clear top nibble of index (keyboard buffer is circular) - 80 # and byte - 25 # 00/mod/indirect 100/subop/and 101/rm32/use-disp32 - cc 7d 00 00 # disp32 [label] - 0f # imm8 - # print a pixel in fluorescent green - c6 # copy imm8 to m8 at rm32 - 00 # 00/mod/indirect 000/subop 000/rm32/eax - 31 # imm32 - 40 # increment eax - eb dc # loop -36 [label] - -# $break: -e9 fb ff ff ff # hang indefinitely - -# vim:ft=subx diff --git a/baremetal/ex3.mu b/baremetal/ex3.mu deleted file mode 100644 index e174ca22..00000000 --- a/baremetal/ex3.mu +++ /dev/null @@ -1,31 +0,0 @@ -# Draw pixels in response to keyboard events, starting from the top-left -# and in raster order. -# -# To build a disk image: -# ./translate_mu_baremetal baremetal/ex3.mu # emits disk.img -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Expected output: a new green pixel starting from the top left corner of the -# screen every time you press a key (letter or digit) - -fn main { - var x/ecx: int <- copy 0 - var y/edx: int <- copy 0 - { - var key/eax: byte <- read-key 0/keyboard - compare key, 0 - loop-if-= # busy wait - pixel-on-real-screen x, y, 0x31/green - x <- increment - compare x, 0x400/screen-width=1024 - { - break-if-< - y <- increment - x <- copy 0 - } - loop - } -} diff --git a/baremetal/ex4.mu b/baremetal/ex4.mu deleted file mode 100644 index 5b883131..00000000 --- a/baremetal/ex4.mu +++ /dev/null @@ -1,14 +0,0 @@ -# Draw a character using the built-in font (GNU unifont) -# -# To build a disk image: -# ./translate_mu_baremetal baremetal/ex4.mu # emits disk.img -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Expected output: letter 'A' in green near the top-left corner of screen - -fn main { - draw-codepoint 0/screen, 0x41/A, 2/row, 1/col, 0xa/fg, 0/bg -} diff --git a/baremetal/ex5.mu b/baremetal/ex5.mu deleted file mode 100644 index 1f3bea10..00000000 --- a/baremetal/ex5.mu +++ /dev/null @@ -1,16 +0,0 @@ -# Draw a single line of ASCII text using the built-in font (GNU unifont) -# Also demonstrates bounds-checking _before_ drawing. -# -# To build a disk image: -# ./translate_mu_baremetal baremetal/ex5.mu # emits disk.img -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Expected output: text in green near the top-left corner of screen - -fn main { - var dummy/eax: int <- draw-text-rightward 0/screen, "hello from baremetal Mu!", 0x10/x, 0x400/xmax, 0x10/y, 0xa/color - dummy <- draw-text-rightward 0/screen, "you shouldn't see this", 0x10/x, 0xa0/xmax, 0x30/y, 0x3/color # xmax is too narrow -} diff --git a/baremetal/ex6.mu b/baremetal/ex6.mu deleted file mode 100644 index d209e3f6..00000000 --- a/baremetal/ex6.mu +++ /dev/null @@ -1,32 +0,0 @@ -# Drawing ASCII text incrementally. -# -# To build a disk image: -# ./translate_mu_baremetal baremetal/ex6.mu # emits disk.img -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Expected output: a box and text that doesn't overflow it - -fn main { - # drawing text within a bounding box - draw-box-on-real-screen 0xf, 0x1f, 0x79, 0x51, 0x4 - var x/eax: int <- copy 0x20 - var y/ecx: int <- copy 0x20 - x, y <- draw-text-wrapping-right-then-down 0/screen, "hello ", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/color - x, y <- draw-text-wrapping-right-then-down 0/screen, "from ", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/color - x, y <- draw-text-wrapping-right-then-down 0/screen, "baremetal ", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/color - x, y <- draw-text-wrapping-right-then-down 0/screen, "Mu!", 0x10/xmin, 0x20/ymin, 0x78/xmax, 0x50/ymax, x, y, 0xa/color - - # drawing at the cursor in multiple directions - draw-text-wrapping-down-then-right-from-cursor-over-full-screen 0/screen, "abc", 0xa - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "def", 0xa - - # test drawing near the edge - x <- draw-text-rightward 0/screen, "R", 0x3f8/x, 0x400/xmax=screen-width, 0x100/y, 0xa/color - draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "wrapped from R", 0xa - - x <- draw-text-downward 0/screen, "D", 0x100/x, 0x2f0/y, 0x300/ymax=screen-height, 0xa/color - draw-text-wrapping-down-then-right-from-cursor-over-full-screen 0/screen, "wrapped from D", 0xa -} diff --git a/baremetal/ex7.mu b/baremetal/ex7.mu deleted file mode 100644 index 30e3c1bc..00000000 --- a/baremetal/ex7.mu +++ /dev/null @@ -1,46 +0,0 @@ -# Cursor-based motions. -# -# To build a disk image: -# ./translate_mu_baremetal baremetal/ex7.mu # emits disk.img -# To run: -# qemu-system-i386 disk.img -# Or: -# bochs -f baremetal/boot.bochsrc # boot.bochsrc loads disk.img -# -# Expected output: an interactive game a bit like "snakes". Try pressing h, j, -# k, l. - -fn main { - var space/eax: grapheme <- copy 0x20 - set-cursor-position 0/screen, 0, 0 - { - show-cursor 0/screen, space - var key/eax: byte <- read-key 0/keyboard - { - compare key, 0x68/h - break-if-!= - draw-code-point-at-cursor 0/screen, 0x2d/dash, 0x31/fg, 0/bg - move-cursor-left 0 - } - { - compare key, 0x6a/j - break-if-!= - draw-code-point-at-cursor 0/screen, 0x7c/vertical-bar, 0x31/fg, 0/bg - move-cursor-down 0 - } - { - compare key, 0x6b/k - break-if-!= - draw-code-point-at-cursor 0/screen, 0x7c/vertical-bar, 0x31/fg, 0/bg - move-cursor-up 0 - } - { - compare key, 0x6c/l - break-if-!= - var g/eax: code-point <- copy 0x2d/dash - draw-code-point-at-cursor 0/screen, 0x2d/dash, 0x31/fg, 0/bg - move-cursor-right 0 - } - loop - } -} diff --git a/baremetal/ex8.mu b/baremetal/ex8.mu deleted file mode 100644 index 367c665f..00000000 --- a/baremetal/ex8.mu +++ /dev/null @@ -1,6 +0,0 @@ -# Demo of floating-point - -fn main { - var n/eax: int <- copy 0 - var result/xmm0: float <- convert n -} diff --git a/baremetal/life.mu b/baremetal/life.mu deleted file mode 100644 index c8643ea9..00000000 --- a/baremetal/life.mu +++ /dev/null @@ -1,252 +0,0 @@ -# Conway's Game of Life -# -# To build: -# $ ./translate_mu_baremetal baremetal/life.mu -# To run: -# $ qemu-system-i386 disk.img - -fn state _grid: (addr array boolean), x: int, y: int -> _/eax: boolean { - # clip at the edge - compare x, 0 - { - break-if->= - return 0/false - } - compare y, 0 - { - break-if->= - return 0/false - } - compare x, 0x100/width - { - break-if-< - return 0/false - } - compare y, 0xc0/height - { - break-if-< - return 0/false - } - var idx/eax: int <- copy y - idx <- shift-left 8/log2width - idx <- add x - var grid/esi: (addr array boolean) <- copy _grid - var result/eax: (addr boolean) <- index grid, idx - return *result -} - -fn set-state _grid: (addr array boolean), x: int, y: int, val: boolean { - # don't bother checking bounds - var idx/eax: int <- copy y - idx <- shift-left 8/log2width - idx <- add x - var grid/esi: (addr array boolean) <- copy _grid - var result/eax: (addr boolean) <- index grid, idx - var src/ecx: boolean <- copy val - copy-to *result, src -} - -fn num-live-neighbors grid: (addr array boolean), x: int, y: int -> _/eax: int { - var result/edi: int <- copy 0 - # row above: zig - decrement y - decrement x - var s/eax: boolean <- state grid, x, y - { - compare s, 0/false - break-if-= - result <- increment - } - increment x - s <- state grid, x, y - { - compare s, 0/false - break-if-= - result <- increment - } - increment x - s <- state grid, x, y - { - compare s, 0/false - break-if-= - result <- increment - } - # curr row: zag - increment y - s <- state grid, x, y - { - compare s, 0/false - break-if-= - result <- increment - } - subtract-from x, 2 - s <- state grid, x, y - { - compare s, 0/false - break-if-= - result <- increment - } - # row below: zig - increment y - s <- state grid, x, y - { - compare s, 0/false - break-if-= - result <- increment - } - increment x - s <- state grid, x, y - { - compare s, 0/false - break-if-= - result <- increment - } - increment x - s <- state grid, x, y - { - compare s, 0/false - break-if-= - result <- increment - } - return result -} - -fn step old-grid: (addr array boolean), new-grid: (addr array boolean) { - var y/ecx: int <- copy 0 - { - compare y, 0xc0/height - break-if->= - var x/edx: int <- copy 0 - { - compare x, 0x100/width - break-if->= - var n/eax: int <- num-live-neighbors old-grid, x, y - # if neighbors < 2, die of loneliness - { - compare n, 2 - break-if->= - set-state new-grid, x, y, 0/dead - } - # if neighbors > 3, die of overcrowding - { - compare n, 3 - break-if-<= - set-state new-grid, x, y, 0/dead - } - # if neighbors = 2, preserve state - { - compare n, 2 - break-if-!= - var old-state/eax: boolean <- state old-grid, x, y - set-state new-grid, x, y, old-state - } - # if neighbors = 3, cell quickens to life - { - compare n, 3 - break-if-!= - set-state new-grid, x, y, 1/live - } - x <- increment - loop - } - y <- increment - loop - } -} - -# color a square of size 'side' starting at x*side, y*side -fn render-square _x: int, _y: int, color: int { - var y/edx: int <- copy _y - y <- shift-left 2/log2side - var side/ebx: int <- copy 1 - side <- shift-left 2/log2side - var ymax/ecx: int <- copy y - ymax <- add side - { - compare y, ymax - break-if->= - { - var x/eax: int <- copy _x - x <- shift-left 2/log2side - var xmax/ecx: int <- copy x - xmax <- add side - { - compare x, xmax - break-if->= - pixel-on-real-screen x, y, color - x <- increment - loop - } - } - y <- increment - loop - } -} - -fn render grid: (addr array boolean) { - var y/ecx: int <- copy 0 - { - compare y, 0xc0/height - break-if->= - var x/edx: int <- copy 0 - { - compare x, 0x100/width - break-if->= - var state/eax: boolean <- state grid, x, y - compare state, 0/false - { - break-if-= - render-square x, y, 3/cyan - } - compare state, 0/false - { - break-if-!= - render-square x, y, 0/black - } - x <- increment - loop - } - y <- increment - loop - } -} - -fn main { -#? # allocate on the stack -#? var grid1-storage: (array boolean 0xc000) # width * height -#? var grid1/esi: (addr array boolean) <- address grid1-storage -#? var grid2-storage: (array boolean 0xc000) # width * height -#? var grid2/edi: (addr array boolean) <- address grid2-storage - # allocate on the heap - var grid1-storage: (handle array boolean) - var grid1-ah/eax: (addr handle array boolean) <- address grid1-storage - populate grid1-ah, 0xc000 # width * height - var _grid1/eax: (addr array boolean) <- lookup *grid1-ah - var grid1/esi: (addr array boolean) <- copy _grid1 - var grid2-storage: (handle array boolean) - var grid2-ah/eax: (addr handle array boolean) <- address grid2-storage - populate grid2-ah, 0xc000 # width * height - var _grid2/eax: (addr array boolean) <- lookup *grid2-ah - var grid2/edi: (addr array boolean) <- copy _grid2 - # initialize grid1 - set-state grid1, 0x80, 0x5f, 1/live - set-state grid1, 0x81, 0x5f, 1/live - set-state grid1, 0x7f, 0x60, 1/live - set-state grid1, 0x80, 0x60, 1/live - set-state grid1, 0x80, 0x61, 1/live - # render grid1 - render grid1 - { - var key/eax: byte <- read-key 0/keyboard - compare key, 0 -#? loop-if-= # press key to step - break-if-!= # press key to quit - # iter: grid1 -> grid2 - step grid1, grid2 - render grid2 - # iter: grid2 -> grid1 - step grid2, grid1 - render grid1 - loop - } -} diff --git a/baremetal/mu-init.subx b/baremetal/mu-init.subx deleted file mode 100644 index 26b83451..00000000 --- a/baremetal/mu-init.subx +++ /dev/null @@ -1,27 +0,0 @@ -# Initialize the minimal runtime for Mu programs. -# -# See translate_mu_baremetal for how this file is used. -# -# Mu baremetal programs start at a function called 'main' without inouts or outputs. - -== code - -# initialize stack -bd/copy-to-ebp 0/imm32 -# always first run tests -(run-tests) -(num-test-failures) # => eax -# call main if tests all passed -{ - 3d/compare-eax-and 0/imm32 - 75/jump-if-!= break/disp8 - (clear-real-screen) - c7 0/subop/copy *Real-screen-cursor-x 0/imm32 - c7 0/subop/copy *Real-screen-cursor-y 0/imm32 - (main) -} - -# hang indefinitely -{ - eb/jump loop/disp8 -} diff --git a/baremetal/rpn.mu b/baremetal/rpn.mu deleted file mode 100644 index eaccccdf..00000000 --- a/baremetal/rpn.mu +++ /dev/null @@ -1,152 +0,0 @@ -# Integer arithmetic using postfix notation -# -# Limitations: -# Division not implemented yet. -# -# To build: -# $ ./translate_mu_baremetal baremetal/rpn.mu -# -# Example session: -# $ qemu-system-i386 disk.img -# > 4 -# 4 -# > 5 3 - -# 2 -# -# Error handling is non-existent. This is just a prototype. - -fn main { - var in-storage: (stream byte 0x80) - var in/esi: (addr stream byte) <- address in-storage - var y/ecx: int <- copy 0 - var space/edx: grapheme <- copy 0x20 - # read-eval-print loop - { - # print prompt - var x/eax: int <- draw-text-rightward 0/screen, "> ", 0/x, 0x80/xmax, y, 3/fg/cyan, 0/bg - set-cursor-position 0/screen, x, y - # read line from keyboard - clear-stream in - { - show-cursor 0/screen, space - var key/eax: byte <- read-key 0/keyboard - compare key, 0xa/newline - break-if-= - compare key, 0 - loop-if-= - var key2/eax: int <- copy key - append-byte in, key2 - var g/eax: grapheme <- copy key2 - draw-grapheme-at-cursor 0/screen, g, 0xf/fg, 0/bg - move-cursor-right 0 - loop - } - # clear cursor - draw-grapheme-at-cursor 0/screen, space, 3/fg/never-used, 0/bg - # parse and eval - var out/eax: int <- simplify in - # print - y <- increment - out, y <- draw-int32-decimal-wrapping-right-then-down 0/screen, out, 0/xmin, y, 0x80/xmax, 0x30/ymax, 0/x, y, 7/fg, 0/bg - # newline - y <- increment - # - loop - } -} - -type int-stack { - data: (handle array int) - top: int -} - -fn simplify in: (addr stream byte) -> _/eax: int { - var word-storage: slice - var word/ecx: (addr slice) <- address word-storage - var stack-storage: int-stack - var stack/esi: (addr int-stack) <- address stack-storage - initialize-int-stack stack, 0x10 - $simplify:word-loop: { - next-word in, word - var done?/eax: boolean <- slice-empty? word - compare done?, 0 - break-if-!= - # if word is an operator, perform it - { - var is-add?/eax: boolean <- slice-equal? word, "+" - compare is-add?, 0 - break-if-= - var _b/eax: int <- pop-int-stack stack - var b/edx: int <- copy _b - var a/eax: int <- pop-int-stack stack - a <- add b - push-int-stack stack, a - loop $simplify:word-loop - } - { - var is-sub?/eax: boolean <- slice-equal? word, "-" - compare is-sub?, 0 - break-if-= - var _b/eax: int <- pop-int-stack stack - var b/edx: int <- copy _b - var a/eax: int <- pop-int-stack stack - a <- subtract b - push-int-stack stack, a - loop $simplify:word-loop - } - { - var is-mul?/eax: boolean <- slice-equal? word, "*" - compare is-mul?, 0 - break-if-= - var _b/eax: int <- pop-int-stack stack - var b/edx: int <- copy _b - var a/eax: int <- pop-int-stack stack - a <- multiply b - push-int-stack stack, a - loop $simplify:word-loop - } - # otherwise it's an int - var n/eax: int <- parse-decimal-int-from-slice word - push-int-stack stack, n - loop - } - var result/eax: int <- pop-int-stack stack - return result -} - -fn initialize-int-stack _self: (addr int-stack), n: int { - var self/esi: (addr int-stack) <- copy _self - var d/edi: (addr handle array int) <- get self, data - populate d, n - var top/eax: (addr int) <- get self, top - copy-to *top, 0 -} - -fn push-int-stack _self: (addr int-stack), _val: int { - var self/esi: (addr int-stack) <- copy _self - var top-addr/ecx: (addr int) <- get self, top - var data-ah/edx: (addr handle array int) <- get self, data - var data/eax: (addr array int) <- lookup *data-ah - var top/edx: int <- copy *top-addr - var dest-addr/edx: (addr int) <- index data, top - var val/eax: int <- copy _val - copy-to *dest-addr, val - add-to *top-addr, 1 -} - -fn pop-int-stack _self: (addr int-stack) -> _/eax: int { - var self/esi: (addr int-stack) <- copy _self - var top-addr/ecx: (addr int) <- get self, top - { - compare *top-addr, 0 - break-if-> - return 0 - } - subtract-from *top-addr, 1 - var data-ah/edx: (addr handle array int) <- get self, data - var data/eax: (addr array int) <- lookup *data-ah - var top/edx: int <- copy *top-addr - var result-addr/eax: (addr int) <- index data, top - var val/eax: int <- copy *result-addr - return val -} diff --git a/baremetal/shell/cell.mu b/baremetal/shell/cell.mu deleted file mode 100644 index 59558fb9..00000000 --- a/baremetal/shell/cell.mu +++ /dev/null @@ -1,89 +0,0 @@ -type cell { - type: int - # type 0: pair - left: (handle cell) - right: (handle cell) - # type 1: number - number-data: float - # type 2: symbol - # type 3: string - text-data: (handle stream byte) - # TODO: array, (associative) table, stream -} - -fn allocate-symbol _out: (addr handle cell) { - var out/eax: (addr handle cell) <- copy _out - allocate out - var out-addr/eax: (addr cell) <- lookup *out - var type/ecx: (addr int) <- get out-addr, type - copy-to *type, 2/symbol - var dest-ah/eax: (addr handle stream byte) <- get out-addr, text-data - populate-stream dest-ah, 0x40/max-symbol-size -} - -fn initialize-symbol _out: (addr handle cell), val: (addr array byte) { - var out/eax: (addr handle cell) <- copy _out - var out-addr/eax: (addr cell) <- lookup *out - var dest-ah/eax: (addr handle stream byte) <- get out-addr, text-data - var dest/eax: (addr stream byte) <- lookup *dest-ah - write dest, val -} - -fn new-symbol out: (addr handle cell), val: (addr array byte) { - allocate-symbol out - initialize-symbol out, val -} - -fn allocate-number _out: (addr handle cell) { - var out/eax: (addr handle cell) <- copy _out - allocate out - var out-addr/eax: (addr cell) <- lookup *out - var type/ecx: (addr int) <- get out-addr, type - copy-to *type, 1/number -} - -fn initialize-integer _out: (addr handle cell), n: int { - var out/eax: (addr handle cell) <- copy _out - var out-addr/eax: (addr cell) <- lookup *out - var dest-ah/eax: (addr float) <- get out-addr, number-data - var src/xmm0: float <- convert n - copy-to *dest-ah, src -} - -fn new-integer out: (addr handle cell), n: int { - allocate-number out - initialize-integer out, n -} - -fn initialize-float _out: (addr handle cell), n: float { - var out/eax: (addr handle cell) <- copy _out - var out-addr/eax: (addr cell) <- lookup *out - var dest-ah/eax: (addr float) <- get out-addr, number-data - var src/xmm0: float <- copy n - copy-to *dest-ah, src -} - -fn new-float out: (addr handle cell), n: float { - allocate-number out - initialize-float out, n -} - -fn allocate-pair _out: (addr handle cell) { - var out/eax: (addr handle cell) <- copy _out - allocate out - # new cells have type pair by default -} - -fn initialize-pair _out: (addr handle cell), left: (handle cell), right: (handle cell) { - var out/eax: (addr handle cell) <- copy _out - var out-addr/eax: (addr cell) <- lookup *out - var dest-ah/ecx: (addr handle cell) <- get out-addr, left - copy-handle left, dest-ah - dest-ah <- get out-addr, right - copy-handle right, dest-ah -} - -fn new-pair out: (addr handle cell), left: (handle cell), right: (handle cell) { - allocate-pair out - initialize-pair out, left, right -} diff --git a/baremetal/shell/eval.mu b/baremetal/shell/eval.mu deleted file mode 100644 index e69de29b..00000000 --- a/baremetal/shell/eval.mu +++ /dev/null diff --git a/baremetal/shell/gap-buffer.mu b/baremetal/shell/gap-buffer.mu deleted file mode 100644 index 81537e9c..00000000 --- a/baremetal/shell/gap-buffer.mu +++ /dev/null @@ -1,781 +0,0 @@ -# primitive for editing a single word - -type gap-buffer { - left: grapheme-stack - right: grapheme-stack - # some fields for scanning incrementally through a gap-buffer - left-read-index: int - right-read-index: int -} - -fn initialize-gap-buffer _self: (addr gap-buffer), max-word-size: int { - var self/esi: (addr gap-buffer) <- copy _self - var left/eax: (addr grapheme-stack) <- get self, left - initialize-grapheme-stack left, max-word-size - var right/eax: (addr grapheme-stack) <- get self, right - initialize-grapheme-stack right, max-word-size -} - -# just for tests -fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) { - initialize-gap-buffer self, 0x10/max-word-size - var stream-storage: (stream byte 0x10/max-word-size) - var stream/ecx: (addr stream byte) <- address stream-storage - write stream, s - { - var done?/eax: boolean <- stream-empty? stream - compare done?, 0/false - break-if-!= - var g/eax: grapheme <- read-grapheme stream - add-grapheme-at-gap self, g - loop - } -} - -fn emit-gap-buffer _self: (addr gap-buffer), out: (addr stream byte) { - var self/esi: (addr gap-buffer) <- copy _self - clear-stream out - var left/eax: (addr grapheme-stack) <- get self, left - emit-stack-from-bottom left, out - var right/eax: (addr grapheme-stack) <- get self, right - emit-stack-from-top right, out -} - -# dump stack from bottom to top -fn emit-stack-from-bottom _self: (addr grapheme-stack), out: (addr stream byte) { - var self/esi: (addr grapheme-stack) <- copy _self - var data-ah/edi: (addr handle array grapheme) <- get self, data - var _data/eax: (addr array grapheme) <- lookup *data-ah - var data/edi: (addr array grapheme) <- copy _data - var top-addr/ecx: (addr int) <- get self, top - var i/eax: int <- copy 0 - { - compare i, *top-addr - break-if->= - var g/edx: (addr grapheme) <- index data, i - write-grapheme out, *g - i <- increment - loop - } -} - -# dump stack from top to bottom -fn emit-stack-from-top _self: (addr grapheme-stack), out: (addr stream byte) { - var self/esi: (addr grapheme-stack) <- copy _self - var data-ah/edi: (addr handle array grapheme) <- get self, data - var _data/eax: (addr array grapheme) <- lookup *data-ah - var data/edi: (addr array grapheme) <- copy _data - var top-addr/ecx: (addr int) <- get self, top - var i/eax: int <- copy *top-addr - i <- decrement - { - compare i, 0 - break-if-< - var g/edx: (addr grapheme) <- index data, i - write-grapheme out, *g - i <- decrement - loop - } -} - -# We implicitly render everything editable in a single color, and assume the -# cursor is a single other color. -fn render-gap-buffer-wrapping-right-then-down screen: (addr screen), _gap: (addr gap-buffer), xmin: int, ymin: int, xmax: int, ymax: int, render-cursor?: boolean -> _/eax: int, _/ecx: int { - var gap/esi: (addr gap-buffer) <- copy _gap - var left/edx: (addr grapheme-stack) <- get gap, left - var x2/eax: int <- copy 0 - var y2/ecx: int <- copy 0 - x2, y2 <- render-stack-from-bottom-wrapping-right-then-down screen, left, xmin, ymin, xmax, ymax, xmin, ymin - var right/edx: (addr grapheme-stack) <- get gap, right - x2, y2 <- render-stack-from-top-wrapping-right-then-down screen, right, xmin, ymin, xmax, ymax, x2, y2, render-cursor? - # decide whether we still need to print a cursor - var bg/ebx: int <- copy 0 - compare render-cursor?, 0/false - { - break-if-= - # if the right side is empty, grapheme stack didn't print the cursor - var empty?/eax: boolean <- grapheme-stack-empty? right - compare empty?, 0/false - break-if-= - bg <- copy 7/cursor - } - # print a grapheme either way so that cursor position doesn't affect printed width - var space/edx: grapheme <- copy 0x20 - x2, y2 <- render-grapheme screen, space, xmin, ymin, xmax, ymax, x2, y2, 3/fg=cyan, bg - return x2, y2 -} - -fn render-gap-buffer screen: (addr screen), gap: (addr gap-buffer), x: int, y: int, render-cursor?: boolean -> _/eax: int { - var _width/eax: int <- copy 0 - var _height/ecx: int <- copy 0 - _width, _height <- screen-size screen - var width/edx: int <- copy _width - var height/ebx: int <- copy _height - var x2/eax: int <- copy 0 - var y2/ecx: int <- copy 0 - x2, y2 <- render-gap-buffer-wrapping-right-then-down screen, gap, x, y, width, height, render-cursor? - return x2 # y2? yolo -} - -fn gap-buffer-length _gap: (addr gap-buffer) -> _/eax: int { - var gap/esi: (addr gap-buffer) <- copy _gap - var left/eax: (addr grapheme-stack) <- get gap, left - var tmp/eax: (addr int) <- get left, top - var left-length/ecx: int <- copy *tmp - var right/esi: (addr grapheme-stack) <- get gap, right - tmp <- get right, top - var result/eax: int <- copy *tmp - result <- add left-length - return result -} - -fn add-grapheme-at-gap _self: (addr gap-buffer), g: grapheme { - var self/esi: (addr gap-buffer) <- copy _self - var left/eax: (addr grapheme-stack) <- get self, left - push-grapheme-stack left, g -} - -fn gap-to-start self: (addr gap-buffer) { - { - var curr/eax: grapheme <- gap-left self - compare curr, -1 - loop-if-!= - } -} - -fn gap-to-end self: (addr gap-buffer) { - { - var curr/eax: grapheme <- gap-right self - compare curr, -1 - loop-if-!= - } -} - -fn gap-at-start? _self: (addr gap-buffer) -> _/eax: boolean { - var self/esi: (addr gap-buffer) <- copy _self - var left/eax: (addr grapheme-stack) <- get self, left - var result/eax: boolean <- grapheme-stack-empty? left - return result -} - -fn gap-at-end? _self: (addr gap-buffer) -> _/eax: boolean { - var self/esi: (addr gap-buffer) <- copy _self - var right/eax: (addr grapheme-stack) <- get self, right - var result/eax: boolean <- grapheme-stack-empty? right - return result -} - -fn gap-right _self: (addr gap-buffer) -> _/eax: grapheme { - var self/esi: (addr gap-buffer) <- copy _self - var g/eax: grapheme <- copy 0 - var right/ecx: (addr grapheme-stack) <- get self, right - g <- pop-grapheme-stack right - compare g, -1 - { - break-if-= - var left/ecx: (addr grapheme-stack) <- get self, left - push-grapheme-stack left, g - } - return g -} - -fn gap-left _self: (addr gap-buffer) -> _/eax: grapheme { - var self/esi: (addr gap-buffer) <- copy _self - var g/eax: grapheme <- copy 0 - { - var left/ecx: (addr grapheme-stack) <- get self, left - g <- pop-grapheme-stack left - } - compare g, -1 - { - break-if-= - var right/ecx: (addr grapheme-stack) <- get self, right - push-grapheme-stack right, g - } - return g -} - -fn index-of-gap _self: (addr gap-buffer) -> _/eax: int { - var self/eax: (addr gap-buffer) <- copy _self - var left/eax: (addr grapheme-stack) <- get self, left - var top-addr/eax: (addr int) <- get left, top - var result/eax: int <- copy *top-addr - return result -} - -fn first-grapheme-in-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme { - var self/esi: (addr gap-buffer) <- copy _self - # try to read from left - var left/eax: (addr grapheme-stack) <- get self, left - var top-addr/ecx: (addr int) <- get left, top - compare *top-addr, 0 - { - break-if-<= - var data-ah/eax: (addr handle array grapheme) <- get left, data - var data/eax: (addr array grapheme) <- lookup *data-ah - var result-addr/eax: (addr grapheme) <- index data, 0 - return *result-addr - } - # try to read from right - var right/eax: (addr grapheme-stack) <- get self, right - top-addr <- get right, top - compare *top-addr, 0 - { - break-if-<= - var data-ah/eax: (addr handle array grapheme) <- get right, data - var data/eax: (addr array grapheme) <- lookup *data-ah - var top/ecx: int <- copy *top-addr - top <- decrement - var result-addr/eax: (addr grapheme) <- index data, top - return *result-addr - } - # give up - return -1 -} - -fn grapheme-before-cursor-in-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme { - var self/esi: (addr gap-buffer) <- copy _self - # try to read from left - var left/ecx: (addr grapheme-stack) <- get self, left - var top-addr/edx: (addr int) <- get left, top - compare *top-addr, 0 - { - break-if-<= - var result/eax: grapheme <- pop-grapheme-stack left - push-grapheme-stack left, result - return result - } - # give up - return -1 -} - -fn delete-before-gap _self: (addr gap-buffer) { - var self/eax: (addr gap-buffer) <- copy _self - var left/eax: (addr grapheme-stack) <- get self, left - var dummy/eax: grapheme <- pop-grapheme-stack left -} - -fn pop-after-gap _self: (addr gap-buffer) -> _/eax: grapheme { - var self/eax: (addr gap-buffer) <- copy _self - var right/eax: (addr grapheme-stack) <- get self, right - var result/eax: grapheme <- pop-grapheme-stack right - return result -} - -fn gap-buffer-equal? _self: (addr gap-buffer), s: (addr array byte) -> _/eax: boolean { - var self/esi: (addr gap-buffer) <- copy _self - # complication: graphemes may be multiple bytes - # so don't rely on length - # instead turn the expected result into a stream and arrange to read from it in order - var stream-storage: (stream byte 0x10/max-word-size) - var expected-stream/ecx: (addr stream byte) <- address stream-storage - write expected-stream, s - # compare left - var left/edx: (addr grapheme-stack) <- get self, left - var result/eax: boolean <- prefix-match? left, expected-stream - compare result, 0/false - { - break-if-!= - return result - } - # compare right - var right/edx: (addr grapheme-stack) <- get self, right - result <- suffix-match? right, expected-stream - compare result, 0/false - { - break-if-!= - return result - } - # ensure there's nothing left over - result <- stream-empty? expected-stream - return result -} - -fn test-gap-buffer-equal-from-end { - var _g: gap-buffer - var g/esi: (addr gap-buffer) <- address _g - initialize-gap-buffer g, 0x10 - # - var c/eax: grapheme <- copy 0x61/a - add-grapheme-at-gap g, c - add-grapheme-at-gap g, c - add-grapheme-at-gap g, c - # gap is at end (right is empty) - var result/eax: boolean <- gap-buffer-equal? g, "aaa" - check result, "F - test-gap-buffer-equal-from-end" -} - -fn test-gap-buffer-equal-from-middle { - var _g: gap-buffer - var g/esi: (addr gap-buffer) <- address _g - initialize-gap-buffer g, 0x10 - # - var c/eax: grapheme <- copy 0x61/a - add-grapheme-at-gap g, c - add-grapheme-at-gap g, c - add-grapheme-at-gap g, c - var dummy/eax: grapheme <- gap-left g - # gap is in the middle - var result/eax: boolean <- gap-buffer-equal? g, "aaa" - check result, "F - test-gap-buffer-equal-from-middle" -} - -fn test-gap-buffer-equal-from-start { - var _g: gap-buffer - var g/esi: (addr gap-buffer) <- address _g - initialize-gap-buffer g, 0x10 - # - var c/eax: grapheme <- copy 0x61/a - add-grapheme-at-gap g, c - add-grapheme-at-gap g, c - add-grapheme-at-gap g, c - var dummy/eax: grapheme <- gap-left g - dummy <- gap-left g - dummy <- gap-left g - # gap is at the start - var result/eax: boolean <- gap-buffer-equal? g, "aaa" - check result, "F - test-gap-buffer-equal-from-start" -} - -fn test-gap-buffer-equal-fails { - # g = "aaa" - var _g: gap-buffer - var g/esi: (addr gap-buffer) <- address _g - initialize-gap-buffer g, 0x10 - var c/eax: grapheme <- copy 0x61/a - add-grapheme-at-gap g, c - add-grapheme-at-gap g, c - add-grapheme-at-gap g, c - # - var result/eax: boolean <- gap-buffer-equal? g, "aa" - check-not result, "F - test-gap-buffer-equal-fails" -} - -fn gap-buffers-equal? self: (addr gap-buffer), g: (addr gap-buffer) -> _/eax: boolean { - var tmp/eax: int <- gap-buffer-length self - var len/ecx: int <- copy tmp - var leng/eax: int <- gap-buffer-length g - compare len, leng - { - break-if-= - return 0/false - } - var i/edx: int <- copy 0 - { - compare i, len - break-if->= - { - var tmp/eax: grapheme <- gap-index self, i - var curr/ecx: grapheme <- copy tmp - var currg/eax: grapheme <- gap-index g, i - compare curr, currg - break-if-= - return 0/false - } - i <- increment - loop - } - return 1/true -} - -fn gap-index _self: (addr gap-buffer), _n: int -> _/eax: grapheme { - var self/esi: (addr gap-buffer) <- copy _self - var n/ebx: int <- copy _n - # if n < left->length, index into left - var left/edi: (addr grapheme-stack) <- get self, left - var left-len-a/edx: (addr int) <- get left, top - compare n, *left-len-a - { - break-if->= - var data-ah/eax: (addr handle array grapheme) <- get left, data - var data/eax: (addr array grapheme) <- lookup *data-ah - var result/eax: (addr grapheme) <- index data, n - return *result - } - # shrink n - n <- subtract *left-len-a - # if n < right->length, index into right - var right/edi: (addr grapheme-stack) <- get self, right - var right-len-a/edx: (addr int) <- get right, top - compare n, *right-len-a - { - break-if->= - var data-ah/eax: (addr handle array grapheme) <- get right, data - var data/eax: (addr array grapheme) <- lookup *data-ah - # idx = right->len - n - 1 - var idx/ebx: int <- copy n - idx <- subtract *right-len-a - idx <- negate - idx <- subtract 1 - var result/eax: (addr grapheme) <- index data, idx - return *result - } - # error - abort "gap-index: out of bounds" - return 0 -} - -fn test-gap-buffers-equal? { - var _a: gap-buffer - var a/esi: (addr gap-buffer) <- address _a - initialize-gap-buffer-with a, "abc" - var _b: gap-buffer - var b/edi: (addr gap-buffer) <- address _b - initialize-gap-buffer-with b, "abc" - var _c: gap-buffer - var c/ebx: (addr gap-buffer) <- address _c - initialize-gap-buffer-with c, "ab" - var _d: gap-buffer - var d/edx: (addr gap-buffer) <- address _d - initialize-gap-buffer-with d, "abd" - # - var result/eax: boolean <- gap-buffers-equal? a, a - check result, "F - test-gap-buffers-equal? - reflexive" - result <- gap-buffers-equal? a, b - check result, "F - test-gap-buffers-equal? - equal" - # length not equal - result <- gap-buffers-equal? a, c - check-not result, "F - test-gap-buffers-equal? - not equal" - # contents not equal - result <- gap-buffers-equal? a, d - check-not result, "F - test-gap-buffers-equal? - not equal 2" - result <- gap-buffers-equal? d, a - check-not result, "F - test-gap-buffers-equal? - not equal 3" -} - -fn test-gap-buffer-index { - var gap-storage: gap-buffer - var gap/esi: (addr gap-buffer) <- address gap-storage - initialize-gap-buffer-with gap, "abc" - # gap is at end, all contents are in left - var g/eax: grapheme <- gap-index gap, 0 - var x/ecx: int <- copy g - check-ints-equal x, 0x61/a, "F - test-gap-index/left-1" - var g/eax: grapheme <- gap-index gap, 1 - var x/ecx: int <- copy g - check-ints-equal x, 0x62/b, "F - test-gap-index/left-2" - var g/eax: grapheme <- gap-index gap, 2 - var x/ecx: int <- copy g - check-ints-equal x, 0x63/c, "F - test-gap-index/left-3" - # now check when everything is to the right - gap-to-start gap - rewind-gap-buffer gap - var g/eax: grapheme <- gap-index gap, 0 - var x/ecx: int <- copy g - check-ints-equal x, 0x61/a, "F - test-gap-index/right-1" - var g/eax: grapheme <- gap-index gap, 1 - var x/ecx: int <- copy g - check-ints-equal x, 0x62/b, "F - test-gap-index/right-2" - var g/eax: grapheme <- gap-index gap, 2 - var x/ecx: int <- copy g - check-ints-equal x, 0x63/c, "F - test-gap-index/right-3" -} - -fn copy-gap-buffer _src-ah: (addr handle gap-buffer), _dest-ah: (addr handle gap-buffer) { - # obtain src-a, dest-a - var src-ah/eax: (addr handle gap-buffer) <- copy _src-ah - var _src-a/eax: (addr gap-buffer) <- lookup *src-ah - var src-a/esi: (addr gap-buffer) <- copy _src-a - var dest-ah/eax: (addr handle gap-buffer) <- copy _dest-ah - var _dest-a/eax: (addr gap-buffer) <- lookup *dest-ah - var dest-a/edi: (addr gap-buffer) <- copy _dest-a - # copy left grapheme-stack - var src/ecx: (addr grapheme-stack) <- get src-a, left - var dest/edx: (addr grapheme-stack) <- get dest-a, left - copy-grapheme-stack src, dest - # copy right grapheme-stack - src <- get src-a, right - dest <- get dest-a, right - copy-grapheme-stack src, dest -} - -fn gap-buffer-is-decimal-integer? _self: (addr gap-buffer) -> _/eax: boolean { - var self/esi: (addr gap-buffer) <- copy _self - var curr/ecx: (addr grapheme-stack) <- get self, left - var result/eax: boolean <- grapheme-stack-is-decimal-integer? curr - { - compare result, 0/false - break-if-= - curr <- get self, right - result <- grapheme-stack-is-decimal-integer? curr - } - return result -} - -fn test-render-gap-buffer-without-cursor { - # setup - var gap-storage: gap-buffer - var gap/esi: (addr gap-buffer) <- address gap-storage - initialize-gap-buffer-with gap, "abc" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5, 4 - # - var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 0/no-cursor - check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-without-cursor" - check-ints-equal x, 4, "F - test-render-gap-buffer-without-cursor: result" - # abc - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-render-gap-buffer-without-cursor: bg" -} - -fn test-render-gap-buffer-with-cursor-at-end { - # setup - var gap-storage: gap-buffer - var gap/esi: (addr gap-buffer) <- address gap-storage - initialize-gap-buffer-with gap, "abc" - gap-to-end gap - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5, 4 - # - var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor - check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-at-end" - # we've drawn one extra grapheme for the cursor - check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-end: result" - # abc - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " |", "F - test-render-gap-buffer-with-cursor-at-end: bg" -} - -fn test-render-gap-buffer-with-cursor-in-middle { - # setup - var gap-storage: gap-buffer - var gap/esi: (addr gap-buffer) <- address gap-storage - initialize-gap-buffer-with gap, "abc" - gap-to-end gap - var dummy/eax: grapheme <- gap-left gap - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5, 4 - # - var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor - check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-in-middle" - check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-in-middle: result" - # abc - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-gap-buffer-with-cursor-in-middle: bg" -} - -fn test-render-gap-buffer-with-cursor-at-start { - var gap-storage: gap-buffer - var gap/esi: (addr gap-buffer) <- address gap-storage - initialize-gap-buffer-with gap, "abc" - gap-to-start gap - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5, 4 - # - var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor - check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-at-start" - check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-start: result" - # abc - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "| ", "F - test-render-gap-buffer-with-cursor-at-start: bg" -} - -## some primitives for scanning through a gap buffer -# don't modify the gap buffer while scanning -# this includes moving the cursor around - -# restart scan without affecting gap-buffer contents -fn rewind-gap-buffer _self: (addr gap-buffer) { - var self/esi: (addr gap-buffer) <- copy _self - var dest/eax: (addr int) <- get self, left-read-index - copy-to *dest, 0 - dest <- get self, right-read-index - copy-to *dest, 0 -} - -fn gap-buffer-scan-done? _self: (addr gap-buffer) -> _/eax: boolean { - var self/esi: (addr gap-buffer) <- copy _self - # more in left? - var left/eax: (addr grapheme-stack) <- get self, left - var left-size/eax: int <- grapheme-stack-length left - var left-read-index/ecx: (addr int) <- get self, left-read-index - compare *left-read-index, left-size - { - break-if->= - return 0/false - } - # more in right? - var right/eax: (addr grapheme-stack) <- get self, right - var right-size/eax: int <- grapheme-stack-length right - var right-read-index/ecx: (addr int) <- get self, right-read-index - compare *right-read-index, right-size - { - break-if->= - return 0/false - } - # - return 1/true -} - -fn peek-from-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme { - var self/esi: (addr gap-buffer) <- copy _self - # more in left? - var left/ecx: (addr grapheme-stack) <- get self, left - var left-size/eax: int <- grapheme-stack-length left - var left-read-index-a/edx: (addr int) <- get self, left-read-index - compare *left-read-index-a, left-size - { - break-if->= - var left-data-ah/eax: (addr handle array grapheme) <- get left, data - var left-data/eax: (addr array grapheme) <- lookup *left-data-ah - var left-read-index/ecx: int <- copy *left-read-index-a - var result/eax: (addr grapheme) <- index left-data, left-read-index - return *result - } - # more in right? - var right/ecx: (addr grapheme-stack) <- get self, right - var _right-size/eax: int <- grapheme-stack-length right - var right-size/ebx: int <- copy _right-size - var right-read-index-a/edx: (addr int) <- get self, right-read-index - compare *right-read-index-a, right-size - { - break-if->= - # read the right from reverse - var right-data-ah/eax: (addr handle array grapheme) <- get right, data - var right-data/eax: (addr array grapheme) <- lookup *right-data-ah - var right-read-index/ebx: int <- copy right-size - right-read-index <- subtract *right-read-index-a - right-read-index <- subtract 1 - var result/eax: (addr grapheme) <- index right-data, right-read-index - return *result - } - # if we get here there's nothing left - return 0/nul -} - -fn read-from-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme { - var self/esi: (addr gap-buffer) <- copy _self - # more in left? - var left/ecx: (addr grapheme-stack) <- get self, left - var left-size/eax: int <- grapheme-stack-length left - var left-read-index-a/edx: (addr int) <- get self, left-read-index - compare *left-read-index-a, left-size - { - break-if->= - var left-data-ah/eax: (addr handle array grapheme) <- get left, data - var left-data/eax: (addr array grapheme) <- lookup *left-data-ah - var left-read-index/ecx: int <- copy *left-read-index-a - var result/eax: (addr grapheme) <- index left-data, left-read-index - increment *left-read-index-a - return *result - } - # more in right? - var right/ecx: (addr grapheme-stack) <- get self, right - var _right-size/eax: int <- grapheme-stack-length right - var right-size/ebx: int <- copy _right-size - var right-read-index-a/edx: (addr int) <- get self, right-read-index - compare *right-read-index-a, right-size - { - break-if->= - # read the right from reverse - var right-data-ah/eax: (addr handle array grapheme) <- get right, data - var right-data/eax: (addr array grapheme) <- lookup *right-data-ah - var right-read-index/ebx: int <- copy right-size - right-read-index <- subtract *right-read-index-a - right-read-index <- subtract 1 - var result/eax: (addr grapheme) <- index right-data, right-read-index - increment *right-read-index-a - return *result - } - # if we get here there's nothing left - return 0/nul -} - -fn test-read-from-gap-buffer { - var gap-storage: gap-buffer - var gap/esi: (addr gap-buffer) <- address gap-storage - initialize-gap-buffer-with gap, "abc" - # gap is at end, all contents are in left - var done?/eax: boolean <- gap-buffer-scan-done? gap - check-not done?, "F - test-read-from-gap-buffer/left-1/done" - var g/eax: grapheme <- read-from-gap-buffer gap - var x/ecx: int <- copy g - check-ints-equal x, 0x61/a, "F - test-read-from-gap-buffer/left-1" - var done?/eax: boolean <- gap-buffer-scan-done? gap - check-not done?, "F - test-read-from-gap-buffer/left-2/done" - var g/eax: grapheme <- read-from-gap-buffer gap - var x/ecx: int <- copy g - check-ints-equal x, 0x62/b, "F - test-read-from-gap-buffer/left-2" - var done?/eax: boolean <- gap-buffer-scan-done? gap - check-not done?, "F - test-read-from-gap-buffer/left-3/done" - var g/eax: grapheme <- read-from-gap-buffer gap - var x/ecx: int <- copy g - check-ints-equal x, 0x63/c, "F - test-read-from-gap-buffer/left-3" - var done?/eax: boolean <- gap-buffer-scan-done? gap - check done?, "F - test-read-from-gap-buffer/left-4/done" - var g/eax: grapheme <- read-from-gap-buffer gap - var x/ecx: int <- copy g - check-ints-equal x, 0/nul, "F - test-read-from-gap-buffer/left-4" - # now check when everything is to the right - gap-to-start gap - rewind-gap-buffer gap - var done?/eax: boolean <- gap-buffer-scan-done? gap - check-not done?, "F - test-read-from-gap-buffer/right-1/done" - var g/eax: grapheme <- read-from-gap-buffer gap - var x/ecx: int <- copy g - check-ints-equal x, 0x61/a, "F - test-read-from-gap-buffer/right-1" - var done?/eax: boolean <- gap-buffer-scan-done? gap - check-not done?, "F - test-read-from-gap-buffer/right-2/done" - var g/eax: grapheme <- read-from-gap-buffer gap - var x/ecx: int <- copy g - check-ints-equal x, 0x62/b, "F - test-read-from-gap-buffer/right-2" - var done?/eax: boolean <- gap-buffer-scan-done? gap - check-not done?, "F - test-read-from-gap-buffer/right-3/done" - var g/eax: grapheme <- read-from-gap-buffer gap - var x/ecx: int <- copy g - check-ints-equal x, 0x63/c, "F - test-read-from-gap-buffer/right-3" - var done?/eax: boolean <- gap-buffer-scan-done? gap - check done?, "F - test-read-from-gap-buffer/right-4/done" - var g/eax: grapheme <- read-from-gap-buffer gap - var x/ecx: int <- copy g - check-ints-equal x, 0/nul, "F - test-read-from-gap-buffer/right-4" -} - -fn skip-whitespace-from-gap-buffer self: (addr gap-buffer) { - var done?/eax: boolean <- gap-buffer-scan-done? self - compare done?, 0/false - break-if-!= - var g/eax: grapheme <- peek-from-gap-buffer self - { - compare g, 0x20/space - break-if-= - compare g, 0xa/newline - break-if-= - return - } - g <- read-from-gap-buffer self - loop -} - -fn edit-gap-buffer self: (addr gap-buffer), key: grapheme { - var g/edx: grapheme <- copy key - { - compare g, 8/backspace - break-if-!= - delete-before-gap self - return - } - # arrow keys - { - compare g, 4/ctrl-d - break-if-!= - # ctrl-d: cursor down - return - } - { - compare g, 0x15/ctrl-u - break-if-!= - # ctrl-u: cursor up - return - } - # default: insert character - add-grapheme-at-gap self, g -} - -fn cursor-on-final-line? self: (addr gap-buffer) -> _/eax: boolean { - return 1/true -} diff --git a/baremetal/shell/grapheme-stack.mu b/baremetal/shell/grapheme-stack.mu deleted file mode 100644 index 456df0cb..00000000 --- a/baremetal/shell/grapheme-stack.mu +++ /dev/null @@ -1,280 +0,0 @@ -# grapheme stacks are the smallest unit of editable text - -type grapheme-stack { - data: (handle array grapheme) - top: int -} - -fn initialize-grapheme-stack _self: (addr grapheme-stack), n: int { - var self/esi: (addr grapheme-stack) <- copy _self - var d/edi: (addr handle array grapheme) <- get self, data - populate d, n - var top/eax: (addr int) <- get self, top - copy-to *top, 0 -} - -fn clear-grapheme-stack _self: (addr grapheme-stack) { - var self/esi: (addr grapheme-stack) <- copy _self - var top/eax: (addr int) <- get self, top - copy-to *top, 0 -} - -fn grapheme-stack-empty? _self: (addr grapheme-stack) -> _/eax: boolean { - var self/esi: (addr grapheme-stack) <- copy _self - var top/eax: (addr int) <- get self, top - compare *top, 0 - { - break-if-!= - return 1/true - } - return 0/false -} - -fn grapheme-stack-length _self: (addr grapheme-stack) -> _/eax: int { - var self/esi: (addr grapheme-stack) <- copy _self - var top/eax: (addr int) <- get self, top - return *top -} - -fn push-grapheme-stack _self: (addr grapheme-stack), _val: grapheme { - var self/esi: (addr grapheme-stack) <- copy _self - var top-addr/ecx: (addr int) <- get self, top - var data-ah/edx: (addr handle array grapheme) <- get self, data - var data/eax: (addr array grapheme) <- lookup *data-ah - var top/edx: int <- copy *top-addr - var dest-addr/edx: (addr grapheme) <- index data, top - var val/eax: grapheme <- copy _val - copy-to *dest-addr, val - add-to *top-addr, 1 -} - -fn pop-grapheme-stack _self: (addr grapheme-stack) -> _/eax: grapheme { - var self/esi: (addr grapheme-stack) <- copy _self - var top-addr/ecx: (addr int) <- get self, top - { - compare *top-addr, 0 - break-if-> - return -1 - } - subtract-from *top-addr, 1 - var data-ah/edx: (addr handle array grapheme) <- get self, data - var data/eax: (addr array grapheme) <- lookup *data-ah - var top/edx: int <- copy *top-addr - var result-addr/eax: (addr grapheme) <- index data, top - return *result-addr -} - -fn copy-grapheme-stack _src: (addr grapheme-stack), dest: (addr grapheme-stack) { - var src/esi: (addr grapheme-stack) <- copy _src - var data-ah/edi: (addr handle array grapheme) <- get src, data - var _data/eax: (addr array grapheme) <- lookup *data-ah - var data/edi: (addr array grapheme) <- copy _data - var top-addr/ecx: (addr int) <- get src, top - var i/eax: int <- copy 0 - { - compare i, *top-addr - break-if->= - var g/edx: (addr grapheme) <- index data, i - push-grapheme-stack dest, *g - i <- increment - loop - } -} - -# dump stack to screen from bottom to top -# colors hardcoded -fn render-stack-from-bottom-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int -> _/eax: int, _/ecx: int { - var self/esi: (addr grapheme-stack) <- copy _self - var data-ah/edi: (addr handle array grapheme) <- get self, data - var _data/eax: (addr array grapheme) <- lookup *data-ah - var data/edi: (addr array grapheme) <- copy _data - var x/eax: int <- copy _x - var y/ecx: int <- copy _y - var top-addr/edx: (addr int) <- get self, top - var i/ebx: int <- copy 0 - { - compare i, *top-addr - break-if->= - { - var g/edx: (addr grapheme) <- index data, i - x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, 3/fg=cyan, 0/bg - } - i <- increment - loop - } - return x, y -} - -# helper for small words -fn render-stack-from-bottom screen: (addr screen), self: (addr grapheme-stack), x: int, y: int -> _/eax: int { - var _width/eax: int <- copy 0 - var _height/ecx: int <- copy 0 - _width, _height <- screen-size screen - var width/edx: int <- copy _width - var height/ebx: int <- copy _height - var x2/eax: int <- copy 0 - var y2/ecx: int <- copy 0 - x2, y2 <- render-stack-from-bottom-wrapping-right-then-down screen, self, x, y, width, height, x, y - return x2 # y2? yolo -} - -# dump stack to screen from top to bottom -# optionally render a 'cursor' with the top grapheme -fn render-stack-from-top-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, render-cursor?: boolean -> _/eax: int, _/ecx: int { - var self/esi: (addr grapheme-stack) <- copy _self - var data-ah/edi: (addr handle array grapheme) <- get self, data - var _data/eax: (addr array grapheme) <- lookup *data-ah - var data/edi: (addr array grapheme) <- copy _data - var x/eax: int <- copy _x - var y/ecx: int <- copy _y - var top-addr/edx: (addr int) <- get self, top - var i/ebx: int <- copy *top-addr - i <- decrement - # if render-cursor?, peel off first iteration - { - compare render-cursor?, 0/false - break-if-= - compare i, 0 - break-if-< - { - var g/edx: (addr grapheme) <- index data, i - x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, 3/fg=cyan, 7/bg=cursor - } - i <- decrement - } - # remaining iterations - { - compare i, 0 - break-if-< - { - var g/edx: (addr grapheme) <- index data, i - x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, 3/fg=cyan, 0/bg=cursor - } - i <- decrement - loop - } - return x, y -} - -# helper for small words -fn render-stack-from-top screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, render-cursor?: boolean -> _/eax: int { - var _width/eax: int <- copy 0 - var _height/ecx: int <- copy 0 - _width, _height <- screen-size screen - var width/edx: int <- copy _width - var height/ebx: int <- copy _height - var x2/eax: int <- copy 0 - var y2/ecx: int <- copy 0 - x2, y2 <- render-stack-from-top-wrapping-right-then-down screen, self, x, y, width, height, x, y, render-cursor? - return x2 # y2? yolo -} - -fn test-render-grapheme-stack { - # setup: gs = "abc" - var gs-storage: grapheme-stack - var gs/edi: (addr grapheme-stack) <- address gs-storage - initialize-grapheme-stack gs, 5 - var g/eax: grapheme <- copy 0x61/a - push-grapheme-stack gs, g - g <- copy 0x62/b - push-grapheme-stack gs, g - g <- copy 0x63/c - push-grapheme-stack gs, g - # setup: screen - var screen-on-stack: screen - var screen/esi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5, 4 - # - var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 0/y - check-screen-row screen, 0/y, "abc ", "F - test-render-grapheme-stack from bottom" - check-ints-equal x, 3, "F - test-render-grapheme-stack from bottom: result" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-render-grapheme-stack from bottom: bg" - # - var x/eax: int <- render-stack-from-top screen, gs, 0/x, 1/y, 0/cursor=false - check-screen-row screen, 1/y, "cba ", "F - test-render-grapheme-stack from top without cursor" - check-ints-equal x, 3, "F - test-render-grapheme-stack from top without cursor: result" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-render-grapheme-stack from top without cursor: bg" - # - var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true - check-screen-row screen, 2/y, "cba ", "F - test-render-grapheme-stack from top with cursor" - check-ints-equal x, 3, "F - test-render-grapheme-stack from top without cursor: result" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "| ", "F - test-render-grapheme-stack from top with cursor: bg" -} - -# compare from bottom -# beware: modifies 'stream', which must be disposed of after a false result -fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean { - var self/esi: (addr grapheme-stack) <- copy _self - var data-ah/edi: (addr handle array grapheme) <- get self, data - var _data/eax: (addr array grapheme) <- lookup *data-ah - var data/edi: (addr array grapheme) <- copy _data - var top-addr/ecx: (addr int) <- get self, top - var i/ebx: int <- copy 0 - { - compare i, *top-addr - break-if->= - # if curr != expected, return false - { - var curr-a/edx: (addr grapheme) <- index data, i - var expected/eax: grapheme <- read-grapheme s - { - compare expected, *curr-a - break-if-= - return 0/false - } - } - i <- increment - loop - } - return 1 # true -} - -# compare from bottom -# beware: modifies 'stream', which must be disposed of after a false result -fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean { - var self/esi: (addr grapheme-stack) <- copy _self - var data-ah/edi: (addr handle array grapheme) <- get self, data - var _data/eax: (addr array grapheme) <- lookup *data-ah - var data/edi: (addr array grapheme) <- copy _data - var top-addr/eax: (addr int) <- get self, top - var i/ebx: int <- copy *top-addr - i <- decrement - { - compare i, 0 - break-if-< - { - var curr-a/edx: (addr grapheme) <- index data, i - var expected/eax: grapheme <- read-grapheme s - # if curr != expected, return false - { - compare expected, *curr-a - break-if-= - return 0/false - } - } - i <- decrement - loop - } - return 1 # true -} - -fn grapheme-stack-is-decimal-integer? _self: (addr grapheme-stack) -> _/eax: boolean { - var self/esi: (addr grapheme-stack) <- copy _self - var data-ah/eax: (addr handle array grapheme) <- get self, data - var _data/eax: (addr array grapheme) <- lookup *data-ah - var data/edx: (addr array grapheme) <- copy _data - var top-addr/ecx: (addr int) <- get self, top - var i/ebx: int <- copy 0 - var result/eax: boolean <- copy 1/true - $grapheme-stack-is-integer?:loop: { - compare i, *top-addr - break-if->= - var g/edx: (addr grapheme) <- index data, i - result <- is-decimal-digit? *g - compare result, 0/false - break-if-= - i <- increment - loop - } - return result -} diff --git a/baremetal/shell/main.mu b/baremetal/shell/main.mu deleted file mode 100644 index eb437b67..00000000 --- a/baremetal/shell/main.mu +++ /dev/null @@ -1,22 +0,0 @@ -# Experimental Mu shell -# A Lisp with indent-sensitivity and infix, no macros. Commas are ignored. - -fn main { - var sandbox-storage: sandbox - var sandbox/esi: (addr sandbox) <- address sandbox-storage - initialize-sandbox sandbox - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size 0/screen - { - render-sandbox 0/screen, sandbox, 2/x, 2/y, width, height - { - var key/eax: byte <- read-key 0/keyboard - compare key, 0 - loop-if-= - # no way to quit right now; just reboot - edit-sandbox sandbox, key - } - loop - } -} diff --git a/baremetal/shell/parse.mu b/baremetal/shell/parse.mu deleted file mode 100644 index a0045eb3..00000000 --- a/baremetal/shell/parse.mu +++ /dev/null @@ -1,136 +0,0 @@ -fn parse-input tokens: (addr stream cell), out: (addr handle cell), trace: (addr trace) { - rewind-stream tokens - var empty?/eax: boolean <- stream-empty? tokens - compare empty?, 0/false - { - break-if-= - error trace, "nothing to parse" - return - } - var close-paren?/eax: boolean <- parse-sexpression tokens, out, trace - { - compare close-paren?, 0/false - break-if-= - error trace, "')' is not a valid expression" - return - } - { - var empty?/eax: boolean <- stream-empty? tokens - compare empty?, 0/false - break-if-!= - error trace, "unexpected tokens at end; only type in a single expression at a time" - } -} - -# return value: true if close-paren was encountered -fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace: (addr trace) -> _/eax: boolean { - trace-text trace, "read", "parse" - trace-lower trace - var curr-token-storage: cell - var curr-token/ecx: (addr cell) <- address curr-token-storage - var empty?/eax: boolean <- stream-empty? tokens - compare empty?, 0/false - { - break-if-= - error trace, "end of stream; never found a balancing ')'" - return 1/true - } - read-from-stream tokens, curr-token - $parse-sexpression:type-check: { - # not bracket -> parse atom - var is-bracket-token?/eax: boolean <- is-bracket-token? curr-token - compare is-bracket-token?, 0/false - { - break-if-!= - parse-atom curr-token, _out, trace - break $parse-sexpression:type-check - } - # open paren -> parse list - var is-open-paren?/eax: boolean <- is-open-paren-token? curr-token - compare is-open-paren?, 0/false - { - break-if-= - var curr/esi: (addr handle cell) <- copy _out - $parse-sexpression:list-loop: { - allocate-pair curr - var curr-addr/eax: (addr cell) <- lookup *curr - var left/ecx: (addr handle cell) <- get curr-addr, left - { - var is-close-paren?/eax: boolean <- parse-sexpression tokens, left, trace - compare is-close-paren?, 0/false - break-if-!= $parse-sexpression:list-loop - } - # - curr <- get curr-addr, right - loop - } - break $parse-sexpression:type-check - } - # close paren -> parse list - var is-close-paren?/eax: boolean <- is-close-paren-token? curr-token - compare is-close-paren?, 0/false - { - break-if-= - trace-higher trace - return 1/true - } - # otherwise abort - var stream-storage: (stream byte 0x40) - var stream/edx: (addr stream byte) <- address stream-storage - write stream, "unexpected token " - var curr-token-data-ah/eax: (addr handle stream byte) <- get curr-token, text-data - var curr-token-data/eax: (addr stream byte) <- lookup *curr-token-data-ah - rewind-stream curr-token-data - write-stream stream, curr-token-data - trace trace, "error", stream - } - trace-higher trace - return 0/false -} - -fn parse-atom _curr-token: (addr cell), _out: (addr handle cell), trace: (addr trace) { - trace-text trace, "read", "parse atom" - var curr-token/ecx: (addr cell) <- copy _curr-token - var curr-token-data-ah/eax: (addr handle stream byte) <- get curr-token, text-data - var _curr-token-data/eax: (addr stream byte) <- lookup *curr-token-data-ah - var curr-token-data/esi: (addr stream byte) <- copy _curr-token-data - trace trace, "read", curr-token-data - # number - var is-number-token?/eax: boolean <- is-number-token? curr-token - compare is-number-token?, 0/false - { - break-if-= - rewind-stream curr-token-data - var _val/eax: int <- parse-decimal-int-from-stream curr-token-data - var val/ecx: int <- copy _val - var val-float/xmm0: float <- convert val - allocate-number _out - var out/eax: (addr handle cell) <- copy _out - var out-addr/eax: (addr cell) <- lookup *out - var dest/edi: (addr float) <- get out-addr, number-data - copy-to *dest, val-float - { - var stream-storage: (stream byte 0x40) - var stream/ecx: (addr stream byte) <- address stream-storage - write stream, "=> number " - print-number out-addr, stream, 0/no-trace - trace trace, "read", stream - } - return - } - # default: symbol - # just copy token data - allocate-symbol _out - var out/eax: (addr handle cell) <- copy _out - var out-addr/eax: (addr cell) <- lookup *out - var curr-token-data-ah/ecx: (addr handle stream byte) <- get curr-token, text-data - var dest-ah/edx: (addr handle stream byte) <- get out-addr, text-data - copy-object curr-token-data-ah, dest-ah - { - var stream-storage: (stream byte 0x40) - var stream/ecx: (addr stream byte) <- address stream-storage - write stream, "=> symbol " - print-symbol out-addr, stream, 0/no-trace - trace trace, "read", stream - } -} diff --git a/baremetal/shell/print.mu b/baremetal/shell/print.mu deleted file mode 100644 index 32f5e725..00000000 --- a/baremetal/shell/print.mu +++ /dev/null @@ -1,260 +0,0 @@ -fn print-cell _in: (addr handle cell), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "print", "print-cell" - trace-lower trace - var in/eax: (addr handle cell) <- copy _in - var in-addr/eax: (addr cell) <- lookup *in - { - var is-nil?/eax: boolean <- is-nil? in-addr - compare is-nil?, 0/false - break-if-= - write out, "()" - trace-higher trace - return - } - var in-type/ecx: (addr int) <- get in-addr, type - compare *in-type, 0/pair - { - break-if-!= - print-list in-addr, out, trace - trace-higher trace - return - } - compare *in-type, 1/number - { - break-if-!= - print-number in-addr, out, trace - trace-higher trace - return - } - compare *in-type, 2/symbol - { - break-if-!= - print-symbol in-addr, out, trace - trace-higher trace - return - } -} - -fn print-symbol _in: (addr cell), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "print", "symbol" - var in/esi: (addr cell) <- copy _in - var data-ah/eax: (addr handle stream byte) <- get in, text-data - var _data/eax: (addr stream byte) <- lookup *data-ah - var data/esi: (addr stream byte) <- copy _data - rewind-stream data - write-stream out, data - # trace - rewind-stream data - var stream-storage: (stream byte 0x40) - var stream/ecx: (addr stream byte) <- address stream-storage - write stream, "=> symbol " - write-stream stream, data - trace trace, "print", stream -} - -fn print-number _in: (addr cell), out: (addr stream byte), trace: (addr trace) { - var in/esi: (addr cell) <- copy _in - var val/eax: (addr float) <- get in, number-data - write-float-decimal-approximate out, *val, 3/precision - # trace - var stream-storage: (stream byte 0x40) - var stream/ecx: (addr stream byte) <- address stream-storage - write stream, "=> number " - write-float-decimal-approximate stream, *val, 3/precision - trace trace, "print", stream -} - -fn print-list _in: (addr cell), out: (addr stream byte), trace: (addr trace) { - var curr/esi: (addr cell) <- copy _in - write out, "(" - $print-list:loop: { - var left/ecx: (addr handle cell) <- get curr, left - { - var left-addr/eax: (addr cell) <- lookup *left - var left-is-nil?/eax: boolean <- is-nil? left-addr - compare left-is-nil?, 0/false - { - break-if-= - trace-text trace, "print", "left is null" - break $print-list:loop - } - } - print-cell left, out, trace - var right/ecx: (addr handle cell) <- get curr, right - var right-addr/eax: (addr cell) <- lookup *right - { - compare right-addr, 0 - break-if-!= - abort "null encountered" - } - { - var right-is-nil?/eax: boolean <- is-nil? right-addr - compare right-is-nil?, 0/false - { - break-if-= - trace-text trace, "print", "right is null" - break $print-list:loop - } - } - write out, " " - var right-type-addr/edx: (addr int) <- get right-addr, type - { - compare *right-type-addr, 0/pair - break-if-= - write out, ". " - print-cell right, out, trace - break $print-list:loop - } - curr <- copy right-addr - loop - } - write out, ")" -} - -# Most lisps intern nil, but we don't really have globals yet, so we'll be -# less efficient for now. -fn is-nil? _in: (addr cell) -> _/eax: boolean { - var in/esi: (addr cell) <- copy _in - # if type != pair, return false - var type/eax: (addr int) <- get in, type - compare *type, 0/pair - { - break-if-= - return 0/false - } - # if left != null, return false - var left-ah/eax: (addr handle cell) <- get in, left - var left/eax: (addr cell) <- lookup *left-ah - compare left, 0 - { - break-if-= - return 0/false - } - # if right != null, return false - var right-ah/eax: (addr handle cell) <- get in, right - var right/eax: (addr cell) <- lookup *right-ah - compare right, 0 - { - break-if-= - return 0/false - } - return 1/true -} - -fn test-print-cell-zero { - var num-storage: (handle cell) - var num/esi: (addr handle cell) <- address num-storage - new-integer num, 0 - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell num, out, 0/no-trace - check-stream-equal out, "0", "F - test-print-cell-zero" -} - -fn test-print-cell-integer { - var num-storage: (handle cell) - var num/esi: (addr handle cell) <- address num-storage - new-integer num, 1 - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell num, out, 0/no-trace - check-stream-equal out, "1", "F - test-print-cell-integer" -} - -fn test-print-cell-integer-2 { - var num-storage: (handle cell) - var num/esi: (addr handle cell) <- address num-storage - new-integer num, 0x30 - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell num, out, 0/no-trace - check-stream-equal out, "48", "F - test-print-cell-integer-2" -} - -fn test-print-cell-fraction { - var num-storage: (handle cell) - var num/esi: (addr handle cell) <- address num-storage - var val/xmm0: float <- rational 1, 2 - new-float num, val - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell num, out, 0/no-trace - check-stream-equal out, "0.5", "F - test-print-cell-fraction" -} - -fn test-print-cell-symbol { - var sym-storage: (handle cell) - var sym/esi: (addr handle cell) <- address sym-storage - new-symbol sym, "abc" - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell sym, out, 0/no-trace - check-stream-equal out, "abc", "F - test-print-cell-symbol" -} - -fn test-print-cell-nil-list { - var nil-storage: (handle cell) - var nil/esi: (addr handle cell) <- address nil-storage - allocate-pair nil - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell nil, out, 0/no-trace - check-stream-equal out, "()", "F - test-print-cell-nil-list" -} - -fn test-print-cell-singleton-list { - # list - var left-storage: (handle cell) - var left/ecx: (addr handle cell) <- address left-storage - new-symbol left, "abc" - var nil-storage: (handle cell) - var nil/edx: (addr handle cell) <- address nil-storage - allocate-pair nil - var list-storage: (handle cell) - var list/esi: (addr handle cell) <- address list-storage - new-pair list, *left, *nil - # - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell list, out, 0/no-trace - check-stream-equal out, "(abc)", "F - test-print-cell-singleton-list" -} - -fn test-print-cell-list { - # list = cons "abc", nil - var left-storage: (handle cell) - var left/ecx: (addr handle cell) <- address left-storage - new-symbol left, "abc" - var nil-storage: (handle cell) - var nil/edx: (addr handle cell) <- address nil-storage - allocate-pair nil - var list-storage: (handle cell) - var list/esi: (addr handle cell) <- address list-storage - new-pair list, *left, *nil - # list = cons 64, list - new-integer left, 0x40 - new-pair list, *left, *list - # - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell list, out, 0/no-trace - check-stream-equal out, "(64 abc)", "F - test-print-cell-list" -} - -fn test-print-dotted-list { - # list = cons 64, "abc" - var left-storage: (handle cell) - var left/ecx: (addr handle cell) <- address left-storage - new-symbol left, "abc" - var right-storage: (handle cell) - var right/edx: (addr handle cell) <- address right-storage - new-integer right, 0x40 - var list-storage: (handle cell) - var list/esi: (addr handle cell) <- address list-storage - new-pair list, *left, *right - # - var out-storage: (stream byte 0x40) - var out/edi: (addr stream byte) <- address out-storage - print-cell list, out, 0/no-trace - check-stream-equal out, "(abc . 64)", "F - test-print-dotted-list" -} diff --git a/baremetal/shell/read.mu b/baremetal/shell/read.mu deleted file mode 100644 index d3e1dc86..00000000 --- a/baremetal/shell/read.mu +++ /dev/null @@ -1,15 +0,0 @@ -# out is not allocated -fn read-cell in: (addr gap-buffer), out: (addr handle cell), trace: (addr trace) { - var tokens-storage: (stream cell 0x100) - var tokens/ecx: (addr stream cell) <- address tokens-storage - tokenize in, tokens, trace - var error?/eax: boolean <- has-errors? trace - compare error?, 0/false - { - break-if-= - return - } - # TODO: insert parens - # TODO: transform infix - parse-input tokens, out, trace -} diff --git a/baremetal/shell/sandbox.mu b/baremetal/shell/sandbox.mu deleted file mode 100644 index 49c2a5f9..00000000 --- a/baremetal/shell/sandbox.mu +++ /dev/null @@ -1,263 +0,0 @@ -type sandbox { - data: (handle gap-buffer) - value: (handle stream byte) - trace: (handle trace) - cursor-in-trace?: boolean -} - -fn initialize-sandbox _self: (addr sandbox) { - var self/esi: (addr sandbox) <- copy _self - var data-ah/eax: (addr handle gap-buffer) <- get self, data - allocate data-ah - var data/eax: (addr gap-buffer) <- lookup *data-ah - initialize-gap-buffer data, 0x1000/4KB - var value-ah/eax: (addr handle stream byte) <- get self, value - populate-stream value-ah, 0x1000/4KB - var trace-ah/eax: (addr handle trace) <- get self, trace - allocate trace-ah - var trace/eax: (addr trace) <- lookup *trace-ah - initialize-trace trace, 0x1000/lines, 0x80/visible-lines -} - -## some helpers for tests - -fn initialize-sandbox-with _self: (addr sandbox), s: (addr array byte) { - var self/esi: (addr sandbox) <- copy _self - var data-ah/eax: (addr handle gap-buffer) <- get self, data - allocate data-ah - var data/eax: (addr gap-buffer) <- lookup *data-ah - initialize-gap-buffer-with data, s -} - -fn allocate-sandbox-with _out: (addr handle sandbox), s: (addr array byte) { - var out/eax: (addr handle sandbox) <- copy _out - allocate out - var out-addr/eax: (addr sandbox) <- lookup *out - initialize-sandbox-with out-addr, s -} - -## - -fn render-sandbox screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int, xmax: int, ymax: int { - clear-screen screen - var self/esi: (addr sandbox) <- copy _self - # data - var data-ah/eax: (addr handle gap-buffer) <- get self, data - var _data/eax: (addr gap-buffer) <- lookup *data-ah - var data/edx: (addr gap-buffer) <- copy _data - var x/eax: int <- copy xmin - var y/ecx: int <- copy ymin - var cursor-in-sandbox?/ebx: boolean <- copy 0/false - { - var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace? - compare *cursor-in-trace?, 0/false - break-if-!= - cursor-in-sandbox? <- copy 1/true - } - x, y <- render-gap-buffer-wrapping-right-then-down screen, data, x, y, xmax, ymax, cursor-in-sandbox? - y <- increment - # trace - var trace-ah/eax: (addr handle trace) <- get self, trace - var _trace/eax: (addr trace) <- lookup *trace-ah - var trace/edx: (addr trace) <- copy _trace - var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace? - y <- render-trace screen, trace, xmin, y, xmax, ymax, *cursor-in-trace? - # value - $render-sandbox:value: { - var value-ah/eax: (addr handle stream byte) <- get self, value - var _value/eax: (addr stream byte) <- lookup *value-ah - var value/esi: (addr stream byte) <- copy _value - rewind-stream value - var done?/eax: boolean <- stream-empty? value - compare done?, 0/false - break-if-!= - var x/eax: int <- copy 0 - x, y <- draw-text-wrapping-right-then-down screen, "=> ", xmin, y, xmax, ymax, xmin, y, 7/fg, 0/bg - var x2/edx: int <- copy x - var dummy/eax: int <- draw-stream-rightward screen, value, x2, xmax, y, 7/fg=grey, 0/bg - } - # render menu - var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace? - compare *cursor-in-trace?, 0/false - { - break-if-= - render-trace-menu screen - return - } - render-sandbox-menu screen -} - -fn render-sandbox-menu screen: (addr screen) { - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size screen - var y/ecx: int <- copy height - y <- decrement - set-cursor-position screen, 0/x, y - draw-text-rightward-from-cursor screen, " ctrl-s ", width, 0/fg, 7/bg=grey - draw-text-rightward-from-cursor screen, " run sandbox ", width, 7/fg, 0/bg - draw-text-rightward-from-cursor screen, " ctrl-d ", width, 0/fg, 7/bg=grey - draw-text-rightward-from-cursor screen, " cursor down ", width, 7/fg, 0/bg - draw-text-rightward-from-cursor screen, " ctrl-u ", width, 0/fg, 7/bg=grey - draw-text-rightward-from-cursor screen, " cursor up ", width, 7/fg, 0/bg - draw-text-rightward-from-cursor screen, " tab ", width, 0/fg, 9/bg=blue - draw-text-rightward-from-cursor screen, " move to trace ", width, 7/fg, 0/bg -} - -fn edit-sandbox _self: (addr sandbox), key: byte { - var self/esi: (addr sandbox) <- copy _self - var g/edx: grapheme <- copy key - # running code - { - compare g, 0x12/ctrl-r - break-if-!= - # ctrl-r: run function outside sandbox - # required: fn (addr screen), (addr keyboard) - # Mu will pass in the real screen and keyboard. - return - } - { - compare g, 0x13/ctrl-s - break-if-!= - # ctrl-s: run sandbox(es) - var data-ah/eax: (addr handle gap-buffer) <- get self, data - var _data/eax: (addr gap-buffer) <- lookup *data-ah - var data/ecx: (addr gap-buffer) <- copy _data - var value-ah/eax: (addr handle stream byte) <- get self, value - var _value/eax: (addr stream byte) <- lookup *value-ah - var value/edx: (addr stream byte) <- copy _value - var trace-ah/eax: (addr handle trace) <- get self, trace - var trace/eax: (addr trace) <- lookup *trace-ah - clear-trace trace - run data, value, trace - return - } - # tab - var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace? - { - compare g, 9/tab - break-if-!= - # if cursor in input, switch to trace - { - compare *cursor-in-trace?, 0/false - break-if-!= - copy-to *cursor-in-trace?, 1/true - return - } - # if cursor in trace, switch to input - copy-to *cursor-in-trace?, 0/false - return - } - # if cursor in trace, send cursor to trace - { - compare *cursor-in-trace?, 0/false - break-if-= - var trace-ah/eax: (addr handle trace) <- get self, trace - var trace/eax: (addr trace) <- lookup *trace-ah - edit-trace trace, g - return - } - # otherwise send cursor to input - var data-ah/eax: (addr handle gap-buffer) <- get self, data - var data/eax: (addr gap-buffer) <- lookup *data-ah - edit-gap-buffer data, g - return -} - -fn run in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) { - var read-result-storage: (handle cell) - var read-result/esi: (addr handle cell) <- address read-result-storage - read-cell in, read-result, trace - var error?/eax: boolean <- has-errors? trace - { - compare error?, 0/false - break-if-= - return - } - # TODO: eval - clear-stream out - print-cell read-result, out, trace - mark-lines-dirty trace -} - -fn test-run-integer { - var sandbox-storage: sandbox - var sandbox/esi: (addr sandbox) <- address sandbox-storage - initialize-sandbox sandbox - # type "1" - edit-sandbox sandbox, 0x31/1 - # eval - edit-sandbox sandbox, 0x13/ctrl-s - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x80/width, 0x10/height - # - render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height - check-screen-row screen, 0/y, "1 ", "F - test-run-integer/0" - check-screen-row screen, 1/y, "... ", "F - test-run-integer/1" - check-screen-row screen, 2/y, "=> 1 ", "F - test-run-integer/2" -} - -fn test-run-error-invalid-integer { - var sandbox-storage: sandbox - var sandbox/esi: (addr sandbox) <- address sandbox-storage - initialize-sandbox sandbox - # type "1a" - edit-sandbox sandbox, 0x31/1 - edit-sandbox sandbox, 0x61/a - # eval - edit-sandbox sandbox, 0x13/ctrl-s - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x80/width, 0x10/height - # - render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height - check-screen-row screen, 0/y, "1a ", "F - test-run-error-invalid-integer/0" - check-screen-row screen, 1/y, "... ", "F - test-run-error-invalid-integer/0" - check-screen-row screen, 2/y, "invalid number ", "F - test-run-error-invalid-integer/2" -} - -fn test-run-move-cursor-into-trace { - var sandbox-storage: sandbox - var sandbox/esi: (addr sandbox) <- address sandbox-storage - initialize-sandbox sandbox - # type "12" - edit-sandbox sandbox, 0x31/1 - edit-sandbox sandbox, 0x32/2 - # eval - edit-sandbox sandbox, 0x13/ctrl-s - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x80/width, 0x10/height - # - render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height - check-screen-row screen, 0/y, "12 ", "F - test-run-move-cursor-into-trace/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-run-move-cursor-into-trace/pre-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-run-move-cursor-into-trace/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-run-move-cursor-into-trace/pre-1/cursor" - check-screen-row screen, 2/y, "=> 12 ", "F - test-run-move-cursor-into-trace/pre-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-run-move-cursor-into-trace/pre-2/cursor" - # move cursor into trace - edit-sandbox sandbox, 9/tab - # - render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height - check-screen-row screen, 0/y, "12 ", "F - test-run-move-cursor-into-trace/trace-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-run-move-cursor-into-trace/trace-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-run-move-cursor-into-trace/trace-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "||| ", "F - test-run-move-cursor-into-trace/trace-1/cursor" - check-screen-row screen, 2/y, "=> 12 ", "F - test-run-move-cursor-into-trace/trace-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-run-move-cursor-into-trace/trace-2/cursor" - # move cursor into input - edit-sandbox sandbox, 9/tab - # - render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height - check-screen-row screen, 0/y, "12 ", "F - test-run-move-cursor-into-trace/input-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-run-move-cursor-into-trace/input-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-run-move-cursor-into-trace/input-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-run-move-cursor-into-trace/input-1/cursor" - check-screen-row screen, 2/y, "=> 12 ", "F - test-run-move-cursor-into-trace/input-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-run-move-cursor-into-trace/input-2/cursor" -} diff --git a/baremetal/shell/tokenize.mu b/baremetal/shell/tokenize.mu deleted file mode 100644 index 7beedf23..00000000 --- a/baremetal/shell/tokenize.mu +++ /dev/null @@ -1,422 +0,0 @@ -# We reuse the cell data structure for tokenization -# Token cells are special, though. They have no type, they're always atoms, -# they always have text-data. - -fn tokenize in: (addr gap-buffer), out: (addr stream cell), trace: (addr trace) { - trace-text trace, "read", "tokenize" - trace-lower trace - rewind-gap-buffer in - var token-storage: cell - var token/edx: (addr cell) <- address token-storage - { - var done?/eax: boolean <- gap-buffer-scan-done? in - compare done?, 0/false - break-if-!= - # initialize token data each iteration to avoid aliasing - var dest-ah/eax: (addr handle stream byte) <- get token, text-data - populate-stream dest-ah, 0x40/max-token-size - # - next-token in, token, trace - var error?/eax: boolean <- has-errors? trace - compare error?, 0/false - { - break-if-= - return - } - write-to-stream out, token # shallow-copy text-data - loop - } - trace-higher trace -} - -fn next-token in: (addr gap-buffer), _out-cell: (addr cell), trace: (addr trace) { - trace-text trace, "read", "next-token" - trace-lower trace - var out-cell/eax: (addr cell) <- copy _out-cell - var out-ah/eax: (addr handle stream byte) <- get out-cell, text-data - var _out/eax: (addr stream byte) <- lookup *out-ah - var out/edi: (addr stream byte) <- copy _out - $next-token:body: { - clear-stream out - skip-whitespace-from-gap-buffer in - var g/eax: grapheme <- peek-from-gap-buffer in - { - var stream-storage: (stream byte 0x40) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, "next: " - var gval/eax: int <- copy g - write-int32-hex stream, gval - trace trace, "read", stream - } - # digit - { - var digit?/eax: boolean <- is-decimal-digit? g - compare digit?, 0/false - break-if-= - next-number-token in, out, trace - break $next-token:body - } - # other symbol char - { - var symbol?/eax: boolean <- is-symbol-grapheme? g - compare symbol?, 0/false - break-if-= - next-symbol-token in, out, trace - break $next-token:body - } - # brackets are always single-char tokens - { - var bracket?/eax: boolean <- is-bracket-grapheme? g - compare bracket?, 0/false - break-if-= - var g/eax: grapheme <- read-from-gap-buffer in - next-bracket-token g, out, trace - break $next-token:body - } - } - trace-higher trace - var stream-storage: (stream byte 0x40) - var stream/eax: (addr stream byte) <- address stream-storage - write stream, "=> " - rewind-stream out - write-stream stream, out - trace trace, "read", stream -} - -fn next-symbol-token in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "looking for a symbol" - trace-lower trace - $next-symbol-token:loop: { - var done?/eax: boolean <- gap-buffer-scan-done? in - compare done?, 0/false - break-if-!= - var g/eax: grapheme <- peek-from-gap-buffer in - { - var stream-storage: (stream byte 0x40) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, "next: " - var gval/eax: int <- copy g - write-int32-hex stream, gval - trace trace, "read", stream - } - # if non-symbol, return - { - var symbol-grapheme?/eax: boolean <- is-symbol-grapheme? g - compare symbol-grapheme?, 0/false - break-if-!= - trace-text trace, "read", "stop" - break $next-symbol-token:loop - } - var g/eax: grapheme <- read-from-gap-buffer in - write-grapheme out, g - loop - } - trace-higher trace - var stream-storage: (stream byte 0x40) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, "=> " - rewind-stream out - write-stream stream, out - trace trace, "read", stream -} - -fn next-number-token in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "looking for a number" - trace-lower trace - $next-number-token:loop: { - var done?/eax: boolean <- gap-buffer-scan-done? in - compare done?, 0/false - break-if-!= - var g/eax: grapheme <- peek-from-gap-buffer in - { - var stream-storage: (stream byte 0x40) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, "next: " - var gval/eax: int <- copy g - write-int32-hex stream, gval - trace trace, "read", stream - } - # if not symbol grapheme, return - { - var symbol-grapheme?/eax: boolean <- is-symbol-grapheme? g - compare symbol-grapheme?, 0/false - break-if-!= - trace-text trace, "read", "stop" - break $next-number-token:loop - } - # if not digit grapheme, abort - { - var digit?/eax: boolean <- is-decimal-digit? g - compare digit?, 0/false - break-if-!= - error trace, "invalid number" - return - } - trace-text trace, "read", "append" - var g/eax: grapheme <- read-from-gap-buffer in - write-grapheme out, g - loop - } - trace-higher trace -} - -fn next-bracket-token g: grapheme, out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "bracket" - write-grapheme out, g - var stream-storage: (stream byte 0x40) - var stream/esi: (addr stream byte) <- address stream-storage - write stream, "=> " - rewind-stream out - write-stream stream, out - trace trace, "read", stream -} - -fn is-symbol-grapheme? g: grapheme -> _/eax: boolean { - ## whitespace - compare g, 9/tab - { - break-if-!= - return 0/false - } - compare g, 0xa/newline - { - break-if-!= - return 0/false - } - compare g, 0x20/space - { - break-if-!= - return 0/false - } - ## quotes - compare g, 0x22/double-quote - { - break-if-!= - return 0/false - } - compare g, 0x27/single-quote - { - break-if-!= - return 0/false - } - compare g, 0x60/backquote - { - break-if-!= - return 0/false - } - ## brackets - compare g, 0x28/open-paren - { - break-if-!= - return 0/false - } - compare g, 0x29/close-paren - { - break-if-!= - return 0/false - } - compare g, 0x5b/open-square-bracket - { - break-if-!= - return 0/false - } - compare g, 0x5d/close-square-bracket - { - break-if-!= - return 0/false - } - compare g, 0x7b/open-curly-bracket - { - break-if-!= - return 0/false - } - compare g, 0x7d/close-curly-bracket - { - break-if-!= - return 0/false - } - # - other punctuation - # '!' is a symbol char - compare g, 0x23/hash - { - break-if-!= - return 0/false - } - # '$' is a symbol char - compare g, 0x25/percent - { - break-if-!= - return 0/false - } - compare g, 0x26/ampersand - { - break-if-!= - return 0/false - } - compare g, 0x2a/asterisk - { - break-if-!= - return 0/false - } - compare g, 0x2b/plus - { - break-if-!= - return 0/false - } - compare g, 0x2c/comma - { - break-if-!= - return 0/false - } - # '-' is a symbol char - compare g, 0x2e/period - { - break-if-!= - return 0/false - } - compare g, 0x2f/slash - { - break-if-!= - return 0/false - } - compare g, 0x2f/slash - { - break-if-!= - return 0/false - } - compare g, 0x3a/colon - { - break-if-!= - return 0/false - } - compare g, 0x3b/semi-colon - { - break-if-!= - return 0/false - } - compare g, 0x3c/less-than - { - break-if-!= - return 0/false - } - compare g, 0x3d/equal - { - break-if-!= - return 0/false - } - compare g, 0x3e/greater-than - { - break-if-!= - return 0/false - } - # '?' is a symbol char - compare g, 0x40/at-sign - { - break-if-!= - return 0/false - } - compare g, 0x5c/backslash - { - break-if-!= - return 0/false - } - compare g, 0x5e/caret - { - break-if-!= - return 0/false - } - # '_' is a symbol char - compare g, 0x7c/vertical-line - { - break-if-!= - return 0/false - } - compare g, 0x7e/tilde - { - break-if-!= - return 0/false - } - return 1/true -} - -fn is-bracket-grapheme? g: grapheme -> _/eax: boolean { - compare g, 0x28/open-paren - { - break-if-!= - return 1/true - } - compare g, 0x29/close-paren - { - break-if-!= - return 1/true - } - compare g, 0x5b/open-square-bracket - { - break-if-!= - return 1/true - } - compare g, 0x5d/close-square-bracket - { - break-if-!= - return 1/true - } - compare g, 0x7b/open-curly-bracket - { - break-if-!= - return 1/true - } - compare g, 0x7d/close-curly-bracket - { - break-if-!= - return 1/true - } - return 0/false -} - -fn is-number-token? _in: (addr cell) -> _/eax: boolean { - var in/eax: (addr cell) <- copy _in - var in-data-ah/eax: (addr handle stream byte) <- get in, text-data - var in-data/eax: (addr stream byte) <- lookup *in-data-ah - rewind-stream in-data - var g/eax: grapheme <- read-grapheme in-data - var result/eax: boolean <- is-decimal-digit? g - return result -} - -fn is-bracket-token? _in: (addr cell) -> _/eax: boolean { - var in/eax: (addr cell) <- copy _in - var in-data-ah/eax: (addr handle stream byte) <- get in, text-data - var in-data/eax: (addr stream byte) <- lookup *in-data-ah - rewind-stream in-data - var g/eax: grapheme <- read-grapheme in-data - var result/eax: boolean <- is-bracket-grapheme? g - return result -} - -fn is-open-paren-token? _in: (addr cell) -> _/eax: boolean { - var in/eax: (addr cell) <- copy _in - var in-data-ah/eax: (addr handle stream byte) <- get in, text-data - var in-data/eax: (addr stream byte) <- lookup *in-data-ah - rewind-stream in-data - var g/eax: grapheme <- read-grapheme in-data - compare g, 0x28/open-paren - { - break-if-!= - return 1/true - } - return 0/false -} - -fn is-close-paren-token? _in: (addr cell) -> _/eax: boolean { - var in/eax: (addr cell) <- copy _in - var in-data-ah/eax: (addr handle stream byte) <- get in, text-data - var in-data/eax: (addr stream byte) <- lookup *in-data-ah - rewind-stream in-data - var g/eax: grapheme <- read-grapheme in-data - compare g, 0x29/open-paren - { - break-if-!= - return 1/true - } - return 0/false -} diff --git a/baremetal/shell/trace.mu b/baremetal/shell/trace.mu deleted file mode 100644 index 7fd52ceb..00000000 --- a/baremetal/shell/trace.mu +++ /dev/null @@ -1,1449 +0,0 @@ -# A trace records the evolution of a computation. -# An integral part of the Mu Shell is facilities for browsing traces. - -type trace { - # steady-state life cycle of a trace: - # reload loop: - # there are already some visible lines - # append a bunch of new trace lines to the trace - # render loop: - # rendering displays trace lines that match visible lines - # rendering computes cursor-line based on the cursor-y coordinate - # edit-trace updates cursor-y coordinate - # edit-trace might add/remove lines to visible - curr-depth: int # depth that will be assigned to next line appended - data: (handle array trace-line) - first-free: int - visible: (handle array trace-line) - recompute-visible?: boolean - top-line-index: int # index into data - cursor-y: int # row index on screen - cursor-line-index: int # index into data -} - -type trace-line { - depth: int - label: (handle array byte) - data: (handle array byte) - visible?: boolean -} - -fn initialize-trace _self: (addr trace), capacity: int, visible-capacity: int { - var self/esi: (addr trace) <- copy _self - compare self, 0 - break-if-= - var trace-ah/eax: (addr handle array trace-line) <- get self, data - populate trace-ah, capacity - var visible-ah/eax: (addr handle array trace-line) <- get self, visible - populate visible-ah, visible-capacity -} - -fn clear-trace _self: (addr trace) { - var self/eax: (addr trace) <- copy _self - compare self, 0 - break-if-= - var len/edx: (addr int) <- get self, first-free - copy-to *len, 0 - # might leak memory; existing elements won't be used anymore -} - -fn mark-lines-dirty _self: (addr trace) { - var self/eax: (addr trace) <- copy _self - var dest/edx: (addr boolean) <- get self, recompute-visible? - copy-to *dest, 1/true -} - -fn mark-lines-clean _self: (addr trace) { - var self/eax: (addr trace) <- copy _self - var dest/edx: (addr boolean) <- get self, recompute-visible? - copy-to *dest, 0/false -} - -fn has-errors? _self: (addr trace) -> _/eax: boolean { - var self/eax: (addr trace) <- copy _self - var max/edx: (addr int) <- get self, first-free - var trace-ah/eax: (addr handle array trace-line) <- get self, data - var _trace/eax: (addr array trace-line) <- lookup *trace-ah - var trace/esi: (addr array trace-line) <- copy _trace - var i/ecx: int <- copy 0 - { - compare i, *max - break-if->= - var offset/eax: (offset trace-line) <- compute-offset trace, i - var curr/eax: (addr trace-line) <- index trace, offset - var curr-label-ah/eax: (addr handle array byte) <- get curr, label - var curr-label/eax: (addr array byte) <- lookup *curr-label-ah - var is-error?/eax: boolean <- string-equal? curr-label, "error" - compare is-error?, 0/false - { - break-if-= - return 1/true - } - i <- increment - loop - } - return 0/false -} - -fn trace _self: (addr trace), label: (addr array byte), message: (addr stream byte) { - var self/esi: (addr trace) <- copy _self - compare self, 0 - break-if-= - var data-ah/eax: (addr handle array trace-line) <- get self, data - var data/eax: (addr array trace-line) <- lookup *data-ah - var index-addr/edi: (addr int) <- get self, first-free - var index/ecx: int <- copy *index-addr - var offset/ecx: (offset trace-line) <- compute-offset data, index - var dest/eax: (addr trace-line) <- index data, offset - var depth/ecx: (addr int) <- get self, curr-depth - rewind-stream message - initialize-trace-line *depth, label, message, dest - increment *index-addr -} - -fn trace-text self: (addr trace), label: (addr array byte), s: (addr array byte) { - compare self, 0 - break-if-= - var data-storage: (stream byte 0x100) - var data/eax: (addr stream byte) <- address data-storage - write data, s - trace self, label, data -} - -fn error self: (addr trace), message: (addr array byte) { - trace-text self, "error", message -} - -fn initialize-trace-line depth: int, label: (addr array byte), data: (addr stream byte), _out: (addr trace-line) { - var out/edi: (addr trace-line) <- copy _out - # depth - var src/eax: int <- copy depth - var dest/ecx: (addr int) <- get out, depth - copy-to *dest, src - # label - var dest/eax: (addr handle array byte) <- get out, label - copy-array-object label, dest - # data - var dest/eax: (addr handle array byte) <- get out, data - stream-to-array data, dest -} - -fn trace-lower _self: (addr trace) { - var self/esi: (addr trace) <- copy _self - compare self, 0 - break-if-= - var depth/eax: (addr int) <- get self, curr-depth - increment *depth -} - -fn trace-higher _self: (addr trace) { - var self/esi: (addr trace) <- copy _self - compare self, 0 - break-if-= - var depth/eax: (addr int) <- get self, curr-depth - decrement *depth -} - -fn render-trace screen: (addr screen), _self: (addr trace), xmin: int, ymin: int, xmax: int, ymax: int, show-cursor?: boolean -> _/ecx: int { - var already-hiding-lines?: boolean - var y/ecx: int <- copy ymin - var self/esi: (addr trace) <- copy _self - compare self, 0 - { - break-if-!= - return ymin - } - clamp-cursor-to-top self, y - var trace-ah/eax: (addr handle array trace-line) <- get self, data - var _trace/eax: (addr array trace-line) <- lookup *trace-ah - var trace/edi: (addr array trace-line) <- copy _trace - var i/edx: int <- copy 0 - var max-addr/ebx: (addr int) <- get self, first-free - var max/ebx: int <- copy *max-addr - $render-trace:loop: { - compare i, max - break-if->= - $render-trace:iter: { - var offset/ebx: (offset trace-line) <- compute-offset trace, i - var curr/ebx: (addr trace-line) <- index trace, offset - var curr-label-ah/eax: (addr handle array byte) <- get curr, label - var curr-label/eax: (addr array byte) <- lookup *curr-label-ah - var bg/edi: int <- copy 0/black - compare show-cursor?, 0/false - { - break-if-= - var cursor-y/eax: (addr int) <- get self, cursor-y - compare *cursor-y, y - break-if-!= - bg <- copy 7/cursor-line-bg - var cursor-line-index/eax: (addr int) <- get self, cursor-line-index - copy-to *cursor-line-index, i - } - # always display errors - var is-error?/eax: boolean <- string-equal? curr-label, "error" - { - compare is-error?, 0/false - break-if-= - y <- render-trace-line screen, curr, xmin, y, xmax, ymax, 0xc/fg=trace-error, bg - copy-to already-hiding-lines?, 0/false - break $render-trace:iter - } - # display expanded lines - var display?/eax: boolean <- should-render? self, curr - { - compare display?, 0/false - break-if-= - y <- render-trace-line screen, curr, xmin, y, xmax, ymax, 9/fg=blue, bg - copy-to already-hiding-lines?, 0/false - break $render-trace:iter - } - # ignore the rest - compare already-hiding-lines?, 0/false - { - break-if-!= - var x/eax: int <- copy xmin - x, y <- draw-text-wrapping-right-then-down screen, "...", xmin, ymin, xmax, ymax, x, y, 9/fg=trace, bg - y <- increment - copy-to already-hiding-lines?, 1/true - } - } - i <- increment - loop - } - # prevent cursor from going too far down - clamp-cursor-to-bottom self, y, screen, xmin, ymin, xmax, ymax - mark-lines-clean self - return y -} - -fn render-trace-line screen: (addr screen), _self: (addr trace-line), xmin: int, ymin: int, xmax: int, ymax: int, fg: int, bg: int -> _/ecx: int { - var self/esi: (addr trace-line) <- copy _self - var xsave/edx: int <- copy xmin - var y/ecx: int <- copy ymin - var label-ah/eax: (addr handle array byte) <- get self, label - var _label/eax: (addr array byte) <- lookup *label-ah - var label/ebx: (addr array byte) <- copy _label - var is-error?/eax: boolean <- string-equal? label, "error" - compare is-error?, 0/false - { - break-if-!= - var x/eax: int <- copy xsave - { - var depth/edx: (addr int) <- get self, depth - x, y <- draw-int32-decimal-wrapping-right-then-down screen, *depth, xmin, ymin, xmax, ymax, x, y, fg, bg - x, y <- draw-text-wrapping-right-then-down screen, " ", xmin, ymin, xmax, ymax, x, y, fg, bg - # don't show label in UI; it's just for tests - } - xsave <- copy x - } - var data-ah/eax: (addr handle array byte) <- get self, data - var _data/eax: (addr array byte) <- lookup *data-ah - var data/ebx: (addr array byte) <- copy _data - var x/eax: int <- copy xsave - x, y <- draw-text-wrapping-right-then-down screen, data, xmin, ymin, xmax, ymax, x, y, fg, bg - y <- increment - return y -} - -fn should-render? _self: (addr trace), _line: (addr trace-line) -> _/eax: boolean { - var self/esi: (addr trace) <- copy _self - # if visible? is already cached, just return it - var dest/edx: (addr boolean) <- get self, recompute-visible? - compare *dest, 0/false - { - break-if-!= - var line/eax: (addr trace-line) <- copy _line - var result/eax: (addr boolean) <- get line, visible? - return *result - } - # recompute - var candidates-ah/eax: (addr handle array trace-line) <- get self, visible - var candidates/eax: (addr array trace-line) <- lookup *candidates-ah - var i/ecx: int <- copy 0 - var len/edx: int <- length candidates - { - compare i, len - break-if->= - { - var curr-offset/ecx: (offset trace-line) <- compute-offset candidates, i - var curr/ecx: (addr trace-line) <- index candidates, curr-offset - var match?/eax: boolean <- trace-lines-equal? curr, _line - compare match?, 0/false - break-if-= - var line/eax: (addr trace-line) <- copy _line - var dest/eax: (addr boolean) <- get line, visible? - copy-to *dest, 1/true - return 1/true - } - i <- increment - loop - } - var line/eax: (addr trace-line) <- copy _line - var dest/eax: (addr boolean) <- get line, visible? - copy-to *dest, 0/false - return 0/false -} - -# this is probably super-inefficient, string comparing every trace line -# against every visible line on every render -fn trace-lines-equal? _a: (addr trace-line), _b: (addr trace-line) -> _/eax: boolean { - var a/esi: (addr trace-line) <- copy _a - var b/edi: (addr trace-line) <- copy _b - var a-depth/ecx: (addr int) <- get a, depth - var b-depth/edx: (addr int) <- get b, depth - var benchmark/eax: int <- copy *b-depth - compare *a-depth, benchmark - { - break-if-= - return 0/false - } - var a-label-ah/eax: (addr handle array byte) <- get a, label - var _a-label/eax: (addr array byte) <- lookup *a-label-ah - var a-label/ecx: (addr array byte) <- copy _a-label - var b-label-ah/ebx: (addr handle array byte) <- get b, label - var b-label/eax: (addr array byte) <- lookup *b-label-ah - var label-match?/eax: boolean <- string-equal? a-label, b-label - { - compare label-match?, 0/false - break-if-!= - return 0/false - } - var a-data-ah/eax: (addr handle array byte) <- get a, data - var _a-data/eax: (addr array byte) <- lookup *a-data-ah - var a-data/ecx: (addr array byte) <- copy _a-data - var b-data-ah/ebx: (addr handle array byte) <- get b, data - var b-data/eax: (addr array byte) <- lookup *b-data-ah - var data-match?/eax: boolean <- string-equal? a-data, b-data - return data-match? -} - -fn clamp-cursor-to-top _self: (addr trace), _y: int { - var y/ecx: int <- copy _y - var self/esi: (addr trace) <- copy _self - var cursor-y/eax: (addr int) <- get self, cursor-y - compare *cursor-y, y - break-if->= - copy-to *cursor-y, y -} - -# extremely hacky; consider deleting test-render-trace-empty-3 when you clean this up -fn clamp-cursor-to-bottom _self: (addr trace), _y: int, screen: (addr screen), xmin: int, ymin: int, xmax: int, ymax: int { - var y/ebx: int <- copy _y - compare y, ymin - { - break-if-> - return - } - y <- decrement - var self/esi: (addr trace) <- copy _self - var cursor-y/eax: (addr int) <- get self, cursor-y - compare *cursor-y, y - break-if-<= - copy-to *cursor-y, y - # redraw cursor-line - # TODO: ugly duplication - var trace-ah/eax: (addr handle array trace-line) <- get self, data - var trace/eax: (addr array trace-line) <- lookup *trace-ah - var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index - var cursor-line-index/ecx: int <- copy *cursor-line-index-addr - var first-free/edx: (addr int) <- get self, first-free - compare cursor-line-index, *first-free - { - break-if-< - return - } - var cursor-offset/ecx: (offset trace-line) <- compute-offset trace, cursor-line-index - var cursor-line/ecx: (addr trace-line) <- index trace, cursor-offset - var display?/eax: boolean <- should-render? self, cursor-line - { - compare display?, 0/false - break-if-= - var dummy/ecx: int <- render-trace-line screen, cursor-line, xmin, y, xmax, ymax, 9/fg=blue, 7/cursor-line-bg - return - } - var dummy1/eax: int <- copy 0 - var dummy2/ecx: int <- copy 0 - dummy1, dummy2 <- draw-text-wrapping-right-then-down screen, "...", xmin, ymin, xmax, ymax, xmin, y, 9/fg=trace, 7/cursor-line-bg -} - -fn test-render-trace-empty { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 5/xmax, 4/ymax, 0/no-cursor - # - check-ints-equal y, 0, "F - test-render-trace-empty/cursor" - check-screen-row screen, 0/y, " ", "F - test-render-trace-empty" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-render-trace-empty/bg" -} - -fn test-render-trace-empty-2 { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 2/ymin, 5/xmax, 4/ymax, 0/no-cursor # cursor below top row - # - check-ints-equal y, 2, "F - test-render-trace-empty-2/cursor" - check-screen-row screen, 2/y, " ", "F - test-render-trace-empty-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-render-trace-empty-2/bg" -} - -fn test-render-trace-empty-3 { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 2/ymin, 5/xmax, 4/ymax, 1/show-cursor # try show cursor - # still no cursor to show - check-ints-equal y, 2, "F - test-render-trace-empty-3/cursor" - check-screen-row screen, 1/y, " ", "F - test-render-trace-empty-3/line-above-cursor" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-render-trace-empty-3/bg-for-line-above-cursor" - check-screen-row screen, 2/y, " ", "F - test-render-trace-empty-3" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-render-trace-empty-3/bg" -} - -fn test-render-trace-collapsed-by-default { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - trace-text t, "l", "data" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 5/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 5/xmax, 4/ymax, 0/no-cursor - # - check-ints-equal y, 1, "F - test-render-trace-collapsed-by-default/cursor" - check-screen-row screen, 0/y, "... ", "F - test-render-trace-collapsed-by-default" -} - -fn test-render-trace-error { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - error t, "error" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0xa/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor - # - check-ints-equal y, 1, "F - test-render-trace-error/cursor" - check-screen-row screen, 0/y, "error", "F - test-render-trace-error" -} - -fn test-render-trace-error-at-start { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - error t, "error" - trace-text t, "l", "data" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0xa/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor - # - check-ints-equal y, 2, "F - test-render-trace-error-at-start/cursor" - check-screen-row screen, 0/y, "error", "F - test-render-trace-error-at-start/0" - check-screen-row screen, 1/y, "... ", "F - test-render-trace-error-at-start/1" -} - -fn test-render-trace-error-at-end { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "data" - error t, "error" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0xa/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor - # - check-ints-equal y, 2, "F - test-render-trace-error-at-end/cursor" - check-screen-row screen, 0/y, "... ", "F - test-render-trace-error-at-end/0" - check-screen-row screen, 1/y, "error", "F - test-render-trace-error-at-end/1" -} - -fn test-render-trace-error-in-the-middle { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - error t, "error" - trace-text t, "l", "line 3" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0xa/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor - # - check-ints-equal y, 3, "F - test-render-trace-error-in-the-middle/cursor" - check-screen-row screen, 0/y, "... ", "F - test-render-trace-error-in-the-middle/0" - check-screen-row screen, 1/y, "error", "F - test-render-trace-error-in-the-middle/1" - check-screen-row screen, 2/y, "... ", "F - test-render-trace-error-in-the-middle/2" -} - -fn test-render-trace-cursor-in-single-line { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - error t, "error" - trace-text t, "l", "line 3" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0xa/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-render-trace-cursor-in-single-line/0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-render-trace-cursor-in-single-line/0/cursor" - check-screen-row screen, 1/y, "error ", "F - test-render-trace-cursor-in-single-line/1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-render-trace-cursor-in-single-line/1/cursor" - check-screen-row screen, 2/y, "... ", "F - test-render-trace-cursor-in-single-line/2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-render-trace-cursor-in-single-line/2/cursor" -} - -fn render-trace-menu screen: (addr screen) { - var width/eax: int <- copy 0 - var height/ecx: int <- copy 0 - width, height <- screen-size screen - var y/ecx: int <- copy height - y <- decrement - set-cursor-position screen, 0/x, y - draw-text-rightward-from-cursor screen, " ctrl-s ", width, 0/fg, 7/bg=grey - draw-text-rightward-from-cursor screen, " run sandbox ", width, 7/fg, 0/bg - draw-text-rightward-from-cursor screen, " ctrl-d ", width, 0/fg, 7/bg=grey - draw-text-rightward-from-cursor screen, " cursor down ", width, 7/fg, 0/bg - draw-text-rightward-from-cursor screen, " ctrl-u ", width, 0/fg, 7/bg=grey - draw-text-rightward-from-cursor screen, " cursor up ", width, 7/fg, 0/bg - draw-text-rightward-from-cursor screen, " tab ", width, 0/fg, 3/bg=cyan - draw-text-rightward-from-cursor screen, " move to sandbox ", width, 7/fg, 0/bg - draw-text-rightward-from-cursor screen, " enter ", width, 0/fg, 7/bg=grey - draw-text-rightward-from-cursor screen, " expand ", width, 7/fg, 0/bg - draw-text-rightward-from-cursor screen, " backspace ", width, 0/fg, 7/bg=grey - draw-text-rightward-from-cursor screen, " collapse ", width, 7/fg, 0/bg -} - -fn edit-trace _self: (addr trace), key: grapheme { - var self/esi: (addr trace) <- copy _self - # cursor down - { - compare key, 4/ctrl-d - break-if-!= - var cursor-y/eax: (addr int) <- get self, cursor-y - increment *cursor-y - return - } - # cursor up - { - compare key, 0x15/ctrl-u - break-if-!= - var cursor-y/eax: (addr int) <- get self, cursor-y - decrement *cursor-y - return - } - # enter = expand - { - compare key, 0xa/newline - break-if-!= - expand self - return - } - # backspace = collapse - { - compare key, 8/backspace - break-if-!= - collapse self - return - } -} - -fn expand _self: (addr trace) { - var self/esi: (addr trace) <- copy _self - var trace-ah/eax: (addr handle array trace-line) <- get self, data - var _trace/eax: (addr array trace-line) <- lookup *trace-ah - var trace/edi: (addr array trace-line) <- copy _trace - var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index - var cursor-line-index/ecx: int <- copy *cursor-line-index-addr - var cursor-line-offset/eax: (offset trace-line) <- compute-offset trace, cursor-line-index - var cursor-line/edx: (addr trace-line) <- index trace, cursor-line-offset - var cursor-line-visible?/eax: (addr boolean) <- get cursor-line, visible? - var cursor-line-depth/ebx: (addr int) <- get cursor-line, depth - var target-depth/ebx: int <- copy *cursor-line-depth - # if cursor-line is already visible, increment target-depth - compare *cursor-line-visible?, 0/false - { - break-if-= - target-depth <- increment - } - # reveal the run of lines starting at cursor-line-index with depth target-depth - var i/ecx: int <- copy cursor-line-index - var max/edx: (addr int) <- get self, first-free - { - compare i, *max - break-if->= - var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i - var curr-line/edx: (addr trace-line) <- index trace, curr-line-offset - var curr-line-depth/eax: (addr int) <- get curr-line, depth - compare *curr-line-depth, target-depth - break-if-< - { - break-if-!= - var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible? - copy-to *curr-line-visible?, 1/true - reveal-trace-line self, curr-line - } - i <- increment - loop - } -} - -fn collapse _self: (addr trace) { - var self/esi: (addr trace) <- copy _self - var trace-ah/eax: (addr handle array trace-line) <- get self, data - var _trace/eax: (addr array trace-line) <- lookup *trace-ah - var trace/edi: (addr array trace-line) <- copy _trace - var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index - var cursor-line-index/ecx: int <- copy *cursor-line-index-addr - var cursor-line-offset/eax: (offset trace-line) <- compute-offset trace, cursor-line-index - var cursor-line/edx: (addr trace-line) <- index trace, cursor-line-offset - var cursor-line-visible?/eax: (addr boolean) <- get cursor-line, visible? - # if cursor-line is not visible, do nothing - compare *cursor-line-visible?, 0/false - { - break-if-!= - return - } - # hide all lines between previous and next line with a lower depth - var cursor-line-depth/ebx: (addr int) <- get cursor-line, depth - var cursor-y/edx: (addr int) <- get self, cursor-y - var target-depth/ebx: int <- copy *cursor-line-depth - var i/ecx: int <- copy cursor-line-index - $collapse:loop1: { - compare i, 0 - break-if-< - var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i - var curr-line/eax: (addr trace-line) <- index trace, curr-line-offset - { - var curr-line-depth/eax: (addr int) <- get curr-line, depth - compare *curr-line-depth, target-depth - break-if-< $collapse:loop1 - } - # if cursor-line is visible, decrement cursor-y - { - var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible? - compare *curr-line-visible?, 0/false - break-if-= - decrement *cursor-y - } - i <- decrement - loop - } - i <- increment - var max/edx: (addr int) <- get self, first-free - $collapse:loop2: { - compare i, *max - break-if->= - var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i - var curr-line/edx: (addr trace-line) <- index trace, curr-line-offset - var curr-line-depth/eax: (addr int) <- get curr-line, depth - compare *curr-line-depth, target-depth - break-if-< - { - hide-trace-line self, curr-line - var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible? - copy-to *curr-line-visible?, 0/false - } - i <- increment - loop - } -} - -# the 'visible' array is not required to be in order -# elements can also be deleted out of order -# so it can have holes -# however, lines in it always have visible? set -# we'll use visible? being unset as a sign of emptiness -fn reveal-trace-line _self: (addr trace), line: (addr trace-line) { - var self/esi: (addr trace) <- copy _self - var visible-ah/eax: (addr handle array trace-line) <- get self, visible - var visible/eax: (addr array trace-line) <- lookup *visible-ah - var i/ecx: int <- copy 0 - var len/edx: int <- length visible - { - compare i, len - break-if->= - var curr-offset/edx: (offset trace-line) <- compute-offset visible, i - var curr/edx: (addr trace-line) <- index visible, curr-offset - var curr-visible?/eax: (addr boolean) <- get curr, visible? - compare *curr-visible?, 0/false - { - break-if-!= - # empty slot found - copy-object line, curr - return - } - i <- increment - loop - } - abort "too many visible lines; increase size of array trace.visible" -} - -fn hide-trace-line _self: (addr trace), line: (addr trace-line) { - var self/esi: (addr trace) <- copy _self - var visible-ah/eax: (addr handle array trace-line) <- get self, visible - var visible/eax: (addr array trace-line) <- lookup *visible-ah - var i/ecx: int <- copy 0 - var len/edx: int <- length visible - { - compare i, len - break-if->= - var curr-offset/edx: (offset trace-line) <- compute-offset visible, i - var curr/edx: (addr trace-line) <- index visible, curr-offset - var found?/eax: boolean <- trace-lines-equal? curr, line - compare found?, 0/false - { - break-if-= - clear-object curr - } - i <- increment - loop - } -} - -fn test-cursor-down-and-up-within-trace { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - error t, "error" - trace-text t, "l", "line 3" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0xa/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-cursor-down-and-up-within-trace/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-cursor-down-and-up-within-trace/pre-0/cursor" - check-screen-row screen, 1/y, "error ", "F - test-cursor-down-and-up-within-trace/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-cursor-down-and-up-within-trace/pre-1/cursor" - check-screen-row screen, 2/y, "... ", "F - test-cursor-down-and-up-within-trace/pre-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-cursor-down-and-up-within-trace/pre-2/cursor" - # cursor down - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-cursor-down-and-up-within-trace/down-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-cursor-down-and-up-within-trace/down-0/cursor" - check-screen-row screen, 1/y, "error ", "F - test-cursor-down-and-up-within-trace/down-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "||||| ", "F - test-cursor-down-and-up-within-trace/down-1/cursor" - check-screen-row screen, 2/y, "... ", "F - test-cursor-down-and-up-within-trace/down-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-cursor-down-and-up-within-trace/down-2/cursor" - # cursor up - edit-trace t, 0x15/ctrl-u - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-cursor-down-and-up-within-trace/up-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-cursor-down-and-up-within-trace/up-0/cursor" - check-screen-row screen, 1/y, "error ", "F - test-cursor-down-and-up-within-trace/up-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-cursor-down-and-up-within-trace/up-1/cursor" - check-screen-row screen, 2/y, "... ", "F - test-cursor-down-and-up-within-trace/up-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-cursor-down-and-up-within-trace/up-2/cursor" -} - -fn test-cursor-down-past-bottom-of-trace { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - error t, "error" - trace-text t, "l", "line 3" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0xa/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-cursor-down-past-bottom-of-trace/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-cursor-down-past-bottom-of-trace/pre-0/cursor" - check-screen-row screen, 1/y, "error ", "F - test-cursor-down-past-bottom-of-trace/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-cursor-down-past-bottom-of-trace/pre-1/cursor" - check-screen-row screen, 2/y, "... ", "F - test-cursor-down-past-bottom-of-trace/pre-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-cursor-down-past-bottom-of-trace/pre-2/cursor" - # cursor down several times - edit-trace t, 4/ctrl-d - edit-trace t, 4/ctrl-d - edit-trace t, 4/ctrl-d - edit-trace t, 4/ctrl-d - edit-trace t, 4/ctrl-d - # hack: we do need to render to make this test pass; we're mixing state management with rendering - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor - # cursor clamps at bottom - check-screen-row screen, 0/y, "... ", "F - test-cursor-down-past-bottom-of-trace/down-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-cursor-down-past-bottom-of-trace/down-0/cursor" - check-screen-row screen, 1/y, "error ", "F - test-cursor-down-past-bottom-of-trace/down-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-cursor-down-past-bottom-of-trace/down-1/cursor" - check-screen-row screen, 2/y, "... ", "F - test-cursor-down-past-bottom-of-trace/down-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||| ", "F - test-cursor-down-past-bottom-of-trace/down-2/cursor" -} - -fn test-expand-within-trace { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-text t, "l", "line 2" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-expand-within-trace/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-expand-within-trace/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-expand-within-trace/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-expand-within-trace/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-expand-within-trace/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-expand-within-trace/expand-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-expand-within-trace/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-expand-within-trace/expand-1/cursor" - check-screen-row screen, 2/y, " ", "F - test-expand-within-trace/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-expand-within-trace/expand-2/cursor" -} - -fn test-trace-expand-skips-lower-depth { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-lower t - trace-text t, "l", "line 2" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-expand-skips-lower-depth/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-expand-skips-lower-depth/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-expand-skips-lower-depth/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-expand-skips-lower-depth/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-expand-skips-lower-depth/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-expand-skips-lower-depth/expand-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-expand-skips-lower-depth/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-expand-skips-lower-depth/expand-1/cursor" - check-screen-row screen, 2/y, " ", "F - test-trace-expand-skips-lower-depth/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-expand-skips-lower-depth/expand-2/cursor" -} - -fn test-trace-expand-continues-past-lower-depth { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-lower t - trace-text t, "l", "line 1.1" - trace-higher t - trace-text t, "l", "line 2" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-expand-continues-past-lower-depth/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-expand-continues-past-lower-depth/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-expand-continues-past-lower-depth/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-expand-continues-past-lower-depth/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-expand-continues-past-lower-depth/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-expand-continues-past-lower-depth/expand-0/cursor" - # TODO: might be too wasteful to show every place where lines are hidden - check-screen-row screen, 1/y, "... ", "F - test-trace-expand-continues-past-lower-depth/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-expand-continues-past-lower-depth/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-expand-continues-past-lower-depth/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-expand-continues-past-lower-depth/expand-2/cursor" -} - -fn test-trace-expand-stops-at-higher-depth { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1.1" - trace-lower t - trace-text t, "l", "line 1.1.1" - trace-higher t - trace-text t, "l", "line 1.2" - trace-higher t - trace-text t, "l", "line 2" - trace-lower t - trace-text t, "l", "line 2.1" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 8/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-expand-stops-at-higher-depth/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-expand-stops-at-higher-depth/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-expand-stops-at-higher-depth/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-expand-stops-at-higher-depth/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1.1 ", "F - test-trace-expand-stops-at-higher-depth/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||||| ", "F - test-trace-expand-stops-at-higher-depth/expand-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-expand-stops-at-higher-depth/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-expand-stops-at-higher-depth/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 1.2 ", "F - test-trace-expand-stops-at-higher-depth/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-expand-stops-at-higher-depth/expand-2/cursor" - check-screen-row screen, 3/y, "... ", "F - test-trace-expand-stops-at-higher-depth/expand-3" - check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, " ", "F - test-trace-expand-stops-at-higher-depth/expand-3/cursor" - check-screen-row screen, 4/y, " ", "F - test-trace-expand-stops-at-higher-depth/expand-4" - check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, " ", "F - test-trace-expand-stops-at-higher-depth/expand-4/cursor" -} - -fn test-trace-expand-twice { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-lower t - trace-text t, "l", "line 1.1" - trace-higher t - trace-text t, "l", "line 2" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-expand-twice/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-expand-twice/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-expand-twice/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-expand-twice/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-expand-twice/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-expand-twice/expand-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-expand-twice/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-expand-twice/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-expand-twice/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-expand-twice/expand-2/cursor" - # cursor down - edit-trace t, 4/ctrl-d - # hack: we need to render here to make this test pass; we're mixing state management with rendering - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-expand-twice/down-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-expand-twice/down-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-expand-twice/down-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "||| ", "F - test-trace-expand-twice/down-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-expand-twice/down-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-expand-twice/down-2/cursor" - # expand again - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-expand-twice/expand2-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-expand-twice/expand2-0/cursor" - check-screen-row screen, 1/y, "1 line 1.1 ", "F - test-trace-expand-twice/expand2-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||||||||| ", "F - test-trace-expand-twice/expand2-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-expand-twice/expand2-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-expand-twice/expand2-2/cursor" -} - -fn test-trace-refresh-cursor { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-text t, "l", "line 2" - trace-text t, "l", "line 3" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-refresh-cursor/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-refresh-cursor/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-refresh-cursor/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-refresh-cursor/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-refresh-cursor/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-refresh-cursor/expand-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-trace-refresh-cursor/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-refresh-cursor/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 3 ", "F - test-trace-refresh-cursor/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-refresh-cursor/expand-2/cursor" - # cursor down - edit-trace t, 4/ctrl-d - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-refresh-cursor/down-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-refresh-cursor/down-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-trace-refresh-cursor/down-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-refresh-cursor/down-1/cursor" - check-screen-row screen, 2/y, "0 line 3 ", "F - test-trace-refresh-cursor/down-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "|||||||| ", "F - test-trace-refresh-cursor/down-2/cursor" - # recreate trace - clear-trace t - trace-text t, "l", "line 1" - trace-text t, "l", "line 2" - trace-text t, "l", "line 3" - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # cursor remains unchanged - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-refresh-cursor/refresh-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-refresh-cursor/refresh-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-trace-refresh-cursor/refresh-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-refresh-cursor/refresh-1/cursor" - check-screen-row screen, 2/y, "0 line 3 ", "F - test-trace-refresh-cursor/refresh-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "|||||||| ", "F - test-trace-refresh-cursor/refresh-2/cursor" -} - -fn test-trace-preserve-cursor-on-refresh { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-text t, "l", "line 2" - trace-text t, "l", "line 3" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-preserve-cursor-on-refresh/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-preserve-cursor-on-refresh/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-preserve-cursor-on-refresh/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-preserve-cursor-on-refresh/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-preserve-cursor-on-refresh/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-preserve-cursor-on-refresh/expand-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-trace-preserve-cursor-on-refresh/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-preserve-cursor-on-refresh/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 3 ", "F - test-trace-preserve-cursor-on-refresh/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-preserve-cursor-on-refresh/expand-2/cursor" - # cursor down - edit-trace t, 4/ctrl-d - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-preserve-cursor-on-refresh/down-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-preserve-cursor-on-refresh/down-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-trace-preserve-cursor-on-refresh/down-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-preserve-cursor-on-refresh/down-1/cursor" - check-screen-row screen, 2/y, "0 line 3 ", "F - test-trace-preserve-cursor-on-refresh/down-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "|||||||| ", "F - test-trace-preserve-cursor-on-refresh/down-2/cursor" - # recreate trace with slightly different lines - clear-trace t - trace-text t, "l", "line 4" - trace-text t, "l", "line 5" - trace-text t, "l", "line 3" # cursor line is unchanged - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # cursor remains unchanged - check-screen-row screen, 0/y, "0 line 4 ", "F - test-trace-preserve-cursor-on-refresh/refresh-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-preserve-cursor-on-refresh/refresh-0/cursor" - check-screen-row screen, 1/y, "0 line 5 ", "F - test-trace-preserve-cursor-on-refresh/refresh-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-preserve-cursor-on-refresh/refresh-1/cursor" - check-screen-row screen, 2/y, "0 line 3 ", "F - test-trace-preserve-cursor-on-refresh/refresh-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "|||||||| ", "F - test-trace-preserve-cursor-on-refresh/refresh-2/cursor" -} - -fn test-trace-keep-cursor-visible-on-refresh { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-text t, "l", "line 2" - trace-text t, "l", "line 3" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-keep-cursor-visible-on-refresh/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-keep-cursor-visible-on-refresh/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-keep-cursor-visible-on-refresh/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-keep-cursor-visible-on-refresh/expand-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-trace-keep-cursor-visible-on-refresh/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 3 ", "F - test-trace-keep-cursor-visible-on-refresh/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/expand-2/cursor" - # cursor down - edit-trace t, 4/ctrl-d - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-keep-cursor-visible-on-refresh/down-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/down-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-trace-keep-cursor-visible-on-refresh/down-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/down-1/cursor" - check-screen-row screen, 2/y, "0 line 3 ", "F - test-trace-keep-cursor-visible-on-refresh/down-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "|||||||| ", "F - test-trace-keep-cursor-visible-on-refresh/down-2/cursor" - # recreate trace with entirely different lines - clear-trace t - trace-text t, "l", "line 4" - trace-text t, "l", "line 5" - trace-text t, "l", "line 6" - mark-lines-dirty t - clear-screen screen - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # trace collapses, and cursor bumps up - check-screen-row screen, 0/y, "... ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-1/cursor" - check-screen-row screen, 2/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-2/cursor" -} - -fn test-trace-collapse-at-top { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-lower t - trace-text t, "l", "line 1.1" - trace-higher t - trace-text t, "l", "line 2" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse-at-top/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse-at-top/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse-at-top/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-at-top/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-collapse-at-top/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-collapse-at-top/expand-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-collapse-at-top/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-at-top/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-collapse-at-top/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-collapse-at-top/expand-2/cursor" - # collapse - edit-trace t, 8/backspace - # hack: we need to render here to make this test pass; we're mixing state management with rendering - clear-screen screen - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-ints-equal y, 1, "F - test-trace-collapse-at-top/post-0/y" - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse-at-top/post-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse-at-top/post-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse-at-top/post-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-at-top/post-1/cursor" -} - -fn test-trace-collapse { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-text t, "l", "line 2" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-collapse/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-collapse/expand-0/cursor" - check-screen-row screen, 1/y, "0 line 2 ", "F - test-trace-collapse/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse/expand-1/cursor" - # cursor down - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # collapse - edit-trace t, 8/backspace - clear-screen screen - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-ints-equal y, 1, "F - test-trace-collapse/post-0/y" - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse/post-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse/post-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse/post-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse/post-1/cursor" -} - -fn test-trace-collapse-skips-invisible-lines { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-lower t - trace-text t, "l", "line 1.1" - trace-higher t - trace-text t, "l", "line 2" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse-skips-invisible-lines/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse-skips-invisible-lines/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse-skips-invisible-lines/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-skips-invisible-lines/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # two visible lines with an invisible line in between - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-collapse-skips-invisible-lines/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-collapse-skips-invisible-lines/expand-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-collapse-skips-invisible-lines/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-skips-invisible-lines/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-collapse-skips-invisible-lines/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-collapse-skips-invisible-lines/expand-2/cursor" - # cursor down to second visible line - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # collapse - edit-trace t, 8/backspace - clear-screen screen - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-ints-equal y, 1, "F - test-trace-collapse-skips-invisible-lines/post-0/y" - var cursor-y/eax: (addr int) <- get t, cursor-y - check-ints-equal *cursor-y, 0, "F - test-trace-collapse-skips-invisible-lines/post-0/cursor-y" - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse-skips-invisible-lines/post-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse-skips-invisible-lines/post-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse-skips-invisible-lines/post-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-skips-invisible-lines/post-1/cursor" -} - -fn test-trace-collapse-two-levels { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-lower t - trace-text t, "l", "line 1.1" - trace-higher t - trace-text t, "l", "line 2" - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 4/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse-two-levels/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse-two-levels/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse-two-levels/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-two-levels/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # two visible lines with an invisible line in between - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-collapse-two-levels/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-collapse-two-levels/expand-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-collapse-two-levels/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-two-levels/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-collapse-two-levels/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-collapse-two-levels/expand-2/cursor" - # cursor down to ellipses - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # two visible lines with an invisible line in between - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-collapse-two-levels/expand2-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-collapse-two-levels/expand2-0/cursor" - check-screen-row screen, 1/y, "1 line 1.1 ", "F - test-trace-collapse-two-levels/expand2-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||||||||| ", "F - test-trace-collapse-two-levels/expand2-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-collapse-two-levels/expand2-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-collapse-two-levels/expand2-2/cursor" - # cursor down to second visible line - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # collapse - edit-trace t, 8/backspace - clear-screen screen - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor - # - check-ints-equal y, 1, "F - test-trace-collapse-two-levels/post-0/y" - var cursor-y/eax: (addr int) <- get t, cursor-y - check-ints-equal *cursor-y, 0, "F - test-trace-collapse-two-levels/post-0/cursor-y" - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse-two-levels/post-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse-two-levels/post-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse-two-levels/post-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-two-levels/post-1/cursor" -} - -fn test-trace-collapse-nested-level { - var t-storage: trace - var t/esi: (addr trace) <- address t-storage - initialize-trace t, 0x10, 0x10 - # - trace-text t, "l", "line 1" - trace-lower t - trace-text t, "l", "line 1.1" - trace-higher t - trace-text t, "l", "line 2" - trace-lower t - trace-text t, "l", "line 2.1" - trace-text t, "l", "line 2.2" - trace-higher t - # setup: screen - var screen-on-stack: screen - var screen/edi: (addr screen) <- address screen-on-stack - initialize-screen screen, 0x10/width, 8/height - # - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - # - check-screen-row screen, 0/y, "... ", "F - test-trace-collapse-nested-level/pre-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||| ", "F - test-trace-collapse-nested-level/pre-0/cursor" - check-screen-row screen, 1/y, " ", "F - test-trace-collapse-nested-level/pre-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-nested-level/pre-1/cursor" - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - # two visible lines with an invisible line in between - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-collapse-nested-level/expand-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-collapse-nested-level/expand-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-collapse-nested-level/expand-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-nested-level/expand-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-collapse-nested-level/expand-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-collapse-nested-level/expand-2/cursor" - check-screen-row screen, 3/y, "... ", "F - test-trace-collapse-nested-level/expand-3" - check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, " ", "F - test-trace-collapse-nested-level/expand-3/cursor" - # cursor down to bottom - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - edit-trace t, 4/ctrl-d - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - # expand - edit-trace t, 0xa/enter - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - # two visible lines with an invisible line in between - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-collapse-nested-level/expand2-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-collapse-nested-level/expand2-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-collapse-nested-level/expand2-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-nested-level/expand2-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-collapse-nested-level/expand2-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ", "F - test-trace-collapse-nested-level/expand2-2/cursor" - check-screen-row screen, 3/y, "1 line 2.1 ", "F - test-trace-collapse-nested-level/expand2-3" - check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "|||||||||| ", "F - test-trace-collapse-nested-level/expand2-3/cursor" - check-screen-row screen, 4/y, "1 line 2.2 ", "F - test-trace-collapse-nested-level/expand2-4" - check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, " ", "F - test-trace-collapse-nested-level/expand2-4/cursor" - # collapse - edit-trace t, 8/backspace - clear-screen screen - var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor - # - check-ints-equal y, 4, "F - test-trace-collapse-nested-level/post-0/y" - var cursor-y/eax: (addr int) <- get t, cursor-y - check-ints-equal *cursor-y, 2, "F - test-trace-collapse-nested-level/post-0/cursor-y" - check-screen-row screen, 0/y, "0 line 1 ", "F - test-trace-collapse-nested-level/post-0" - check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-trace-collapse-nested-level/post-0/cursor" - check-screen-row screen, 1/y, "... ", "F - test-trace-collapse-nested-level/post-1" - check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-trace-collapse-nested-level/post-1/cursor" - check-screen-row screen, 2/y, "0 line 2 ", "F - test-trace-collapse-nested-level/post-2" - check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "|||||||| ", "F - test-trace-collapse-nested-level/post-2/cursor" - check-screen-row screen, 3/y, "... ", "F - test-trace-collapse-nested-level/post-3" - check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, " ", "F - test-trace-collapse-nested-level/post-3/cursor" -} diff --git a/baremetal/shell/vimrc.vim b/baremetal/shell/vimrc.vim deleted file mode 100644 index 348fe364..00000000 --- a/baremetal/shell/vimrc.vim +++ /dev/null @@ -1,2 +0,0 @@ -" when opening files in this directory, load vimrc from cwd (top-level) -source vimrc.vim diff --git a/baremetal/vga_palette b/baremetal/vga_palette deleted file mode 100644 index 4c04d989..00000000 --- a/baremetal/vga_palette +++ /dev/null @@ -1,283 +0,0 @@ -# Default VGA 256-color palette - -# First 16 colors - 0: 0 0 0 - 1: 0 0 42 .......................................... - 2: 0 42 0 .......................................... - 3: 0 42 42 .......................................... .......................................... - 4: 42 0 0 .......................................... - 5: 42 0 42 .......................................... .......................................... - 6: 42 21 0 .......................................... ..................... - 7: 42 42 42 .......................................... .......................................... .......................................... - 8: 21 21 21 ..................... ..................... ..................... - 9: 21 21 63 ..................... ..................... ............................................................... - 10: 21 63 21 ..................... ............................................................... ..................... - 11: 21 63 63 ..................... ............................................................... ............................................................... - 12: 63 21 21 ............................................................... ..................... ..................... - 13: 63 21 63 ............................................................... ..................... ............................................................... - 14: 63 63 21 ............................................................... ............................................................... ..................... - 15: 63 63 63 ............................................................... ............................................................... ............................................................... - -# Greyscale - 16: 0 0 0 - 17: 5 5 5 ..... ..... ..... - 18: 8 8 8 ........ ........ ........ - 19: 11 11 11 ........... ........... ........... - 20: 14 14 14 .............. .............. .............. - 21: 17 17 17 ................. ................. ................. - 22: 20 20 20 .................... .................... .................... - 23: 24 24 24 ........................ ........................ ........................ - 24: 28 28 28 ............................ ............................ ............................ - 25: 32 32 32 ................................ ................................ ................................ - 26: 36 36 36 .................................... .................................... .................................... - 27: 40 40 40 ........................................ ........................................ ........................................ - 28: 45 45 45 ............................................. ............................................. ............................................. - 29: 50 50 50 .................................................. .................................................. .................................................. - 30: 56 56 56 ........................................................ ........................................................ ........................................................ - 31: 63 63 63 ............................................................... ............................................................... ............................................................... - -# Cycle 0 (light) - 32: 0 0 63 ............................................................... - 33: 16 0 63 ................ ............................................................... - 34: 31 0 63 ............................... ............................................................... - 35: 47 0 63 ............................................... ............................................................... - 36: 63 0 63 ............................................................... ............................................................... - 37: 63 0 47 ............................................................... ............................................... - 38: 63 0 31 ............................................................... ............................... - 39: 63 0 16 ............................................................... ................ - 40: 63 0 0 ............................................................... - 41: 63 16 0 ............................................................... ................ - 42: 63 31 0 ............................................................... ............................... - 43: 63 47 0 ............................................................... ............................................... - 44: 63 63 0 ............................................................... ............................................................... - 45: 47 63 0 ............................................... ............................................................... - 46: 31 63 0 ............................... ............................................................... - 47: 16 63 0 ................ ............................................................... - 48: 0 63 0 ............................................................... - 49: 0 63 16 ............................................................... ................ - 50: 0 63 31 ............................................................... ............................... - 51: 0 63 47 ............................................................... ............................................... - 52: 0 63 63 ............................................................... ............................................................... - 53: 0 47 63 ............................................... ............................................................... - 54: 0 31 63 ............................... ............................................................... - 55: 0 16 63 ................ ............................................................... - - # Cycle 1 (lighter) - 56: 31 31 63 ............................... ............................... ............................................................... - 57: 39 31 63 ....................................... ............................... ............................................................... - 58: 47 31 63 ............................................... ............................... ............................................................... - 59: 55 31 63 ....................................................... ............................... ............................................................... - 60: 63 31 63 ............................................................... ............................... ............................................................... - 61: 63 31 55 ............................................................... ............................... ....................................................... - 62: 63 31 47 ............................................................... ............................... ............................................... - 63: 63 31 39 ............................................................... ............................... ....................................... - 64: 63 31 31 ............................................................... ............................... ............................... - 65: 63 39 31 ............................................................... ....................................... ............................... - 66: 63 47 31 ............................................................... ............................................... ............................... - 67: 63 55 31 ............................................................... ....................................................... ............................... - 68: 63 63 31 ............................................................... ............................................................... ............................... - 69: 55 63 31 ....................................................... ............................................................... ............................... - 70: 47 63 31 ............................................... ............................................................... ............................... - 71: 39 63 31 ....................................... ............................................................... ............................... - 72: 31 63 31 ............................... ............................................................... ............................... - 73: 31 63 39 ............................... ............................................................... ....................................... - 74: 31 63 47 ............................... ............................................................... ............................................... - 75: 31 63 55 ............................... ............................................................... ....................................................... - 76: 31 63 63 ............................... ............................................................... ............................................................... - 77: 31 55 63 ............................... ....................................................... ............................................................... - 78: 31 47 63 ............................... ............................................... ............................................................... - 79: 31 39 63 ............................... ....................................... ............................................................... - - # Cycle 2 (lightest) - 80: 45 45 63 ............................................. ............................................. ............................................................... - 81: 49 45 63 ................................................. ............................................. ............................................................... - 82: 54 45 63 ...................................................... ............................................. ............................................................... - 83: 58 45 63 .......................................................... ............................................. ............................................................... - 84: 63 45 63 ............................................................... ............................................. ............................................................... - 85: 63 45 58 ............................................................... ............................................. .......................................................... - 86: 63 45 54 ............................................................... ............................................. ...................................................... - 87: 63 45 49 ............................................................... ............................................. ................................................. - 88: 63 45 45 ............................................................... ............................................. ............................................. - 89: 63 49 45 ............................................................... ................................................. ............................................. - 90: 63 54 45 ............................................................... ...................................................... ............................................. - 91: 63 58 45 ............................................................... .......................................................... ............................................. - 92: 63 63 45 ............................................................... ............................................................... ............................................. - 93: 58 63 45 .......................................................... ............................................................... ............................................. - 94: 54 63 45 ...................................................... ............................................................... ............................................. - 95: 49 63 45 ................................................. ............................................................... ............................................. - 96: 45 63 45 ............................................. ............................................................... ............................................. - 97: 45 63 49 ............................................. ............................................................... ................................................. - 98: 45 63 54 ............................................. ............................................................... ...................................................... - 99: 45 63 58 ............................................. ............................................................... .......................................................... -100: 45 63 63 ............................................. ............................................................... ............................................................... -101: 45 58 63 ............................................. .......................................................... ............................................................... -102: 45 54 63 ............................................. ...................................................... ............................................................... -103: 45 49 63 ............................................. ................................................. ............................................................... - -# Cycle 3 (sober) -104: 0 0 28 ............................ -105: 7 0 28 ....... ............................ -106: 14 0 28 .............. ............................ -107: 21 0 28 ..................... ............................ -108: 28 0 28 ............................ ............................ -109: 28 0 21 ............................ ..................... -110: 28 0 14 ............................ .............. -111: 28 0 7 ............................ ....... -112: 28 0 0 ............................ -113: 28 7 0 ............................ ....... -114: 28 14 0 ............................ .............. -115: 28 21 0 ............................ ..................... -116: 28 28 0 ............................ ............................ -117: 21 28 0 ..................... ............................ -118: 14 28 0 .............. ............................ -119: 7 28 0 ....... ............................ -120: 0 28 0 ............................ -121: 0 28 7 ............................ ....... -122: 0 28 14 ............................ .............. -123: 0 28 21 ............................ ..................... -124: 0 28 28 ............................ ............................ -125: 0 21 28 ..................... ............................ -126: 0 14 28 .............. ............................ -127: 0 7 28 ....... ............................ - -# Cycle 4 (darker sober) -128: 14 14 28 .............. .............. ............................ -129: 17 14 28 ................. .............. ............................ -130: 21 14 28 ..................... .............. ............................ -131: 24 14 28 ........................ .............. ............................ -132: 28 14 28 ............................ .............. ............................ -133: 28 14 24 ............................ .............. ........................ -134: 28 14 21 ............................ .............. ..................... -135: 28 14 17 ............................ .............. ................. -136: 28 14 14 ............................ .............. .............. -137: 28 17 14 ............................ ................. .............. -138: 28 21 14 ............................ ..................... .............. -139: 28 24 14 ............................ ........................ .............. -140: 28 28 14 ............................ ............................ .............. -141: 24 28 14 ........................ ............................ .............. -142: 21 28 14 ..................... ............................ .............. -143: 17 28 14 ................. ............................ .............. -144: 14 28 14 .............. ............................ .............. -145: 14 28 17 .............. ............................ ................. -146: 14 28 21 .............. ............................ ..................... -147: 14 28 24 .............. ............................ ........................ -148: 14 28 28 .............. ............................ ............................ -149: 14 24 28 .............. ........................ ............................ -150: 14 21 28 .............. ..................... ............................ -151: 14 17 28 .............. ................. ............................ - -# Cycle 5 (darkest sober) -152: 20 20 28 .................... .................... ............................ -153: 22 20 28 ...................... .................... ............................ -154: 24 20 28 ........................ .................... ............................ -155: 26 20 28 .......................... .................... ............................ -156: 28 20 28 ............................ .................... ............................ -157: 28 20 26 ............................ .................... .......................... -158: 28 20 24 ............................ .................... ........................ -159: 28 20 22 ............................ .................... ...................... -160: 28 20 20 ............................ .................... .................... -161: 28 22 20 ............................ ...................... .................... -162: 28 24 20 ............................ ........................ .................... -163: 28 26 20 ............................ .......................... .................... -164: 28 28 20 ............................ ............................ .................... -165: 26 28 20 .......................... ............................ .................... -166: 24 28 20 ........................ ............................ .................... -167: 22 28 20 ...................... ............................ .................... -168: 20 28 20 .................... ............................ .................... -169: 20 28 22 .................... ............................ ...................... -170: 20 28 24 .................... ............................ ........................ -171: 20 28 26 .................... ............................ .......................... -172: 20 28 28 .................... ............................ ............................ -173: 20 26 28 .................... .......................... ............................ -174: 20 24 28 .................... ........................ ............................ -175: 20 22 28 .................... ...................... ............................ - -# Cycle 6 (dark) -176: 0 0 16 ................ -177: 4 0 16 .... ................ -178: 8 0 16 ........ ................ -179: 12 0 16 ............ ................ -180: 16 0 16 ................ ................ -181: 16 0 12 ................ ............ -182: 16 0 8 ................ ........ -183: 16 0 4 ................ .... -184: 16 0 0 ................ -185: 16 4 0 ................ .... -186: 16 8 0 ................ ........ -187: 16 12 0 ................ ............ -188: 16 16 0 ................ ................ -189: 12 16 0 ............ ................ -190: 8 16 0 ........ ................ -191: 4 16 0 .... ................ -192: 0 16 0 ................ -193: 0 16 4 ................ .... -194: 0 16 8 ................ ........ -195: 0 16 12 ................ ............ -196: 0 16 16 ................ ................ -197: 0 12 16 ............ ................ -198: 0 8 16 ........ ................ -199: 0 4 16 .... ................ - -# Cycle 7 (darker) -200: 8 8 16 ........ ........ ................ -201: 10 8 16 .......... ........ ................ -202: 12 8 16 ............ ........ ................ -203: 14 8 16 .............. ........ ................ -204: 16 8 16 ................ ........ ................ -205: 16 8 14 ................ ........ .............. -206: 16 8 12 ................ ........ ............ -207: 16 8 10 ................ ........ .......... -208: 16 8 8 ................ ........ ........ -209: 16 10 8 ................ .......... ........ -210: 16 12 8 ................ ............ ........ -211: 16 14 8 ................ .............. ........ -212: 16 16 8 ................ ................ ........ -213: 14 16 8 .............. ................ ........ -214: 12 16 8 ............ ................ ........ -215: 10 16 8 .......... ................ ........ -216: 8 16 8 ........ ................ ........ -217: 8 16 10 ........ ................ .......... -218: 8 16 12 ........ ................ ............ -219: 8 16 14 ........ ................ .............. -220: 8 16 16 ........ ................ ................ -221: 8 14 16 ........ .............. ................ -222: 8 12 16 ........ ............ ................ -223: 8 10 16 ........ .......... ................ - -# Cycle 8 (darkest) -224: 11 11 16 ........... ........... ................ -225: 12 11 16 ............ ........... ................ -226: 13 11 16 ............. ........... ................ -227: 15 11 16 ............... ........... ................ -228: 16 11 16 ................ ........... ................ -229: 16 11 15 ................ ........... ............... -230: 16 11 13 ................ ........... ............. -231: 16 11 12 ................ ........... ............ -232: 16 11 11 ................ ........... ........... -233: 16 12 11 ................ ............ ........... -234: 16 13 11 ................ ............. ........... -235: 16 15 11 ................ ............... ........... -236: 16 16 11 ................ ................ ........... -237: 15 16 11 ............... ................ ........... -238: 13 16 11 ............. ................ ........... -239: 12 16 11 ............ ................ ........... -240: 11 16 11 ........... ................ ........... -241: 11 16 12 ........... ................ ............ -242: 11 16 13 ........... ................ ............. -243: 11 16 15 ........... ................ ............... -244: 11 16 16 ........... ................ ................ -245: 11 15 16 ........... ............... ................ -246: 11 13 16 ........... ............. ................ -247: 11 12 16 ........... ............ ................ - -# Black -248: 0 0 0 -249: 0 0 0 -250: 0 0 0 -251: 0 0 0 -252: 0 0 0 -253: 0 0 0 -254: 0 0 0 -255: 0 0 0 - -# vim:listchars=:nowrap diff --git a/baremetal/vga_palette.c b/baremetal/vga_palette.c deleted file mode 100644 index 9f4161ce..00000000 --- a/baremetal/vga_palette.c +++ /dev/null @@ -1,179 +0,0 @@ -/* Visualize the standard VGA palette. - * Based on https://github.com/canidlogic/vgapal (MIT License) */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -char* bar(int n) { - char* result = calloc(1024, 32); - int i; - strcat(result, "<div style='float:left; width:40em'>"); - for (i = 0; i < n; ++i) -//? result[i] = '.'; - strcat(result, "■"); /* black square */ -//? for (; i < 64; ++i) -//? result[i] = ' '; -//? result[64] = '\0'; - strcat(result, " </div>"); /* make sure the div occupies space */ - return result; -} - -/* convert 6-bit color to 8-bit color */ -int levelUp(int n) { - assert(n < 64); - /* duplicate two most significant bits in two least significant bits */ - return (n<<2) | (n>>4); -} - -void addColor(int r, int g, int b) { - static int i = 0; -//? printf("%02x %02x %02x\n", r, g, b); -//? printf("%3d: %2d %2d %2d %s %s %s\n", i, r, g, b, bar(r), bar(g), bar(b)); - printf("<div style='clear:both; white-space:pre; color:#%02x%02x%02x'><div style='float:left; margin-right:1em'>%03d: %02d %02d %02d</div> %s %s %s</div>\n", levelUp(r), levelUp(g), levelUp(b), i, r, g, b, bar(r), bar(g), bar(b)); - ++i; -} - -void addGrayColor(int v) { - addColor(v, v, v); -} - -void add16Color(int lo, int melo, int mehi, int hi) { - int r, g, b, i, h, l; - - for (i = 0; i < 8; i++) { - r = g = b = lo; - if (i & 4) r = mehi; - if (i & 2) g = (i==6)?melo:mehi; /* exception: color 6 is brown rather than dark yellow */ - if (i & 1) b = mehi; - addColor(r, g, b); - } - - for (i = 0; i < 8; i++) { - r = g = b = melo; - if (i & 4) r = hi; - if (i & 2) g = hi; - if (i & 1) b = hi; - addColor(r, g, b); - } -} - -/* Add four colors to the palette corresponding to a "run" within an RGB cycle. - * - * start - high and low starting states for each channel at the start of the run - * ch - the channel to change from high to low or low to high */ -void addRun(int start, int ch, int lo, int melo, int me, int mehi, int hi) { - int r, g, b, i, up; - - /* Check parameters */ - if (start < 0 || start > 7) - abort(); - if (ch != 1 && ch != 2 && ch != 4) - abort(); - - /* Get the starting RGB color and add it */ - r = lo; - g = lo; - b = lo; - if ((start & 4) == 4) - r = hi; - if ((start & 2) == 2) - g = hi; - if ((start & 1) == 1) - b = hi; - addColor(r, g, b); - - /* If selected channel starts high, we're going down; otherwise we're going up */ - up = (start & ch) != ch; - - /* Add remaining three colors of the run */ - switch (ch) { - case 4: r = up?melo:mehi; break; - case 2: g = up?melo:mehi; break; - case 1: b = up?melo:mehi; break; - } - addColor(r, g, b); - - switch (ch) { - case 4: r = me; break; - case 2: g = me; break; - case 1: b = me; break; - } - addColor(r, g, b); - - switch (ch) { - case 4: r = up?mehi:melo; break; - case 2: g = up?mehi:melo; break; - case 1: b = up?mehi:melo; break; - } - addColor(r, g, b); -} - -/* A cycle consists of six 4-color runs, each of which transitions from - * one hue to another until arriving back at starting position. */ -void addCycle(int lo, int melo, int me, int mehi, int hi) { - int hue = 1; /* blue */ - addRun(hue, 4, lo, melo, me, mehi, hi); - hue ^= 4; - assert(hue == 5); - addRun(hue, 1, lo, melo, me, mehi, hi); - hue ^= 1; - assert(hue == 4); - addRun(hue, 2, lo, melo, me, mehi, hi); - hue ^= 2; - assert(hue == 6); - addRun(hue, 4, lo, melo, me, mehi, hi); - hue ^= 4; - assert(hue == 2); - addRun(hue, 1, lo, melo, me, mehi, hi); - hue ^= 1; - assert(hue == 3); - addRun(hue, 2, lo, melo, me, mehi, hi); -} - -int main(void) { - int i; - - /* 16-color palette */ - add16Color(0, 21, 42, 63); - - /* 16 shades of gray */ - addGrayColor( 0); - addGrayColor( 5); - addGrayColor( 8); - addGrayColor(11); - addGrayColor(14); - addGrayColor(17); - addGrayColor(20); - addGrayColor(24); - addGrayColor(28); - addGrayColor(32); - addGrayColor(36); - addGrayColor(40); - addGrayColor(45); - addGrayColor(50); - addGrayColor(56); - addGrayColor(63); - - /* Nine RGB cycles organized in three groups of three cycles, - * The groups represent high/medium/low value, - * and the cycles within the groups represent high/medium/low saturation. */ - addCycle( 0, 16, 31, 47, 63); - addCycle(31, 39, 47, 55, 63); - addCycle(45, 49, 54, 58, 63); - - addCycle( 0, 7, 14, 21, 28); - addCycle(14, 17, 21, 24, 28); - addCycle(20, 22, 24, 26, 28); - - addCycle( 0, 4, 8, 12, 16); - addCycle( 8, 10, 12, 14, 16); - addCycle(11, 12, 13, 15, 16); - - /* final eight palette entries are full black */ - for (i = 0; i < 8; ++i) - addGrayColor(0); - - return 0; -} diff --git a/baremetal/vga_palette.png b/baremetal/vga_palette.png deleted file mode 100644 index cea46962..00000000 --- a/baremetal/vga_palette.png +++ /dev/null Binary files differdiff --git a/baremetal/vimrc.vim b/baremetal/vimrc.vim deleted file mode 100644 index 348fe364..00000000 --- a/baremetal/vimrc.vim +++ /dev/null @@ -1,2 +0,0 @@ -" when opening files in this directory, load vimrc from cwd (top-level) -source vimrc.vim |