about summary refs log blame commit diff stats
path: root/103grapheme.subx
blob: abcfe57c213bca8a2ef3fd8e108697155f6bf45a (plain) (tree)
1
2
3
4
5
6
7
8
9
10


                                                                             
                                  


       


                                                          

                                                                          
                                                                                                        


                        
     
                                                                                                                                   





                                  
                                                                                                                                                                                     



                        




















                                                                     
                                                                                                                                      



                                   










                                                                                                               
                                                                         

                                                                                                                                                                           


                        
                      
               


                                                                        
             
                              


                                                                                                                                                                                               
                                                               
                                     
                                                    
                                                              


                                           
                                 



























                                                                                                                                   
                                                        

















                                                                                                                                                                                   


               
               

                              
                               
                               
                                     



                                     
     
                                
                               
                                   
                                                 

                             
                                                                                                                    




                       
                         
     

                                           
                 


                 
















                                                                                                                                                                                 
































                                                                                                             
                                         
                         
                 








                        
 















































                                                                                                                                                                 
                                                            



                                                                                

                                         
                                    




                        
                                                     




                        
     
                            
                                         
                              
                                         
                                        






                         
                                     



                                                                            
                                                                             
                                          







                                                   
                                                                   
                                







                         

       
                                                               


                                                                             
                                                    






                                                                                
 

                                                                            
                     
         
                     
         
# 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 the font).

== 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 -> _/eax
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    (draw-grapheme-on-screen-buffer *Video-memory-addr *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) 0x80 0x30)  # => eax
$draw-grapheme-on-real-screen:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

draw-grapheme-on-screen-array:  # screen-data: (addr array byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    # if screen-width*screen-height > len(screen-data) abort
    {
      # ecx = len(screen-data)
      8b/-> *(ebp+8) 1/r32/ecx
      8b/-> *ecx 1/r32/ecx
      # eax = screen-width*screen-height
      ba/copy-to-edx 0/imm32
      8b/-> *(ebp+0x20) 0/r32/eax
      f7 4/subop/multiply-into-eax *(ebp+0x24)
      81 7/subop/compare %edx 0/imm32
      0f 85/jump-if-!= $draw-grapheme-on-screen-array:overflow/disp32
      # if (eax > ecx) abort
      39/compare %eax 1/r32/ecx
      0f 8f/jump-if-> $draw-grapheme-on-screen-array:abort/disp32
    }
    # eax = screen-data+4   (skip length)
    8b/-> *(ebp+8) 0/r32/eax
    05/add-to-eax 4/imm32
    #
    (draw-grapheme-on-screen-buffer %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))  # => eax
$draw-grapheme-on-screen-array:end:
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$draw-grapheme-on-screen-array:overflow:
    (abort "draw-grapheme-on-screen-array: screen dimensions too large")

$draw-grapheme-on-screen-array:abort:
    (abort "draw-grapheme-on-screen-array: coordinates are off the screen. Are the screen dimensions correct?")

