diff --git a/html/baremetal/101screen.subx.html b/html/baremetal/101screen.subx.html index df52a5b8..038e8f78 100644 --- a/html/baremetal/101screen.subx.html +++ b/html/baremetal/101screen.subx.html @@ -15,8 +15,8 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.LineNr { } .subxS1Comment { color: #0000af; } +.LineNr { } .subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } --> diff --git a/html/baremetal/102keyboard.subx.html b/html/baremetal/102keyboard.subx.html index f841e696..cc092133 100644 --- a/html/baremetal/102keyboard.subx.html +++ b/html/baremetal/102keyboard.subx.html @@ -15,8 +15,8 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.LineNr { } .subxS1Comment { color: #0000af; } +.LineNr { } .subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } --> diff --git a/html/baremetal/103grapheme.subx.html b/html/baremetal/103grapheme.subx.html index b34168d6..13dc6073 100644 --- a/html/baremetal/103grapheme.subx.html +++ b/html/baremetal/103grapheme.subx.html @@ -14,9 +14,10 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } +.SpecialChar { color: #d70000; } .subxComment { color: #005faf; } -.LineNr { } .subxS1Comment { color: #0000af; } +.LineNr { } .subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } --> @@ -54,76 +55,117 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/main/baremetal/103grapheme.subx
- 1 draw-grapheme:  # screen: (addr screen), g: grapheme, x: int, y: int, color: int
- 2     # . prologue
- 3     55/push-ebp
- 4     89/<- %ebp 4/r32/esp
- 5     # . save registers
- 6     50/push-eax
- 7     51/push-ecx
- 8     52/push-edx
- 9     53/push-ebx
-10     56/push-esi
-11     # var letter-bitmap/esi = font[g]
-12     8b/-> *(ebp+0xc) 6/r32/esi
-13     c1 4/subop/shift-left %esi 4/imm8
-14     8d/copy-address *(esi+0x8800) 6/r32/esi  # font-start
-15     # if (letter-bitmap >= 0x9000) return  # characters beyond ASCII currently not supported
-16     81 7/subop/compare %esi 0x9000/imm32
-17     7d/jump-if->= $draw-grapheme:end/disp8
-18     # edx = y
-19     8b/-> *(ebp+0x14) 2/r32/edx
-20     # var ymax/ebx: int = y + 16
-21     8b/-> *(ebp+0x14) 3/r32/ebx
-22     81 0/subop/add %ebx 0x10/imm32
-23     {
-24       # if (y >= ymax) break
-25       39/compare %edx 3/r32/ebx
-26       7d/jump-if->= break/disp8
-27       # eax = x + 7
-28       8b/-> *(ebp+0x10) 0/r32/eax
-29       81 0/subop/add %eax 7/imm32
-30       # var xmin/ecx: int = x
-31       8b/-> *(ebp+0x10) 1/r32/ecx
-32       # var row-bitmap/ebx: int = *letter-bitmap
-33       53/push-ebx
-34       8b/-> *esi 3/r32/ebx
-35       {
-36         # if (x < xmin) break
-37         39/compare %eax 1/r32/ecx
-38         7c/jump-if-< break/disp8
-39         # shift LSB from row-bitmap into carry flag (CF)
-40         c1 5/subop/shift-right-logical %ebx 1/imm8
-41         # if LSB, draw a pixel
-42         {
-43           73/jump-if-not-CF break/disp8
-44           (pixel *(ebp+8) %eax %edx *(ebp+0x18))
-45         }
-46         # --x
-47         48/decrement-eax
-48         #
-49         eb/jump loop/disp8
-50       }
-51       # reclaim row-bitmap
-52       5b/pop-to-ebx
-53       # ++y
-54       42/increment-edx
-55       # next bitmap row
-56       46/increment-esi
-57       #
-58       eb/jump loop/disp8
-59     }
-60 $draw-grapheme:end:
-61     # . restore registers
-62     5e/pop-to-esi
-63     5b/pop-to-ebx
-64     5a/pop-to-edx
-65     59/pop-to-ecx
-66     58/pop-to-eax
-67     # . epilogue
-68     89/<- %esp 5/r32/ebp
-69     5d/pop-to-ebp
-70     c3/return
+  1 draw-grapheme:  # screen: (addr screen), g: grapheme, x: int, y: int, color: int
+  2     # . prologue
+  3     55/push-ebp
+  4     89/<- %ebp 4/r32/esp
+  5     # . save registers
+  6     50/push-eax
+  7     51/push-ecx
+  8     52/push-edx
+  9     53/push-ebx
+ 10     56/push-esi
+ 11     # TODO: support fake screen; we currently assume 'screen' is always 0 (real)
+ 12     # var letter-bitmap/esi = font[g]
+ 13     8b/-> *(ebp+0xc) 6/r32/esi
+ 14     c1 4/subop/shift-left %esi 4/imm8
+ 15     8d/copy-address *(esi+0x8800) 6/r32/esi  # font-start
+ 16     # if (letter-bitmap >= 0x9000) return  # characters beyond ASCII currently not supported
+ 17     81 7/subop/compare %esi 0x9000/imm32
+ 18     7d/jump-if->= $draw-grapheme:end/disp8
+ 19     # edx = y
+ 20     8b/-> *(ebp+0x14) 2/r32/edx
+ 21     # var ymax/ebx: int = y + 16
+ 22     8b/-> *(ebp+0x14) 3/r32/ebx
+ 23     81 0/subop/add %ebx 0x10/imm32
+ 24     {
+ 25       # if (y >= ymax) break
+ 26       39/compare %edx 3/r32/ebx
+ 27       7d/jump-if->= break/disp8
+ 28       # eax = x + 7
+ 29       8b/-> *(ebp+0x10) 0/r32/eax
+ 30       81 0/subop/add %eax 7/imm32
+ 31       # var xmin/ecx: int = x
+ 32       8b/-> *(ebp+0x10) 1/r32/ecx
+ 33       # var row-bitmap/ebx: int = *letter-bitmap
+ 34       53/push-ebx
+ 35       8b/-> *esi 3/r32/ebx
+ 36       {
+ 37         # if (x < xmin) break
+ 38         39/compare %eax 1/r32/ecx
+ 39         7c/jump-if-< break/disp8
+ 40         # shift LSB from row-bitmap into carry flag (CF)
+ 41         c1 5/subop/shift-right-logical %ebx 1/imm8
+ 42         # if LSB, draw a pixel
+ 43         {
+ 44           73/jump-if-not-CF break/disp8
+ 45           (pixel *(ebp+8) %eax %edx *(ebp+0x18))
+ 46         }
+ 47         # --x
+ 48         48/decrement-eax
+ 49         #
+ 50         eb/jump loop/disp8
+ 51       }
+ 52       # reclaim row-bitmap
+ 53       5b/pop-to-ebx
+ 54       # ++y
+ 55       42/increment-edx
+ 56       # next bitmap row
+ 57       46/increment-esi
+ 58       #
+ 59       eb/jump loop/disp8
+ 60     }
+ 61 $draw-grapheme:end:
+ 62     # . restore registers
+ 63     5e/pop-to-esi
+ 64     5b/pop-to-ebx
+ 65     5a/pop-to-edx
+ 66     59/pop-to-ecx
+ 67     58/pop-to-eax
+ 68     # . epilogue
+ 69     89/<- %esp 5/r32/ebp
+ 70     5d/pop-to-ebp
+ 71     c3/return
+ 72 
+ 73 cursor-position:  # screen: (addr screen) -> _/eax: int, _/ecx: int
+ 74     # . prologue
+ 75     55/push-ebp
+ 76     89/<- %ebp 4/r32/esp
+ 77     # TODO: support fake screen; we currently assume 'screen' is always 0 (real)
+ 78     8b/-> *Default-next-x 0/r32/eax
+ 79     8b/-> *Default-next-y 1/r32/ecx
+ 80 $cursor-position:end:
+ 81     # . epilogue
+ 82     89/<- %esp 5/r32/ebp
+ 83     5d/pop-to-ebp
+ 84     c3/return
+ 85 
+ 86 set-cursor-position:  # screen: (addr screen), x: int, y: int
+ 87     # . prologue
+ 88     55/push-ebp
+ 89     89/<- %ebp 4/r32/esp
+ 90     # . save registers
+ 91     50/push-eax
+ 92     # TODO: support fake screen; we currently assume 'screen' is always 0 (real)
+ 93     8b/-> *(ebp+0xc) 0/r32/eax
+ 94     89/<- *Default-next-x 0/r32/eax
+ 95     8b/-> *(ebp+0x10) 0/r32/eax
+ 96     89/<- *Default-next-y 0/r32/eax
+ 97 $set-cursor-position:end:
+ 98     # . restore registers
+ 99     58/pop-to-eax
+100     # . epilogue
+101     89/<- %esp 5/r32/ebp
+102     5d/pop-to-ebp
+103     c3/return
+104 
+105 == data
+106 
+107 Default-next-x:
+108   0/imm32
+109 
+110 Default-next-y:
+111   0/imm32
 
diff --git a/html/baremetal/106stream.subx.html b/html/baremetal/106stream.subx.html new file mode 100644 index 00000000..cbd859ea --- /dev/null +++ b/html/baremetal/106stream.subx.html @@ -0,0 +1,137 @@ + + + + +Mu - baremetal/106stream.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/baremetal/106stream.subx +
+ 1 # streams: data structure for operating on arrays in a stateful manner
+ 2 #
+ 3 # A stream looks like this:
+ 4 #   write: int  # index at which writes go
+ 5 #   read: int  # index that we've read until
+ 6 #   data: (array byte)  # prefixed by size as usual
+ 7 #
+ 8 # some primitives for operating on streams:
+ 9 #   - clear-stream (clears everything but the data size)
+10 #   - rewind-stream (resets read pointer)
+11 
+12 == code
+13 #   instruction                     effective address                                                   register    displacement    immediate
+14 # . op          subop               mod             rm32          base        index         scale       r32
+15 # . 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
+16 
+17 clear-stream:  # f: (addr stream byte)
+18     # . prologue
+19     55/push-ebp
+20     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+21     # . save registers
+22     50/push-eax
+23     51/push-ecx
+24     # eax = f
+25     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+26     # var count/ecx: int = f->size
+27     8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(eax+8) to ecx
+28     # var max/ecx: (addr byte) = &f->data[f->size]
+29     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
+30     # f->write = 0
+31     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
+32     # f->read = 0
+33     c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         0/imm32           # copy to *(eax+4)
+34     # - clear all stream data
+35     # - this isn't strictly necessary, and it can slow things down *a lot*, but better safe than sorry.
+36     # var curr/eax: (addr byte) = f->data
+37     81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               0xc/imm32         # add to eax
+38 $clear-stream:loop:
+39     # if (curr >= max) break
+40     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
+41     73/jump-if-addr>=  $clear-stream:end/disp8
+42     # *curr = 0
+43     c6          0/subop/copy-byte   0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm8            # copy byte to *eax
+44     # ++curr
+45     40/increment-eax
+46     eb/jump  $clear-stream:loop/disp8
+47 $clear-stream:end:
+48     # . restore registers
+49     59/pop-to-ecx
+50     58/pop-to-eax
+51     # . epilogue
+52     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+53     5d/pop-to-ebp
+54     c3/return
+55 
+56 rewind-stream:  # f: (addr stream byte)
+57     # . prologue
+58     55/push-ebp
+59     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+60     # . save registers
+61     50/push-eax
+62     # eax = f
+63     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+64     # f->read = 0
+65     c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         0/imm32           # copy to *(eax+4)
+66 $rewind-stream:end:
+67     # . restore registers
+68     58/pop-to-eax
+69     # . epilogue
+70     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+71     5d/pop-to-ebp
+72     c3/return
+73 
+74 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/baremetal/108write.subx.html b/html/baremetal/108write.subx.html index 085efeff..608ddb82 100644 --- a/html/baremetal/108write.subx.html +++ b/html/baremetal/108write.subx.html @@ -18,10 +18,10 @@ a { color:inherit; } .subxS1Comment { color: #0000af; } .subxS2Comment { color: #8a8a8a; } .LineNr { } -.subxFunction { color: #af5f00; text-decoration: underline; } -.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } .Constant { color: #008787; } .subxMinorFunction { color: #875f5f; } +.subxFunction { color: #af5f00; text-decoration: underline; } +.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } --> diff --git a/html/baremetal/112read-byte.subx.html b/html/baremetal/112read-byte.subx.html index 9fb89fd0..06271ee0 100644 --- a/html/baremetal/112read-byte.subx.html +++ b/html/baremetal/112read-byte.subx.html @@ -18,9 +18,9 @@ a { color:inherit; } .subxS1Comment { color: #0000af; } .subxS2Comment { color: #8a8a8a; } .LineNr { } +.Constant { color: #008787; } .subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.Constant { color: #008787; } --> diff --git a/html/baremetal/115write-byte.subx.html b/html/baremetal/115write-byte.subx.html index 43cbc843..7bcd8a8a 100644 --- a/html/baremetal/115write-byte.subx.html +++ b/html/baremetal/115write-byte.subx.html @@ -18,9 +18,9 @@ a { color:inherit; } .subxS1Comment { color: #0000af; } .subxS2Comment { color: #8a8a8a; } .LineNr { } +.Constant { color: #008787; } .subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.Constant { color: #008787; } --> diff --git a/html/baremetal/120allocate.subx.html b/html/baremetal/120allocate.subx.html index e11f9b00..11c874ee 100644 --- a/html/baremetal/120allocate.subx.html +++ b/html/baremetal/120allocate.subx.html @@ -18,9 +18,9 @@ a { color:inherit; } .subxS1Comment { color: #0000af; } .subxS2Comment { color: #8a8a8a; } .LineNr { } +.Constant { color: #008787; } .subxFunction { color: #af5f00; text-decoration: underline; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.Constant { color: #008787; } --> diff --git a/html/baremetal/302stack_allocate.subx.html b/html/baremetal/302stack_allocate.subx.html index 73e18ff6..0cbbf443 100644 --- a/html/baremetal/302stack_allocate.subx.html +++ b/html/baremetal/302stack_allocate.subx.html @@ -15,11 +15,11 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.LineNr { } .SpecialChar { color: #d70000; } -.CommentedCode { color: #8a8a8a; } +.LineNr { } .subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } +.CommentedCode { color: #8a8a8a; } --> diff --git a/html/baremetal/309stream.subx.html b/html/baremetal/309stream.subx.html index bbfd368b..16e45ed7 100644 --- a/html/baremetal/309stream.subx.html +++ b/html/baremetal/309stream.subx.html @@ -15,8 +15,8 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.LineNr { } .subxS1Comment { color: #0000af; } +.LineNr { } .subxFunction { color: #af5f00; text-decoration: underline; } .Constant { color: #008787; } --> diff --git a/html/baremetal/313index-bounds-check.subx.html b/html/baremetal/313index-bounds-check.subx.html index e364e785..a6421293 100644 --- a/html/baremetal/313index-bounds-check.subx.html +++ b/html/baremetal/313index-bounds-check.subx.html @@ -15,10 +15,10 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.LineNr { } .subxS1Comment { color: #0000af; } -.subxMinorFunction { color: #875f5f; } +.LineNr { } .Constant { color: #008787; } +.subxMinorFunction { color: #875f5f; } --> diff --git a/html/baremetal/400.mu.html b/html/baremetal/400.mu.html index 715c8d09..95835ad8 100644 --- a/html/baremetal/400.mu.html +++ b/html/baremetal/400.mu.html @@ -14,9 +14,9 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } +.PreProc { color: #c000c0; } .LineNr { } .Constant { color: #008787; } -.PreProc { color: #c000c0; } --> @@ -52,14 +52,17 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/main/baremetal/400.mu
-1 sig pixel screen: (addr screen), x: int, y: int, color: int
-2 sig read-key kbd: (addr keyboard) -> _/eax: byte
-3 sig draw-grapheme screen: (addr screen), g: grapheme, x: int, y: int, color: int
-4 
-5 sig write f: (addr stream byte), s: (addr array byte)
-6 sig append-byte f: (addr stream byte), n: int
-7 sig read-byte s: (addr stream byte) -> _/eax: byte
-8 sig stream-empty? s: (addr stream _) -> _/eax: boolean
+ 1 sig pixel screen: (addr screen), x: int, y: int, color: int
+ 2 sig read-key kbd: (addr keyboard) -> _/eax: byte
+ 3 sig draw-grapheme screen: (addr screen), g: grapheme, x: int, y: int, color: int
+ 4 sig cursor-position screen: (addr screen) -> _/eax: int, _/ecx: int
+ 5 sig set-cursor-position screen: (addr screen), x: int, y: int
+ 6 sig clear-stream f: (addr stream _)
+ 7 sig rewind-stream f: (addr stream _)
+ 8 sig write f: (addr stream byte), s: (addr array byte)
+ 9 sig append-byte f: (addr stream byte), n: int
+10 sig read-byte s: (addr stream byte) -> _/eax: byte
+11 sig stream-empty? s: (addr stream _) -> _/eax: boolean
 
diff --git a/html/baremetal/403unicode.mu.html b/html/baremetal/403unicode.mu.html index 8151f6d4..bff11ca4 100644 --- a/html/baremetal/403unicode.mu.html +++ b/html/baremetal/403unicode.mu.html @@ -14,13 +14,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.muComment { color: #005faf; } +.PreProc { color: #c000c0; } .LineNr { } +.Delimiter { color: #c000c0; } .SpecialChar { color: #d70000; } .Constant { color: #008787; } .muFunction { color: #af5f00; text-decoration: underline; } -.Delimiter { color: #c000c0; } -.PreProc { color: #c000c0; } +.muComment { color: #005faf; } --> @@ -77,7 +77,7 @@ if ('onhashchange' in window) { 19 # 20 # The day we want to support combining characters, this function will need to 21 # take multiple code points. Or something. - 22 fn to-grapheme in: code-point -> _/eax: grapheme { + 22 fn to-grapheme in: code-point -> _/eax: grapheme { 23 var c/eax: int <- copy in 24 var num-trailers/ecx: int <- copy 0 25 var first/edx: int <- copy 0 @@ -147,7 +147,7 @@ if ('onhashchange' in window) { 89 # TODO: bring in tests once we have check-ints-equal 90 91 # read the next grapheme from a stream of bytes - 92 fn read-grapheme in: (addr stream byte) -> _/eax: grapheme { + 92 fn read-grapheme in: (addr stream byte) -> _/eax: grapheme { 93 # if at eof, return EOF 94 { 95 var eof?/eax: boolean <- stream-empty? in @@ -203,7 +203,7 @@ if ('onhashchange' in window) { 145 break-if-<= 146 var tmp/eax: byte <- read-byte in 147 var tmp2/eax: int <- copy tmp -148 tmp2 <- shift-left-bytes tmp2, num-byte-shifts +148 tmp2 <- shift-left-bytes tmp2, num-byte-shifts 149 result <- or tmp2 150 # update loop state 151 num-byte-shifts <- increment @@ -214,7 +214,7 @@ if ('onhashchange' in window) { 156 } 157 158 # needed because available primitives only shift by a literal/constant number of bits -159 fn shift-left-bytes n: int, k: int -> _/eax: int { +159 fn shift-left-bytes n: int, k: int -> _/eax: int { 160 var i/ecx: int <- copy 0 161 var result/eax: int <- copy n 162 { @@ -231,7 +231,7 @@ if ('onhashchange' in window) { 173 174 # write a grapheme to a stream of bytes 175 # this is like write-to-stream, except we skip leading 0 bytes -176 fn write-grapheme out: (addr stream byte), g: grapheme { +176 fn write-grapheme out: (addr stream byte), g: grapheme { 177 $write-grapheme:body: { 178 var c/eax: int <- copy g 179 append-byte out, c # first byte is always written diff --git a/html/baremetal/501draw-text.mu.html b/html/baremetal/501draw-text.mu.html index 61ece7dc..fd1c6df8 100644 --- a/html/baremetal/501draw-text.mu.html +++ b/html/baremetal/501draw-text.mu.html @@ -14,13 +14,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.muComment { color: #005faf; } -.LineNr { } -.SpecialChar { color: #d70000; } -.Delimiter { color: #c000c0; } -.muFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } .PreProc { color: #c000c0; } +.LineNr { } +.Delimiter { color: #c000c0; } +.SpecialChar { color: #d70000; } +.Constant { color: #008787; } +.muFunction { color: #af5f00; text-decoration: underline; } +.muComment { color: #005faf; } --> @@ -56,19 +56,265 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/main/baremetal/501draw-text.mu
- 1 fn draw-text-rightward screen: (addr screen), text: (addr array byte), x: int, y: int, color: int {
- 2   var stream-storage: (stream byte 0x100)
- 3   var stream/esi: (addr stream byte) <- address stream-storage
- 4   write stream, text
- 5   {
- 6     var g/eax: grapheme <- read-grapheme stream
- 7     compare g, 0xffffffff  # end-of-file
- 8     break-if-=
- 9     draw-grapheme screen, g, x, y, color
-10     add-to x, 8  # font-width
-11     loop
-12   }
-13 }
+  1 # draw a single line of text from x, y to xmax
+  2 # return the next 'x' coordinate
+  3 # if there isn't enough space, return 0 without modifying the screen
+  4 fn draw-text-rightward screen: (addr screen), text: (addr array byte), x: int, xmax: int, y: int, color: int -> _/eax: int {
+  5   var stream-storage: (stream byte 0x100)
+  6   var stream/esi: (addr stream byte) <- address stream-storage
+  7   write stream, text
+  8   # check if we have enough space
+  9   var xcurr/ecx: int <- copy x
+ 10   {
+ 11     compare xcurr, xmax
+ 12     break-if->
+ 13     var g/eax: grapheme <- read-grapheme stream
+ 14     compare g, 0xffffffff  # end-of-file
+ 15     break-if-=
+ 16     xcurr <- add 8  # font-width
+ 17     loop
+ 18   }
+ 19   compare xcurr, xmax
+ 20   {
+ 21     break-if-<=
+ 22     return 0
+ 23   }
+ 24   # we do; actually draw
+ 25   rewind-stream stream
+ 26   xcurr <- copy x
+ 27   {
+ 28     var g/eax: grapheme <- read-grapheme stream
+ 29     compare g, 0xffffffff  # end-of-file
+ 30     break-if-=
+ 31     draw-grapheme screen, g, xcurr, y, color
+ 32     xcurr <- add 8  # font-width
+ 33     loop
+ 34   }
+ 35   set-cursor-position screen, xcurr, y
+ 36   return xcurr
+ 37 }
+ 38 
+ 39 fn draw-text-rightward-from-cursor screen: (addr screen), text: (addr array byte), xmax: int, color: int -> _/eax: int {
+ 40   var cursor-x/eax: int <- copy 0
+ 41   var cursor-y/ecx: int <- copy 0
+ 42   cursor-x, cursor-y <- cursor-position screen
+ 43   var result/eax: int <- draw-text-rightward screen, text, cursor-x, xmax, cursor-y, color
+ 44   return result
+ 45 }
+ 46 
+ 47 # draw text in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
+ 48 # return the next (x, y) coordinate in raster order where drawing stopped
+ 49 # that way the caller can draw more if given the same min and max bounding-box.
+ 50 # if there isn't enough space, return 0 without modifying the screen
+ 51 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 -> _/eax: int, _/ecx: int {
+ 52   var stream-storage: (stream byte 0x100)
+ 53   var stream/esi: (addr stream byte) <- address stream-storage
+ 54   write stream, text
+ 55   # check if we have enough space
+ 56   var xcurr/edx: int <- copy x
+ 57   var ycurr/ecx: int <- copy y
+ 58   {
+ 59     compare ycurr, ymax
+ 60     break-if->=
+ 61     var g/eax: grapheme <- read-grapheme stream
+ 62     compare g, 0xffffffff  # end-of-file
+ 63     break-if-=
+ 64     xcurr <- add 8  # font-width
+ 65     compare xcurr, xmax
+ 66     {
+ 67       break-if-<
+ 68       xcurr <- copy xmin
+ 69       ycurr <- add 0x10  # font-height
+ 70     }
+ 71     loop
+ 72   }
+ 73   compare ycurr, ymax
+ 74   {
+ 75     break-if-<
+ 76     return 0, 0
+ 77   }
+ 78   # we do; actually draw
+ 79   rewind-stream stream
+ 80   xcurr <- copy x
+ 81   ycurr <- copy y
+ 82   {
+ 83     var g/eax: grapheme <- read-grapheme stream
+ 84     compare g, 0xffffffff  # end-of-file
+ 85     break-if-=
+ 86     draw-grapheme screen, g, xcurr, ycurr, color
+ 87     xcurr <- add 8  # font-width
+ 88     compare xcurr, xmax
+ 89     {
+ 90       break-if-<
+ 91       xcurr <- copy xmin
+ 92       ycurr <- add 0x10  # font-height
+ 93     }
+ 94     loop
+ 95   }
+ 96   set-cursor-position screen, xcurr, ycurr
+ 97   return xcurr, ycurr
+ 98 }
+ 99 
+100 fn draw-text-wrapping-right-then-down-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int -> _/eax: int, _/ecx: int {
+101   var cursor-x/eax: int <- copy 0
+102   var cursor-y/ecx: int <- copy 0
+103   cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, 0, 0, 0x400, 0x300, x, y, color  # 1024, 768
+104   return cursor-x, cursor-y
+105 }
+106 
+107 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 -> _/eax: int, _/ecx: int {
+108   var cursor-x/eax: int <- copy 0
+109   var cursor-y/ecx: int <- copy 0
+110   cursor-x, cursor-y <- cursor-position screen
+111   var end-x/edx: int <- copy cursor-x
+112   end-x <- add 8  # font-width
+113   compare end-x, xmax
+114   {
+115     break-if-<
+116     cursor-x <- copy xmin
+117     cursor-y <- add 0x10  # font-height
+118   }
+119   cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color
+120   return cursor-x, cursor-y
+121 }
+122 
+123 fn draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int -> _/eax: int, _/ecx: int {
+124   var cursor-x/eax: int <- copy 0
+125   var cursor-y/ecx: int <- copy 0
+126   cursor-x, cursor-y <- draw-text-wrapping-right-then-down-from-cursor screen, text, 0, 0, 0x400, 0x300, color  # 1024, 768
+127   return cursor-x, cursor-y
+128 }
+129 
+130 ## Text direction: down then right
+131 
+132 # draw a single line of text vertically from x, y to ymax
+133 # return the next 'y' coordinate
+134 # if there isn't enough space, return 0 without modifying the screen
+135 fn draw-text-downward screen: (addr screen), text: (addr array byte), x: int, y: int, ymax: int, color: int -> _/eax: int {
+136   var stream-storage: (stream byte 0x100)
+137   var stream/esi: (addr stream byte) <- address stream-storage
+138   write stream, text
+139   # check if we have enough space
+140   var ycurr/ecx: int <- copy y
+141   {
+142     compare ycurr, ymax
+143     break-if->
+144     var g/eax: grapheme <- read-grapheme stream
+145     compare g, 0xffffffff  # end-of-file
+146     break-if-=
+147     ycurr <- add 0x10  # font-height
+148     loop
+149   }
+150   compare ycurr, ymax
+151   {
+152     break-if-<=
+153     return 0
+154   }
+155   # we do; actually draw
+156   rewind-stream stream
+157   ycurr <- copy y
+158   {
+159     var g/eax: grapheme <- read-grapheme stream
+160     compare g, 0xffffffff  # end-of-file
+161     break-if-=
+162     draw-grapheme screen, g, x, ycurr, color
+163     ycurr <- add 0x10  # font-height
+164     loop
+165   }
+166   set-cursor-position screen, x, ycurr
+167   return ycurr
+168 }
+169 
+170 fn draw-text-downward-from-cursor screen: (addr screen), text: (addr array byte), ymax: int, color: int -> _/eax: int {
+171   var cursor-x/eax: int <- copy 0
+172   var cursor-y/ecx: int <- copy 0
+173   cursor-x, cursor-y <- cursor-position screen
+174   var result/eax: int <- draw-text-downward screen, text, cursor-x, cursor-y, ymax, color
+175   return result
+176 }
+177 
+178 # draw text down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
+179 # return the next (x, y) coordinate in raster order where drawing stopped
+180 # that way the caller can draw more if given the same min and max bounding-box.
+181 # if there isn't enough space, return 0 without modifying the screen
+182 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 -> _/eax: int, _/ecx: int {
+183   var stream-storage: (stream byte 0x100)
+184   var stream/esi: (addr stream byte) <- address stream-storage
+185   write stream, text
+186   # check if we have enough space
+187   var xcurr/edx: int <- copy x
+188   var ycurr/ecx: int <- copy y
+189   {
+190     compare xcurr, xmax
+191     break-if->=
+192     var g/eax: grapheme <- read-grapheme stream
+193     compare g, 0xffffffff  # end-of-file
+194     break-if-=
+195     ycurr <- add 0x10  # font-height
+196     compare ycurr, ymax
+197     {
+198       break-if-<
+199       xcurr <- add 8  # font-width
+200       ycurr <- copy ymin
+201     }
+202     loop
+203   }
+204   compare xcurr, xmax
+205   {
+206     break-if-<
+207     return 0, 0
+208   }
+209   # we do; actually draw
+210   rewind-stream stream
+211   xcurr <- copy x
+212   ycurr <- copy y
+213   {
+214     var g/eax: grapheme <- read-grapheme stream
+215     compare g, 0xffffffff  # end-of-file
+216     break-if-=
+217     draw-grapheme screen, g, xcurr, ycurr, color
+218     ycurr <- add 0x10  # font-height
+219     compare ycurr, ymax
+220     {
+221       break-if-<
+222       xcurr <- add 8  # font-width
+223       ycurr <- copy ymin
+224     }
+225     loop
+226   }
+227   set-cursor-position screen, xcurr, ycurr
+228   return xcurr, ycurr
+229 }
+230 
+231 fn draw-text-wrapping-down-then-right-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int -> _/eax: int, _/ecx: int {
+232   var cursor-x/eax: int <- copy 0
+233   var cursor-y/ecx: int <- copy 0
+234   cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, 0, 0, 0x400, 0x300, x, y, color  # 1024, 768
+235   return cursor-x, cursor-y
+236 }
+237 
+238 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 -> _/eax: int, _/ecx: int {
+239   var cursor-x/eax: int <- copy 0
+240   var cursor-y/ecx: int <- copy 0
+241   cursor-x, cursor-y <- cursor-position screen
+242   var end-y/edx: int <- copy cursor-y
+243   end-y <- add 0x10  # font-height
+244   compare end-y, ymax
+245   {
+246     break-if-<
+247     cursor-x <- add 8  # font-width
+248     cursor-y <- copy ymin
+249   }
+250   cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color
+251   return cursor-x, cursor-y
+252 }
+253 
+254 fn draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int -> _/eax: int, _/ecx: int {
+255   var cursor-x/eax: int <- copy 0
+256   var cursor-y/ecx: int <- copy 0
+257   cursor-x, cursor-y <- draw-text-wrapping-down-then-right-from-cursor screen, text, 0, 0, 0x400, 0x300, color  # 1024, 768
+258   return cursor-x, cursor-y
+259 }
 
diff --git a/html/baremetal/502manhattan-line.mu.html b/html/baremetal/502manhattan-line.mu.html new file mode 100644 index 00000000..9d2632d1 --- /dev/null +++ b/html/baremetal/502manhattan-line.mu.html @@ -0,0 +1,89 @@ + + + + +Mu - baremetal/502manhattan-line.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/baremetal/502manhattan-line.mu +
+ 1 fn draw-box screen: (addr screen), x1: int, y1: int, x2: int, y2: int, color: int {
+ 2   draw-horizontal-line screen, x1, x2, y1, color
+ 3   draw-vertical-line screen, x1, y1, y2, color
+ 4   draw-horizontal-line screen, x1, x2, y2, color
+ 5   draw-vertical-line screen, x2, y1, y2, color
+ 6 }
+ 7 
+ 8 fn draw-horizontal-line screen: (addr screen), x1: int, x2: int, y: int, color: int {
+ 9   var x/eax: int <- copy x1
+10   {
+11     compare x, x2
+12     break-if->=
+13     pixel screen, x, y, color
+14     x <- increment
+15     loop
+16   }
+17 }
+18 
+19 fn draw-vertical-line screen: (addr screen), x: int, y1: int, y2: int, color: int {
+20   var y/eax: int <- copy y1
+21   {
+22     compare y, y2
+23     break-if->=
+24     pixel screen, x, y, color
+25     y <- increment
+26     loop
+27   }
+28 }
+
+ + + diff --git a/html/baremetal/boot.hex.html b/html/baremetal/boot.hex.html index 5a3f3f43..610bcbe1 100644 --- a/html/baremetal/boot.hex.html +++ b/html/baremetal/boot.hex.html @@ -15,8 +15,8 @@ body { font-size:12pt; font-family: monospace; color: #000000; background-color: a { color:inherit; } * { font-size:12pt; font-size: 1em; } .subxComment { color: #005faf; } -.LineNr { } .subxS1Comment { color: #0000af; } +.LineNr { } .Folded { color: #080808; background-color: #949494; } --> diff --git a/html/baremetal/boot0.hex.html b/html/baremetal/boot0.hex.html index f619f115..958d5530 100644 --- a/html/baremetal/boot0.hex.html +++ b/html/baremetal/boot0.hex.html @@ -14,9 +14,9 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } +.Todo { color: #000000; background-color: #ffff00; padding-bottom: 1px; } .LineNr { } .Comment { color: #005faf; } -.Todo { color: #000000; background-color: #ffff00; padding-bottom: 1px; } --> diff --git a/html/baremetal/ex2.mu.html b/html/baremetal/ex2.mu.html index 4dd35a7f..e52e4b88 100644 --- a/html/baremetal/ex2.mu.html +++ b/html/baremetal/ex2.mu.html @@ -14,13 +14,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.muComment { color: #005faf; } +.PreProc { color: #c000c0; } .LineNr { } +.Constant { color: #008787; } .SpecialChar { color: #d70000; } .Delimiter { color: #c000c0; } .muFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.PreProc { color: #c000c0; } +.muComment { color: #005faf; } --> @@ -68,7 +68,7 @@ if ('onhashchange' in window) { 10 # Expected output: 11 # html/baremetal.png 12 -13 fn main { +13 fn main { 14 var y/eax: int <- copy 0 15 { 16 compare y, 0x300 # 768 diff --git a/html/baremetal/ex3.mu.html b/html/baremetal/ex3.mu.html index c9d6fb1f..54cdea24 100644 --- a/html/baremetal/ex3.mu.html +++ b/html/baremetal/ex3.mu.html @@ -14,13 +14,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.muComment { color: #005faf; } +.PreProc { color: #c000c0; } .LineNr { } +.Constant { color: #008787; } .SpecialChar { color: #d70000; } .Delimiter { color: #c000c0; } .muFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.PreProc { color: #c000c0; } +.muComment { color: #005faf; } --> @@ -69,7 +69,7 @@ if ('onhashchange' in window) { 11 # Expected output: a new green pixel starting from the top left corner of the 12 # screen every time you press a key (letter or digit) 13 -14 fn main { +14 fn main { 15 var x/ecx: int <- copy 0 16 var y/edx: int <- copy 0 17 { diff --git a/html/baremetal/ex4.mu.html b/html/baremetal/ex4.mu.html index b9c5a36f..dc67e721 100644 --- a/html/baremetal/ex4.mu.html +++ b/html/baremetal/ex4.mu.html @@ -14,13 +14,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.muComment { color: #005faf; } +.PreProc { color: #c000c0; } .LineNr { } +.Constant { color: #008787; } .SpecialChar { color: #d70000; } .Delimiter { color: #c000c0; } .muFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.PreProc { color: #c000c0; } +.muComment { color: #005faf; } --> @@ -67,7 +67,7 @@ if ('onhashchange' in window) { 9 # 10 # Expected output: letter 'A' in green near the top-left corner of screen 11 -12 fn main { +12 fn main { 13 var g/eax: grapheme <- copy 0x41 # 'A' 14 draw-grapheme 0, g, 0x10, 0x10, 0xa 15 } diff --git a/html/baremetal/ex5.mu.html b/html/baremetal/ex5.mu.html index 95c2f03d..c4321e97 100644 --- a/html/baremetal/ex5.mu.html +++ b/html/baremetal/ex5.mu.html @@ -14,12 +14,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.muComment { color: #005faf; } +.PreProc { color: #c000c0; } .LineNr { } +.Constant { color: #008787; } +.SpecialChar { color: #d70000; } .Delimiter { color: #c000c0; } .muFunction { color: #af5f00; text-decoration: underline; } -.Constant { color: #008787; } -.PreProc { color: #c000c0; } +.muComment { color: #005faf; } --> @@ -55,20 +56,22 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/main/baremetal/ex5.mu
- 1 # Draw an ASCII string using the built-in font (GNU unifont)
- 2 #
- 3 # To build a disk image:
- 4 #   ./translate_mu_baremetal baremetal/ex5.mu     # emits disk.img
- 5 # To run:
- 6 #   qemu-system-i386 disk.img
- 7 # Or:
- 8 #   bochs -f baremetal/boot.bochsrc               # boot.bochsrc loads disk.img
- 9 #
-10 # Expected output: text in green near the top-left corner of screen
-11 
-12 fn main {
-13   draw-text-rightward 0, "hello from baremetal Mu!", 0x10, 0x10, 0xa
-14 }
+ 1 # Draw a single line of ASCII text using the built-in font (GNU unifont)
+ 2 # Also demonstrates bounds-checking _before_ drawing.
+ 3 #
+ 4 # To build a disk image:
+ 5 #   ./translate_mu_baremetal baremetal/ex5.mu     # emits disk.img
+ 6 # To run:
+ 7 #   qemu-system-i386 disk.img
+ 8 # Or:
+ 9 #   bochs -f baremetal/boot.bochsrc               # boot.bochsrc loads disk.img
+10 #
+11 # Expected output: text in green near the top-left corner of screen
+12 
+13 fn main {
+14   var dummy/eax: int <- draw-text-rightward 0, "hello from baremetal Mu!", 0x10, 0x400, 0x10, 0xa  # xmax = end of screen, plenty of space
+15   dummy <- draw-text-rightward 0, "you shouldn't see this", 0x10, 0xa0, 0x30, 0x3  # xmax = 0xa0, which is too narrow
+16 }
 
diff --git a/html/baremetal/ex6.mu.html b/html/baremetal/ex6.mu.html new file mode 100644 index 00000000..810b729b --- /dev/null +++ b/html/baremetal/ex6.mu.html @@ -0,0 +1,94 @@ + + + + +Mu - baremetal/ex6.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/baremetal/ex6.mu +
+ 1 # Drawing ASCII text incrementally.
+ 2 #
+ 3 # To build a disk image:
+ 4 #   ./translate_mu_baremetal baremetal/ex6.mu     # emits disk.img
+ 5 # To run:
+ 6 #   qemu-system-i386 disk.img
+ 7 # Or:
+ 8 #   bochs -f baremetal/boot.bochsrc               # boot.bochsrc loads disk.img
+ 9 #
+10 # Expected output: a box and text that doesn't overflow it
+11 
+12 fn main {
+13   # drawing text within a bounding box
+14   draw-box 0, 0xf, 0x1f, 0x79, 0x51, 0x4
+15   var x/eax: int <- copy 0x20
+16   var y/ecx: int <- copy 0x20
+17   x, y <- draw-text-wrapping-right-then-down 0, "hello ",     0x10, 0x20, 0x78, 0x50, x, y, 0xa  # (0x10, 0x20) -> (0x78, 0x50)
+18   x, y <- draw-text-wrapping-right-then-down 0, "from ",      0x10, 0x20, 0x78, 0x50, x, y, 0xa
+19   x, y <- draw-text-wrapping-right-then-down 0, "baremetal ", 0x10, 0x20, 0x78, 0x50, x, y, 0xa
+20   x, y <- draw-text-wrapping-right-then-down 0, "Mu!",        0x10, 0x20, 0x78, 0x50, x, y, 0xa
+21 
+22   # drawing at the cursor in multiple directions
+23   x, y <- draw-text-wrapping-down-then-right-from-cursor-over-full-screen 0, "abc", 0xa
+24   x, y <- draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, "def", 0xa
+25 
+26   # test drawing near the edge
+27   x <- draw-text-rightward 0, "R", 0x3f8, 0x400, 0x100, 0xa
+28   x, y <- draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, "wrapped from R", 0xa
+29 
+30   x <- draw-text-downward 0, "D", 0x100, 0x2f0, 0x300, 0xa
+31   x, y <- draw-text-wrapping-down-then-right-from-cursor-over-full-screen 0, "wrapped from D", 0xa
+32 }
+
+ + +