about summary refs log tree commit diff stats
path: root/103grapheme.subx
diff options
context:
space:
mode:
Diffstat (limited to '103grapheme.subx')
-rw-r--r--103grapheme.subx173
1 files changed, 173 insertions, 0 deletions
diff --git a/103grapheme.subx b/103grapheme.subx
new file mode 100644
index 00000000..d26a0b58
--- /dev/null
+++ b/103grapheme.subx
@@ -0,0 +1,173 @@
+# 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