# 'buffer' here is not a valid Mu type: a naked address without a length.
# returns number of 8x16 units printed to screen (1 or 2).
draw-grapheme-on-screen-buffer:  # buffer: (addr byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    56/push-esi
    # switch screen-width and screen-height from grapheme to pixel units
    c1 4/subop/shift-left *(ebp+20) 3/imm8/log2-font-width
    c1 4/subop/shift-left *(ebp+24) 4/imm8/log2-font-height
    # esi = g
    8b/-> *(ebp+0xc) 6/r32/esi
    # if (g >= 4352) return  # unicode planes supported: latin, greek, cyrillic, armenian, hebrew, arabic, syriac, thaana, n'ko, indian (iscii), sinhala, thai, lao, tibetan, myanmar, georgian
                             # next few to support: CJK, ethiopic, cherokee, ...
    81 7/subop/compare %esi 0x1100/imm32
    0f 8d/jump-if->= $draw-grapheme-on-screen-buffer:end/disp32
    # var letter-bitmap/esi = font[g]
    69/multiply %esi 0x21/imm32/glyph-size 6/r32/esi
    81 0/subop/add %esi 0x0010000c/imm32/Font  # see boot.subx
    # dispatch based on letter-bitmap->size
    b8/copy-to-eax 0/imm32
    8a/byte-> *esi 0/r32/AL
    46/increment-esi  # skip size
    3d/compare-eax-and 8/imm32
    {
      75/jump-if-!= break/disp8
      (draw-narrow-grapheme-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
      b8/copy-to-eax 1/imm32
      eb/jump $draw-grapheme-on-screen-buffer:end/disp8
    }
    (draw-wide-grapheme-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
    b8/copy-to-eax 2/imm32
$draw-grapheme-on-screen-buffer:end:
    # . restore registers
    5e/pop-to-esi
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

wide-grapheme?:  # g: grapheme -> _/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # eax = g
    8b/-> *(ebp+8) 0/r32/eax
    # if (g >= 128) return  # characters beyond ASCII currently not supported
    3d/compare-eax-and 0x80/imm32
    0f 8d/jump-if->= $wide-grapheme?:end/disp32
    # var letter-bitmap/eax = font[g]
    69/multiply %eax 0x21/imm32/glyph-size 0/r32/eax
    05/add-to-eax 0x0010000c/imm32/Font  # see boot.subx
    # dispatch based on letter-bitmap->size
    8a/byte-> *eax 0/r32/AL
    25/and-eax-with  0xff/imm32
    3d/compare-eax-and 8/imm32
    0f 95/set-if-!= %eax
$wide-grapheme?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# buffer: naked address to raw screen RAM without a length
# letter-bitmap: naked address to 8-pixel wide font glyph
draw-narrow-grapheme-on-screen-buffer:  # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # esi = letter-bitmap
    8b/-> *(ebp+0xc) 6/r32/esi
    # var ycurr/edx: int = y*16
    8b/-> *(ebp+0x14) 2/r32/edx
    c1 4/subop/shift-left %edx 4/imm8
    # var ymax/edi: int = ycurr + 16
    8b/-> *(ebp+0x14) 7/r32/edi
    c1 4/subop/shift-left %edi 4/imm8
    81 0/subop/add %edi 0x10/imm32
    {
      # if (ycurr >= ymax) break
      39/compare %edx 7/r32/edi
      0f 8d/jump-if->= break/disp32
      # var row-bitmap/ebx: byte = *letter-bitmap
      bb/copy-to-ebx 0/imm32
      8a/byte-> *esi 3/r32/BL
      (draw-run-of-pixels-from-glyph *(ebp+8) %ebx *(ebp+0x10) %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
      # ++y
      42/increment-edx
      # next bitmap row
      46/increment-esi
      #
      e9/jump loop/disp32
    }
$draw-narrow-grapheme-on-screen-buffer:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# buffer: naked address to raw screen RAM without a length
# letter-bitmap: naked address to 16-pixel wide font glyph
draw-wide-grapheme-on-screen-buffer:  # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: 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
    57/push-edi
    # esi = letter-bitmap
    8b/-> *(ebp+0xc) 6/r32/esi
    #
    bb/copy-to-ebx 0/imm32
    # var ycurr/edx: int = y*16
    8b/-> *(ebp+0x14) 2/r32/edx
    c1 4/subop/shift-left %edx 4/imm8
    # var ymax/edi: int = ycurr + 16
    8b/-> *(ebp+0x14) 7/r32/edi
    c1 4/subop/shift-left %edi 4/imm8
    81 0/subop/add %edi 0x10/imm32
    {
      # if (ycurr >= ymax) break
      39/compare %edx 7/r32/edi
      0f 8d/jump-if->= break/disp32
      # var row-bitmap/ebx: byte = *letter-bitmap
      8a/byte-> *(esi+1) 3/r32/BL
      # ecx = x
      8b/-> *(ebp+0x10) 1/r32/ecx
      # first half-row
      (draw-run-of-pixels-from-glyph *(ebp+8) %ebx %ecx %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
      # second half-row
      8a/byte-> *esi 3/r32/BL
      49/increment-ecx
      (draw-run-of-pixels-from-glyph *(ebp+8) %ebx %ecx %edx *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
      # ++y
      42/increment-edx
      # next bitmap row
      81 0/subop/add %esi 2/imm32
      #
      e9/jump loop/disp32
    }
$draw-wide-grapheme-on-screen-buffer: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/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# draw 8 pixels from a single glyph byte in a font bitmap
draw-run-of-pixels-from-glyph:  # buffer: (addr byte), glyph-byte: byte, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # esi = glyph-byte
    8b/-> *(ebp+0xc) 6/r32/esi
    # var xcurr/eax: int = x*8 + 7
    8b/-> *(ebp+0x10) 0/r32/eax
    c1 4/subop/shift-left %eax 3/imm8
    05/add-to-eax 7/imm32
    # var xmin/ecx: int = x*8
    8b/-> *(ebp+0x10) 1/r32/ecx
    c1 4/subop/shift-left %ecx 3/imm8
    {
      # 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 %esi 1/imm8
      # if LSB, draw a pixel in the given color
      {
        73/jump-if-not-CF break/disp8
        (pixel-on-screen-buffer *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18) *(ebp+0x20) *(ebp+0x24))
        eb/jump $draw-grapheme-on-screen-buffer:continue/disp8
      }
      # otherwise use the background color
      (pixel-on-screen-buffer *(ebp+8) %eax *(ebp+0x14) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
$draw-grapheme-on-screen-buffer:continue:
      # --x
      48/decrement-eax
      #
      eb/jump loop/disp8
    }
$draw-run-of-pixels-from-glyph:end:
    # . restore registers
    5e/pop-to-esi
    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

# Not a real `show-cursor` primitive:
#   - 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
draw-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)  # => eax
$draw-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 draw-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