https://github.com/akkartik/mu/blob/main/103grapheme.subx

      1 # Use the built-in font to draw a grapheme to real screen.
      2 #
      3 # We need to do this in machine code because Mu doesn't have global variables
      4 # yet (for the start of video memory).
      5 #
      6 # There are uncomfortable assumptions baked in here about english/latin
      7 # script. We convert the grid of pixels into a fixed-width grid of graphemes,
      8 # which may not work well with other language families.
      9
     10 == code
     11
     12 # The Mu computer's screen is 1024px wide and 768px tall.
     13 # The Mu computer's font is 8px wide and 16px tall.
     14 # Therefore 'x' here is in [0, 128), and 'y' is in [0, 48)
     15 # Doesn't update the cursor; where the cursor should go after printing the
     16 # current grapheme is a higher-level concern.
     17 draw-grapheme-on-real-screen:  # g: grapheme, x: int, y: int, color: int, background-color: int
     18     # . prologue
     19     55/push-ebp
     20     89/<- %ebp 4/r32/esp
     21     # . save registers
     22     50/push-eax
     23     51/push-ecx
     24     52/push-edx
     25     53/push-ebx
     26     56/push-esi
     27     # var letter-bitmap/esi = font[g]
     28     8b/-> *(ebp+8) 6/r32/esi
     29     c1 4/subop/shift-left %esi 4/imm8
     30     81 0/subop/add %esi Font/imm32
     31     # if (letter-bitmap >= 0x9400) return  # characters beyond ASCII currently not supported
     32     81 7/subop/compare %esi 0x9400/imm32
     33     7d/jump-if->= $draw-grapheme-on-real-screen:end/disp8
     34     # var ycurr/edx: int = y*16
     35     8b/-> *(ebp+0x10) 2/r32/edx
     36     c1 4/subop/shift-left %edx 4/imm8
     37     # var ymax/ebx: int = ycurr + 16
     38     8b/-> *(ebp+0x10) 3/r32/ebx
     39     c1 4/subop/shift-left %ebx 4/imm8
     40     81 0/subop/add %ebx 0x10/imm32
     41     {
     42       # if (ycurr >= ymax) break
     43       39/compare %edx 3/r32/ebx
     44       7d/jump-if->= break/disp8
     45       # var xcurr/eax: int = x*8 + 7
     46       8b/-> *(ebp+0xc) 0/r32/eax  # font-width - 1
     47       c1 4/subop/shift-left %eax 3/imm8
     48       81 0/subop/add %eax 7/imm32
     49       # var xmin/ecx: int = x*8
     50       8b/-> *(ebp+0xc) 1/r32/ecx
     51       c1 4/subop/shift-left %ecx 3/imm8
     52       # var row-bitmap/ebx: int = *letter-bitmap
     53       53/push-ebx
     54       8b/-> *esi 3/r32/ebx
     55       {
     56         # if (xcurr < xmin) break
     57         39/compare %eax 1/r32/ecx
     58         7c/jump-if-< break/disp8
     59         # shift LSB from row-bitmap into carry flag (CF)
     60         c1 5/subop/shift-right-logical %ebx 1/imm8
     61         # if LSB, draw a pixel in the given color
     62         {
     63           73/jump-if-not-CF break/disp8
     64           (pixel-on-real-screen %eax %edx *(ebp+0x14))
     65           eb/jump $draw-grapheme-on-real-screen:continue/disp8
     66         }
     67         # otherwise use the background color
     68         (pixel-on-real-screen %eax %edx *(ebp+0x18))
     69 $draw-grapheme-on-real-screen:continue:
     70         # --x
     71         48/decrement-eax
     72         #
     73         eb/jump loop/disp8
     74       }
     75       # reclaim row-bitmap
     76       5b/pop-to-ebx
     77       # ++y
     78       42/increment-edx
     79       # next bitmap row
     80       46/increment-esi
     81       #
     82       eb/jump loop/disp8
     83     }
     84 $draw-grapheme-on-real-screen:end:
     85     # . restore registers
     86     5e/pop-to-esi
     87     5b/pop-to-ebx
     88     5a/pop-to-edx
     89     59/pop-to-ecx
     90     58/pop-to-eax
     91     # . epilogue
     92     89/<- %esp 5/r32/ebp
     93     5d/pop-to-ebp
     94     c3/return
     95
     96 cursor-position-on-real-screen:  # -> _/eax: int, _/ecx: int
     97     # . prologue
     98     55/push-ebp
     99     89/<- %ebp 4/r32/esp
    100     # TODO: support fake screen; we currently assume 'screen' is always 0 (real)
    101     8b/-> *Real-screen-cursor-x 0/r32/eax
    102     8b/-> *Real-screen-cursor-y 1/r32/ecx
    103 $cursor-position-on-real-screen:end:
    104     # . epilogue
    105     89/<- %esp 5/r32/ebp
    106     5d/pop-to-ebp
    107     c3/return
    108
    109 set-cursor-position-on-real-screen:  # x: int, y: int
    110     # . prologue
    111     55/push-ebp
    112     89/<- %ebp 4/r32/esp
    113     # . save registers
    114     50/push-eax
    115     #
    116     8b/-> *(ebp+8) 0/r32/eax
    117     89/<- *Real-screen-cursor-x 0/r32/eax
    118     8b/-> *(ebp+0xc) 0/r32/eax
    119     89/<- *Real-screen-cursor-y 0/r32/eax
    120 $set-cursor-position-on-real-screen:end:
    121     # . restore registers
    122     58/pop-to-eax
    123     # . epilogue
    124     89/<- %esp 5/r32/ebp
    125     5d/pop-to-ebp
    126     c3/return
    127
    128 # Not a real `show-cursor` primitive:
    129 #   - does not clear previous location cursor was shown at.
    130 #   - does not preserve what was at the cursor. Caller is responsible for
    131 #     tracking what was on the screen at this position before and passing it
    132 #     in again.
    133 #   - does not stop showing the cursor at this location when the cursor moves
    134 draw-cursor-on-real-screen:  # g: grapheme
    135     # . prologue
    136     55/push-ebp
    137     89/<- %ebp 4/r32/esp
    138     # . save registers
    139     50/push-eax
    140     51/push-ecx
    141     #
    142     (cursor-position-on-real-screen)  # => eax, ecx
    143     (draw-grapheme-on-real-screen *(ebp+8) %eax %ecx 0 7)
    144 $draw-cursor-on-real-screen:end:
    145     # . restore registers
    146     59/pop-to-ecx
    147     58/pop-to-eax
    148     # . epilogue
    149     89/<- %esp 5/r32/ebp
    150     5d/pop-to-ebp
    151     c3/return
    152
    153 == data
    154
    155 # The cursor is where certain Mu functions (usually of the form
    156 # 'draw*cursor*') print to by default.
    157 #
    158 # We don't bother displaying the cursor when drawing. It only becomes visible
    159 # on draw-cursor, which is quite rickety (see above)
    160 #
    161 # It's up to applications to manage cursor display:
    162 #   - clean up where it used to be
    163 #   - display the cursor before waiting for a key
    164 #   - ensure its location appropriately suggests the effect keystrokes will have
    165 #   - ensure its contents (and colors) appropriately reflect the state of the
    166 #     screen
    167 #
    168 # There's no blinking, etc. We aren't using any hardware-supported text mode
    169 # here.
    170 Real-screen-cursor-x:
    171   0/imm32
    172 Real-screen-cursor-y:
    173   0/imm32