1 # Use the built-in font to draw glyphs to screen.
2 # https://en.wikipedia.org/wiki/Glyph#Typography
3 # Extremely hacky support for combining characters.
4 # https://en.wikipedia.org/wiki/Code_point
5 # https://en.wikipedia.org/wiki/Combining_character
6 # All we support is drawing combining characters atop the same screen cell as
7 # a single base code point. See the overlay? arguments below.
9 # We need to do this in machine code because Mu doesn't have global variables
10 # yet (for the start of the font).
14 # The Mu computer's screen is 1024px wide and 768px tall.
15 # The Mu computer's font is 8px wide and 16px tall.
16 # Therefore 'x' here is in [0, 128), and 'y' is in [0, 48)
17 # Doesn't update the cursor; where the cursor should go after printing the
18 # current code-point is a higher-level concern.
19 draw-code-point-on-real-screen: # c: code-point, x: int, y: int, color: int, background-color: int -> _/eax
24 (draw-code-point-on-screen-buffer *Video-memory-addr *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) 0 0x80 0x30) # 0/no-overlay => eax
25 $draw-code-point-on-real-screen:end:
31 overlay-code-point-on-real-screen: # c: code-point, x: int, y: int, color: int, background-color: int -> _/eax
36 (draw-code-point-on-screen-buffer *Video-memory-addr *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) 1 0x80 0x30) # 1/overlay => eax
37 $overlay-code-point-on-real-screen:end:
43 draw-code-point-on-screen-array: # screen-data: (addr array byte), c: code-point, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
50 # if screen-width*screen-height > len(screen-data) abort
52 # ecx = len(screen-data)
53 8b/-> *(ebp+8) 1/r32/ecx
55 # eax = screen-width*screen-height
56 ba/copy-to-edx 0/imm32
57 8b/-> *(ebp+0x20) 0/r32/eax
58 f7 4/subop/multiply-into-eax *(ebp+0x24)
59 81 7/subop/compare %edx 0/imm32
60 0f 85/jump-if-!= $draw-code-point-on-screen-array:overflow/disp32
61 # if (eax > ecx) abort
62 39/compare %eax 1/r32/ecx
63 0f 8f/jump-if-> $draw-code-point-on-screen-array:abort/disp32
65 # eax = screen-data+4 (skip length)
66 8b/-> *(ebp+8) 0/r32/eax
69 (draw-code-point-on-screen-buffer %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) 1 *(ebp+0x20) *(ebp+0x24)) # => eax
70 $draw-code-point-on-screen-array:end:
79 $draw-code-point-on-screen-array:overflow:
80 (abort "draw-code-point-on-screen-array: screen dimensions too large")
82 $draw-code-point-on-screen-array:abort:
83 (abort "draw-code-point-on-screen-array: coordinates are off the screen. Are the screen dimensions correct?")
85 # 'buffer' here is not a valid Mu type: a naked address without a length.
86 # returns number of 8x16 units printed to screen (1 or 2).
87 draw-code-point-on-screen-buffer: # buffer: (addr byte), c: code-point, x: int, y: int, color: int, background-color: int, overlay?: boolean, screen-width: int, screen-height: int -> _/eax: int
93 # switch screen-width and screen-height from code-point to pixel units
94 c1 4/subop/shift-left *(ebp+24) 3/imm8/log2-font-width
95 c1 4/subop/shift-left *(ebp+28) 4/imm8/log2-font-height
97 8b/-> *(ebp+0xc) 6/r32/esi
98 # if (c >= 4352) return # unicode planes supported: latin, greek, cyrillic, armenian, hebrew, arabic, syriac, thaana, n'ko, indian (iscii), sinhala, thai, lao, tibetan, myanmar, georgian
99 # next few to support: CJK, ethiopic, cherokee, ...
100 81 7/subop/compare %esi 0x1100/imm32/4352
101 0f 8d/jump-if->= $draw-code-point-on-screen-buffer:end/disp32
102 # var letter-bitmap/esi = font[c]
103 69/multiply %esi 0x22/imm32/glyph-size 6/r32/esi
104 81 0/subop/add %esi 0x0010000c/imm32/Font # see boot.subx
105 # dispatch based on letter-bitmap->size
106 b8/copy-to-eax 0/imm32
107 8a/byte-> *esi 0/r32/AL
108 46/increment-esi # skip size
109 46/increment-esi # skip size
110 3d/compare-eax-and 8/imm32
112 75/jump-if-!= break/disp8
113 (draw-narrow-code-point-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24) *(ebp+0x28))
114 b8/copy-to-eax 1/imm32
115 eb/jump $draw-code-point-on-screen-buffer:end/disp8
117 (draw-wide-code-point-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24) *(ebp+0x28))
118 b8/copy-to-eax 2/imm32
119 $draw-code-point-on-screen-buffer:end:
120 # . restore registers
127 wide-code-point?: # c: code-point -> _/eax: boolean
132 8b/-> *(ebp+8) 0/r32/eax
133 # if (c >= 4352) return false
134 3d/compare-eax-and 0x1100/imm32
135 0f 8d/jump-if->= $wide-code-point?:return-false/disp32
136 # var letter-bitmap/eax = font[c]
137 69/multiply %eax 0x22/imm32/glyph-size 0/r32/eax
138 05/add-to-eax 0x0010000c/imm32/Font # see boot.subx
139 # dispatch based on letter-bitmap->size
140 8a/byte-> *eax 0/r32/AL
141 25/and-eax-with 0xff/imm32
142 3d/compare-eax-and 8/imm32
144 $wide-code-point?:end:
150 $wide-code-point?:return-false:
151 b8/copy-to-eax 0/imm32/false
157 combining-code-point?: # c: code-point -> _/eax: boolean
162 8b/-> *(ebp+8) 0/r32/eax
163 # if (c >= 4352) return false
164 3d/compare-eax-and 0x1100/imm32
165 0f 8d/jump-if->= $combining-code-point?:return-false/disp32
166 # var letter-bitmap/eax = font[c]
167 69/multiply %eax 0x22/imm32/glyph-size 0/r32/eax
168 05/add-to-eax 0x0010000c/imm32/Font # see boot.subx
169 # dispatch based on letter-bitmap->is-combine?
170 8a/byte-> *(eax+1) 0/r32/AL
171 25/and-eax-with 0xff/imm32
172 $combining-code-point?:end:
178 $combining-code-point?:return-false:
179 b8/copy-to-eax 0/imm32/false
185 # buffer: naked address to raw screen RAM without a length
186 # letter-bitmap: naked address to 8-pixel wide font glyph
187 draw-narrow-code-point-on-screen-buffer: # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, overlay?: boolean, screen-width: int, screen-height: int
196 # esi = letter-bitmap
197 8b/-> *(ebp+0xc) 6/r32/esi
198 # var ycurr/edx: int = y*16
199 8b/-> *(ebp+0x14) 2/r32/edx
200 c1 4/subop/shift-left %edx 4/imm8
201 # var ymax/edi: int = ycurr + 16
202 8b/-> *(ebp+0x14) 7/r32/edi
203 c1 4/subop/shift-left %edi 4/imm8
204 81 0/subop/add %edi 0x10/imm32
206 # if (ycurr >= ymax) break
207 39/compare %edx 7/r32/edi
208 0f 8d/jump-if->= break/disp32
209 # var row-bitmap/ebx: byte = *letter-bitmap
210 bb/copy-to-ebx 0/imm32
211 8a/byte-> *esi 3/r32/BL
212 (draw-run-of-pixels-from-glyph *(ebp+8) %ebx *(ebp+0x10) %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24) *(ebp+0x28))
220 $draw-narrow-code-point-on-screen-buffer:end:
221 # . restore registers
231 # buffer: naked address to raw screen RAM without a length
232 # letter-bitmap: naked address to 16-pixel wide font glyph
233 draw-wide-code-point-on-screen-buffer: # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, overlay?: boolean, screen-width: int, screen-height: int
244 # esi = letter-bitmap
245 8b/-> *(ebp+0xc) 6/r32/esi
247 bb/copy-to-ebx 0/imm32
248 # var ycurr/edx: int = y*16
249 8b/-> *(ebp+0x14) 2/r32/edx
250 c1 4/subop/shift-left %edx 4/imm8
251 # var ymax/edi: int = ycurr + 16
252 8b/-> *(ebp+0x14) 7/r32/edi
253 c1 4/subop/shift-left %edi 4/imm8
254 81 0/subop/add %edi 0x10/imm32
256 # if (ycurr >= ymax) break
257 39/compare %edx 7/r32/edi
258 0f 8d/jump-if->= break/disp32
259 # var row-bitmap/ebx: byte = *letter-bitmap
260 8a/byte-> *esi 3/r32/BL
262 8b/-> *(ebp+0x10) 1/r32/ecx
264 (draw-run-of-pixels-from-glyph *(ebp+8) %ebx %ecx %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24) *(ebp+0x28))
266 8a/byte-> *(esi+1) 3/r32/BL
268 (draw-run-of-pixels-from-glyph *(ebp+8) %ebx %ecx %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24) *(ebp+0x28))
272 81 0/subop/add %esi 2/imm32
276 $draw-wide-code-point-on-screen-buffer:end:
277 # . restore registers
289 # draw 8 pixels from a single glyph byte in a font bitmap
290 draw-run-of-pixels-from-glyph: # buffer: (addr byte), glyph-byte: byte, x: int, y: int, color: int, background-color: int, overlay?: boolean, screen-width: int, screen-height: int
299 8b/-> *(ebp+0xc) 6/r32/esi
300 # var xcurr/eax: int = x*8 + 7
301 8b/-> *(ebp+0x10) 0/r32/eax
302 c1 4/subop/shift-left %eax 3/imm8
303 05/add-to-eax 7/imm32
304 # var xmin/ecx: int = x*8
305 8b/-> *(ebp+0x10) 1/r32/ecx
306 c1 4/subop/shift-left %ecx 3/imm8
308 # if (xcurr < xmin) break
309 39/compare %eax 1/r32/ecx
310 7c/jump-if-< break/disp8
311 # shift LSB from row-bitmap into carry flag (CF)
312 c1 5/subop/shift-right-logical %esi 1/imm8
313 # if LSB, draw a pixel in the given color
315 73/jump-if-not-CF break/disp8
316 (pixel-on-screen-buffer *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18) *(ebp+0x24) *(ebp+0x28))
317 eb/jump $draw-code-point-on-screen-buffer:continue/disp8
319 # otherwise use the background color (except when overlay?)
321 81 7/subop/compare *(ebp+0x20) 0/imm32/false
322 75/jump-if-!= break/disp8
323 (pixel-on-screen-buffer *(ebp+8) %eax *(ebp+0x14) *(ebp+0x1c) *(ebp+0x24) *(ebp+0x28))
325 $draw-code-point-on-screen-buffer:continue:
331 $draw-run-of-pixels-from-glyph:end:
332 # . restore registers
341 cursor-position-on-real-screen: # -> _/eax: int, _/ecx: int
345 # TODO: support fake screen; we currently assume 'screen' is always 0 (real)
346 8b/-> *Real-screen-cursor-x 0/r32/eax
347 8b/-> *Real-screen-cursor-y 1/r32/ecx
348 $cursor-position-on-real-screen:end:
354 set-cursor-position-on-real-screen: # x: int, y: int
361 8b/-> *(ebp+8) 0/r32/eax
362 89/<- *Real-screen-cursor-x 0/r32/eax
363 8b/-> *(ebp+0xc) 0/r32/eax
364 89/<- *Real-screen-cursor-y 0/r32/eax
365 $set-cursor-position-on-real-screen:end:
366 # . restore registers
373 # Not a real `show-cursor` primitive:
374 # - does not clear previous location cursor was shown at.
375 # - does not preserve what was at the cursor. Caller is responsible for
376 # tracking what was on the screen at this position before and passing it
378 # - does not stop showing the cursor at this location when the cursor moves
379 draw-cursor-on-real-screen: # c: code-point
387 (cursor-position-on-real-screen) # => eax, ecx
388 (draw-code-point-on-real-screen *(ebp+8) %eax %ecx 0 7) # => eax
389 $draw-cursor-on-real-screen:end:
390 # . restore registers
400 # The cursor is where certain Mu functions (usually of the form
401 # 'draw*cursor*') print to by default.
403 # We don't bother displaying the cursor when drawing. It only becomes visible
404 # on draw-cursor, which is quite rickety (see above)
406 # It's up to applications to manage cursor display:
407 # - clean up where it used to be
408 # - display the cursor before waiting for a key
409 # - ensure its location appropriately suggests the effect keystrokes will have
410 # - ensure its contents (and colors) appropriately reflect the state of the
413 # There's no blinking, etc. We aren't using any hardware-supported text mode
415 Real-screen-cursor-x:
417 Real-screen-cursor-y: